svn merge -r108665:108708 svn+ssh://gcc.gnu.org/svn/gcc/trunk
[official-gcc.git] / libjava / java / lang / natPosixProcess.cc
blob9a6c3218d4d1e6bb5c18c4fcce77b39b477d54d0
1 // natPosixProcess.cc - Native side of POSIX process code.
3 /* Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005 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 // Wait for SIGCHLD
130 sigset_t mask;
131 pthread_sigmask (0, NULL, &mask);
132 sigdelset (&mask, SIGCHLD);
134 // Use sigsuspend() instead of sigwait() as sigwait() doesn't play
135 // nicely with the GC's use of signals.
136 sigsuspend (&mask);
138 // Do not check sigsuspend return value. The only legitimate return
139 // is EINTR, but there is a known kernel bug affecting alpha-linux
140 // wrt sigsuspend+handler+sigreturn that can result in a return value
141 // of __NR_sigsuspend and errno unset. Don't fail unnecessarily on
142 // older kernel versions.
144 // All OK.
145 return;
148 jboolean java::lang::ConcreteProcess$ProcessManager::reap ()
150 using namespace java::lang;
152 pid_t pid;
154 for (;;)
156 // Get the return code from a dead child process.
157 int status;
158 pid = waitpid ((pid_t) - 1, &status, WNOHANG);
159 if (pid == -1)
161 if (errno == ECHILD)
162 return false;
163 else
164 goto error;
167 if (pid == 0)
168 return true; // No children to wait for.
170 // Look up the process in our pid map.
171 ConcreteProcess * process = removeProcessFromMap ((jlong) pid);
173 if (process)
175 JvSynchronize sync (process);
176 process->status = WIFEXITED (status) ? WEXITSTATUS (status) : -1;
177 process->state = ConcreteProcess::STATE_TERMINATED;
178 process->processTerminationCleanup();
179 process->notifyAll ();
181 else
183 // Unknown child. How did this happen?
184 fprintf (stderr, "Reaped unknown child pid = %ld\n", (long) pid);
188 error:
189 throw new InternalError (JvNewStringUTF (strerror (errno)));
192 void
193 java::lang::ConcreteProcess$ProcessManager::signalReaper ()
195 int c = pthread_kill ((pthread_t) reaperPID, SIGCHLD);
196 if (c == 0)
197 return;
198 // pthread_kill() failed.
199 throw new InternalError (JvNewStringUTF (strerror (c)));
202 void
203 java::lang::ConcreteProcess::nativeDestroy ()
205 int c = kill ((pid_t) pid, SIGKILL);
206 if (c == 0)
207 return;
208 // kill() failed.
209 throw new InternalError (JvNewStringUTF (strerror (errno)));
212 void
213 java::lang::ConcreteProcess::nativeSpawn ()
215 using namespace java::io;
217 // Initialize all locals here to make cleanup simpler.
218 char **args = NULL;
219 char **env = NULL;
220 char *path = NULL;
221 int inp[2], outp[2], errp[2], msgp[2];
222 inp[0] = -1;
223 inp[1] = -1;
224 outp[0] = -1;
225 outp[1] = -1;
226 errp[0] = -1;
227 errp[1] = -1;
228 msgp[0] = -1;
229 msgp[1] = -1;
230 errorStream = NULL;
231 inputStream = NULL;
232 outputStream = NULL;
236 // Transform arrays to native form.
237 args = (char **) _Jv_Malloc ((progarray->length + 1) * sizeof (char *));
239 // Initialize so we can gracefully recover.
240 jstring *elts = elements (progarray);
241 for (int i = 0; i <= progarray->length; ++i)
242 args[i] = NULL;
244 for (int i = 0; i < progarray->length; ++i)
245 args[i] = new_string (elts[i]);
246 args[progarray->length] = NULL;
248 if (envp)
250 env = (char **) _Jv_Malloc ((envp->length + 1) * sizeof (char *));
251 elts = elements (envp);
253 // Initialize so we can gracefully recover.
254 for (int i = 0; i <= envp->length; ++i)
255 env[i] = NULL;
257 for (int i = 0; i < envp->length; ++i)
258 env[i] = new_string (elts[i]);
259 env[envp->length] = NULL;
262 // We allocate this here because we can't call malloc() after
263 // the fork.
264 if (dir != NULL)
265 path = new_string (dir->getPath ());
267 // Create pipes for I/O. MSGP is for communicating exec()
268 // status.
269 if (pipe (inp) || pipe (outp) || pipe (errp) || pipe (msgp)
270 || fcntl (msgp[1], F_SETFD, FD_CLOEXEC))
271 throw new IOException (JvNewStringUTF (strerror (errno)));
273 // We create the streams before forking. Otherwise if we had an
274 // error while creating the streams we would have run the child
275 // with no way to communicate with it.
276 errorStream =
277 new FileInputStream (new
278 FileChannelImpl (errp[0], FileChannelImpl::READ));
279 inputStream =
280 new FileInputStream (new
281 FileChannelImpl (inp[0], FileChannelImpl::READ));
282 outputStream =
283 new FileOutputStream (new FileChannelImpl (outp[1],
284 FileChannelImpl::WRITE));
286 // We don't use vfork() because that would cause the local
287 // environment to be set by the child.
289 // Use temporary for fork result to avoid dirtying an extra page.
290 pid_t pid_tmp;
291 if ((pid_tmp = fork ()) == -1)
292 throw new IOException (JvNewStringUTF (strerror (errno)));
294 if (pid_tmp == 0)
296 // Child process, so remap descriptors, chdir and exec.
297 if (envp)
299 // Preserve PATH and LD_LIBRARY_PATH unless specified
300 // explicitly.
301 char *path_val = getenv ("PATH");
302 char *ld_path_val = getenv ("LD_LIBRARY_PATH");
303 environ = env;
304 if (path_val && getenv ("PATH") == NULL)
306 char *path_env =
307 (char *) _Jv_Malloc (strlen (path_val) + 5 + 1);
308 strcpy (path_env, "PATH=");
309 strcat (path_env, path_val);
310 putenv (path_env);
312 if (ld_path_val && getenv ("LD_LIBRARY_PATH") == NULL)
314 char *ld_path_env =
315 (char *) _Jv_Malloc (strlen (ld_path_val) + 16 + 1);
316 strcpy (ld_path_env, "LD_LIBRARY_PATH=");
317 strcat (ld_path_env, ld_path_val);
318 putenv (ld_path_env);
322 // We ignore errors from dup2 because they should never occur.
323 dup2 (outp[0], 0);
324 dup2 (inp[1], 1);
325 dup2 (errp[1], 2);
327 // Use close and not myclose -- we're in the child, and we
328 // aren't worried about the possible race condition.
329 close (inp[0]);
330 close (inp[1]);
331 close (errp[0]);
332 close (errp[1]);
333 close (outp[0]);
334 close (outp[1]);
335 close (msgp[0]);
337 // Change directory.
338 if (path != NULL)
340 if (chdir (path) != 0)
342 char c = errno;
343 write (msgp[1], &c, 1);
344 _exit (127);
348 // Make sure that SIGCHLD is unblocked for the new process.
349 sigset_t mask;
350 sigemptyset (&mask);
351 sigaddset (&mask, SIGCHLD);
352 sigprocmask (SIG_UNBLOCK, &mask, NULL);
354 execvp (args[0], args);
356 // Send the parent notification that the exec failed.
357 char c = errno;
358 write (msgp[1], &c, 1);
359 _exit (127);
362 // Parent. Close extra file descriptors and mark ours as
363 // close-on-exec.
364 pid = (jlong) pid_tmp;
366 myclose (outp[0]);
367 myclose (inp[1]);
368 myclose (errp[1]);
369 myclose (msgp[1]);
371 char c;
372 int r = read (msgp[0], &c, 1);
373 if (r == -1)
374 throw new IOException (JvNewStringUTF (strerror (errno)));
375 else if (r != 0)
376 throw new IOException (JvNewStringUTF (strerror (c)));
378 catch (java::lang::Throwable *thrown)
380 // Do some cleanup we only do on failure. If a stream object
381 // has been created, we must close the stream itself (to avoid
382 // duplicate closes when the stream object is collected).
383 // Otherwise we simply close the underlying file descriptor.
384 // We ignore errors here as they are uninteresting.
388 if (inputStream != NULL)
389 inputStream->close ();
390 else
391 myclose (inp[0]);
393 catch (java::lang::Throwable *ignore)
399 if (outputStream != NULL)
400 outputStream->close ();
401 else
402 myclose (outp[1]);
404 catch (java::lang::Throwable *ignore)
410 if (errorStream != NULL)
411 errorStream->close ();
412 else
413 myclose (errp[0]);
415 catch (java::lang::Throwable *ignore)
419 // These are potentially duplicate, but it doesn't matter due to
420 // the use of myclose.
421 myclose (outp[0]);
422 myclose (inp[1]);
423 myclose (errp[1]);
424 myclose (msgp[1]);
426 exception = thrown;
429 myclose (msgp[0]);
430 cleanup (args, env, path);
432 if (exception == NULL)
434 fcntl (outp[1], F_SETFD, FD_CLOEXEC);
435 fcntl (inp[0], F_SETFD, FD_CLOEXEC);
436 fcntl (errp[0], F_SETFD, FD_CLOEXEC);