2004-08-12 David Daney <ddaney@avtrex.com>
[official-gcc.git] / libjava / java / lang / natPosixProcess.cc
blobf6b6f67baf57854e97ad55043ae1484e3371f8e5
1 // natPosixProcess.cc - Native side of POSIX process code.
3 /* Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
11 #include <config.h>
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <signal.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <pthread.h>
27 #include <gcj/cni.h>
28 #include <jvm.h>
30 #include <java/lang/ConcreteProcess$ProcessManager.h>
31 #include <java/lang/ConcreteProcess.h>
32 #include <java/lang/IllegalThreadStateException.h>
33 #include <java/lang/InternalError.h>
34 #include <java/lang/InterruptedException.h>
35 #include <java/lang/NullPointerException.h>
36 #include <java/lang/Thread.h>
37 #include <java/io/File.h>
38 #include <java/io/FileDescriptor.h>
39 #include <gnu/java/nio/channels/FileChannelImpl.h>
40 #include <java/io/FileInputStream.h>
41 #include <java/io/FileOutputStream.h>
42 #include <java/io/IOException.h>
43 #include <java/lang/OutOfMemoryError.h>
45 using gnu::java::nio::channels::FileChannelImpl;
47 extern char **environ;
49 static char *
50 new_string (jstring string)
52 jsize s = _Jv_GetStringUTFLength (string);
53 char *buf = (char *) _Jv_Malloc (s + 1);
54 _Jv_GetStringUTFRegion (string, 0, string->length(), buf);
55 buf[s] = '\0';
56 return buf;
59 static void
60 cleanup (char **args, char **env, char *path)
62 if (args != NULL)
64 for (int i = 0; args[i] != NULL; ++i)
65 _Jv_Free (args[i]);
66 _Jv_Free (args);
68 if (env != NULL)
70 for (int i = 0; env[i] != NULL; ++i)
71 _Jv_Free (env[i]);
72 _Jv_Free (env);
74 if (path != NULL)
75 _Jv_Free (path);
78 // This makes our error handling a bit simpler and it lets us avoid
79 // thread bugs where we close a possibly-reopened file descriptor for
80 // a second time.
81 static void
82 myclose (int &fd)
84 if (fd != -1)
85 close (fd);
86 fd = -1;
89 // There has to be a signal handler in order to be able to
90 // sigwait() on SIGCHLD. The information passed is ignored as it
91 // will be recovered by the waitpid() call.
92 static void
93 sigchld_handler (int)
95 // Ignore.
99 // Get ready to enter the main reaper thread loop.
100 void
101 java::lang::ConcreteProcess$ProcessManager::init ()
103 using namespace java::lang;
104 // Remenber our PID so other threads can kill us.
105 reaperPID = (jlong) pthread_self ();
107 // SIGCHLD is blocked in all threads in posix-threads.cc.
108 // Setup the SIGCHLD handler.
109 struct sigaction sa;
110 memset (&sa, 0, sizeof (sa));
112 sa.sa_handler = sigchld_handler;
113 // We only want signals when the things exit.
114 sa.sa_flags = SA_NOCLDSTOP;
116 if (-1 == sigaction (SIGCHLD, &sa, NULL))
117 goto error;
119 // All OK.
120 return;
122 error:
123 throw new InternalError (JvNewStringUTF (strerror (errno)));
126 void
127 java::lang::ConcreteProcess$ProcessManager::waitForSignal ()
129 using namespace java::lang;
131 sigset_t mask;
132 // Wait for SIGCHLD
133 sigemptyset (&mask);
134 sigaddset (&mask, SIGCHLD);
136 int sig;
137 int c = sigwait (&mask, &sig);
139 if (c != 0)
140 goto error;
142 // All OK.
143 return;
145 error:
146 throw new InternalError (JvNewStringUTF (strerror (c)));
149 jboolean java::lang::ConcreteProcess$ProcessManager::reap ()
151 using namespace java::lang;
153 pid_t pid;
155 for (;;)
157 // Get the return code from a dead child process.
158 int status;
159 pid = waitpid ((pid_t) - 1, &status, WNOHANG);
160 if (pid == -1)
162 if (errno == ECHILD)
163 return false;
164 else
165 goto error;
168 if (pid == 0)
169 return true; // No children to wait for.
171 // Look up the process in our pid map.
172 ConcreteProcess * process = removeProcessFromMap ((jlong) pid);
174 if (process)
176 JvSynchronize sync (process);
177 process->status = WIFEXITED (status) ? WEXITSTATUS (status) : -1;
178 process->state = ConcreteProcess::STATE_TERMINATED;
179 process->processTerminationCleanup();
180 process->notifyAll ();
182 else
184 // Unknown child. How did this happen?
185 fprintf (stderr, "Reaped unknown child pid = %ld\n", (long) pid);
189 error:
190 throw new InternalError (JvNewStringUTF (strerror (errno)));
193 void
194 java::lang::ConcreteProcess$ProcessManager::signalReaper ()
196 int c = pthread_kill ((pthread_t) reaperPID, SIGCHLD);
197 if (c == 0)
198 return;
199 // pthread_kill() failed.
200 throw new InternalError (JvNewStringUTF (strerror (c)));
203 void
204 java::lang::ConcreteProcess::nativeDestroy ()
206 int c = kill ((pid_t) pid, SIGKILL);
207 if (c == 0)
208 return;
209 // kill() failed.
210 throw new InternalError (JvNewStringUTF (strerror (errno)));
213 void
214 java::lang::ConcreteProcess::nativeSpawn ()
216 using namespace java::io;
218 // Initialize all locals here to make cleanup simpler.
219 char **args = NULL;
220 char **env = NULL;
221 char *path = NULL;
222 int inp[2], outp[2], errp[2], msgp[2];
223 inp[0] = -1;
224 inp[1] = -1;
225 outp[0] = -1;
226 outp[1] = -1;
227 errp[0] = -1;
228 errp[1] = -1;
229 msgp[0] = -1;
230 msgp[1] = -1;
231 errorStream = NULL;
232 inputStream = NULL;
233 outputStream = NULL;
237 // Transform arrays to native form.
238 args = (char **) _Jv_Malloc ((progarray->length + 1) * sizeof (char *));
240 // Initialize so we can gracefully recover.
241 jstring *elts = elements (progarray);
242 for (int i = 0; i <= progarray->length; ++i)
243 args[i] = NULL;
245 for (int i = 0; i < progarray->length; ++i)
246 args[i] = new_string (elts[i]);
247 args[progarray->length] = NULL;
249 if (envp)
251 env = (char **) _Jv_Malloc ((envp->length + 1) * sizeof (char *));
252 elts = elements (envp);
254 // Initialize so we can gracefully recover.
255 for (int i = 0; i <= envp->length; ++i)
256 env[i] = NULL;
258 for (int i = 0; i < envp->length; ++i)
259 env[i] = new_string (elts[i]);
260 env[envp->length] = NULL;
263 // We allocate this here because we can't call malloc() after
264 // the fork.
265 if (dir != NULL)
266 path = new_string (dir->getPath ());
268 // Create pipes for I/O. MSGP is for communicating exec()
269 // status.
270 if (pipe (inp) || pipe (outp) || pipe (errp) || pipe (msgp)
271 || fcntl (msgp[1], F_SETFD, FD_CLOEXEC))
272 throw new IOException (JvNewStringUTF (strerror (errno)));
274 // We create the streams before forking. Otherwise if we had an
275 // error while creating the streams we would have run the child
276 // with no way to communicate with it.
277 errorStream =
278 new FileInputStream (new
279 FileChannelImpl (errp[0], FileChannelImpl::READ));
280 inputStream =
281 new FileInputStream (new
282 FileChannelImpl (inp[0], FileChannelImpl::READ));
283 outputStream =
284 new FileOutputStream (new FileChannelImpl (outp[1],
285 FileChannelImpl::WRITE));
287 // We don't use vfork() because that would cause the local
288 // environment to be set by the child.
290 // Use temporary for fork result to avoid dirtying an extra page.
291 pid_t pid_tmp;
292 if ((pid_tmp = fork ()) == -1)
293 throw new IOException (JvNewStringUTF (strerror (errno)));
295 if (pid_tmp == 0)
297 // Child process, so remap descriptors, chdir and exec.
298 if (envp)
300 // Preserve PATH and LD_LIBRARY_PATH unless specified
301 // explicitly.
302 char *path_val = getenv ("PATH");
303 char *ld_path_val = getenv ("LD_LIBRARY_PATH");
304 environ = env;
305 if (path_val && getenv ("PATH") == NULL)
307 char *path_env =
308 (char *) _Jv_Malloc (strlen (path_val) + 5 + 1);
309 strcpy (path_env, "PATH=");
310 strcat (path_env, path_val);
311 putenv (path_env);
313 if (ld_path_val && getenv ("LD_LIBRARY_PATH") == NULL)
315 char *ld_path_env =
316 (char *) _Jv_Malloc (strlen (ld_path_val) + 16 + 1);
317 strcpy (ld_path_env, "LD_LIBRARY_PATH=");
318 strcat (ld_path_env, ld_path_val);
319 putenv (ld_path_env);
323 // We ignore errors from dup2 because they should never occur.
324 dup2 (outp[0], 0);
325 dup2 (inp[1], 1);
326 dup2 (errp[1], 2);
328 // Use close and not myclose -- we're in the child, and we
329 // aren't worried about the possible race condition.
330 close (inp[0]);
331 close (inp[1]);
332 close (errp[0]);
333 close (errp[1]);
334 close (outp[0]);
335 close (outp[1]);
336 close (msgp[0]);
338 // Change directory.
339 if (path != NULL)
341 if (chdir (path) != 0)
343 char c = errno;
344 write (msgp[1], &c, 1);
345 _exit (127);
349 execvp (args[0], args);
351 // Send the parent notification that the exec failed.
352 char c = errno;
353 write (msgp[1], &c, 1);
354 _exit (127);
357 // Parent. Close extra file descriptors and mark ours as
358 // close-on-exec.
359 pid = (jlong) pid_tmp;
361 myclose (outp[0]);
362 myclose (inp[1]);
363 myclose (errp[1]);
364 myclose (msgp[1]);
366 char c;
367 int r = read (msgp[0], &c, 1);
368 if (r == -1)
369 throw new IOException (JvNewStringUTF (strerror (errno)));
370 else if (r != 0)
371 throw new IOException (JvNewStringUTF (strerror (c)));
373 catch (java::lang::Throwable *thrown)
375 // Do some cleanup we only do on failure. If a stream object
376 // has been created, we must close the stream itself (to avoid
377 // duplicate closes when the stream object is collected).
378 // Otherwise we simply close the underlying file descriptor.
379 // We ignore errors here as they are uninteresting.
383 if (inputStream != NULL)
384 inputStream->close ();
385 else
386 myclose (inp[0]);
388 catch (java::lang::Throwable *ignore)
394 if (outputStream != NULL)
395 outputStream->close ();
396 else
397 myclose (outp[1]);
399 catch (java::lang::Throwable *ignore)
405 if (errorStream != NULL)
406 errorStream->close ();
407 else
408 myclose (errp[0]);
410 catch (java::lang::Throwable *ignore)
414 // These are potentially duplicate, but it doesn't matter due to
415 // the use of myclose.
416 myclose (outp[0]);
417 myclose (inp[1]);
418 myclose (errp[1]);
419 myclose (msgp[1]);
421 exception = thrown;
424 myclose (msgp[0]);
425 cleanup (args, env, path);
427 if (exception == NULL)
429 fcntl (outp[1], F_SETFD, FD_CLOEXEC);
430 fcntl (inp[0], F_SETFD, FD_CLOEXEC);
431 fcntl (errp[0], F_SETFD, FD_CLOEXEC);