diff options
author | David Daney <daney@gcc.gnu.org> | 2004-08-12 16:20:11 +0000 |
---|---|---|
committer | David Daney <daney@gcc.gnu.org> | 2004-08-12 16:20:11 +0000 |
commit | c58f29001dee1b4f6dfb09cc2a49f2739b106553 (patch) | |
tree | d4c32b005acd50085c465f85fda29e5885955ec5 /libjava/java/lang/natPosixProcess.cc | |
parent | db151e9d837b9a27d2de105869186e2f9b7ca353 (diff) | |
download | gcc-c58f29001dee1b4f6dfb09cc2a49f2739b106553.zip gcc-c58f29001dee1b4f6dfb09cc2a49f2739b106553.tar.gz gcc-c58f29001dee1b4f6dfb09cc2a49f2739b106553.tar.bz2 |
re PR libgcj/11801 (Problems with Process.waitFor() and exitValue())
2004-08-12 David Daney <ddaney@avtrex.com>
PR libgcj/11801
* java/lang/PosixProcess.java: Rewrote.
* java/lang/natPosixProcess.cc: Rewrote.
* java/lang/Runtime.java (execInternal): Declare throws IOException.
* gcj/javaprims.h (ConcreteProcess$ProcessManager): Declare.
* posix-threads.cc (block_sigchld) New function.
(_Jv_ThreadRegister) Use it.
(_Jv_ThreadStart) Use it.
* configure.in (PLATFORM_INNER_NAT_HDRS): New AC_SUBST() used in...
* Makefile.am: ... to specify extra native headers.
* configure: Regenerated.
* include/config.h: Regenerated.
* Makefile.in: Regenerated.
* gcj/Makefile.in: Regenerated.
* include/Makefile.in: Regenerated.
* testsuite/Makefile.in: Regenerated.
From-SVN: r85880
Diffstat (limited to 'libjava/java/lang/natPosixProcess.cc')
-rw-r--r-- | libjava/java/lang/natPosixProcess.cc | 220 |
1 files changed, 156 insertions, 64 deletions
diff --git a/libjava/java/lang/natPosixProcess.cc b/libjava/java/lang/natPosixProcess.cc index fb97020..f6b6f67 100644 --- a/libjava/java/lang/natPosixProcess.cc +++ b/libjava/java/lang/natPosixProcess.cc @@ -21,12 +21,16 @@ details. */ #include <string.h> #include <stdlib.h> #include <stdio.h> +#include <unistd.h> +#include <pthread.h> #include <gcj/cni.h> #include <jvm.h> +#include <java/lang/ConcreteProcess$ProcessManager.h> #include <java/lang/ConcreteProcess.h> #include <java/lang/IllegalThreadStateException.h> +#include <java/lang/InternalError.h> #include <java/lang/InterruptedException.h> #include <java/lang/NullPointerException.h> #include <java/lang/Thread.h> @@ -42,44 +46,6 @@ using gnu::java::nio::channels::FileChannelImpl; extern char **environ; -void -java::lang::ConcreteProcess::destroy (void) -{ - if (! hasExited) - { - // Really kill it. - kill ((pid_t) pid, SIGKILL); - } -} - -jint -java::lang::ConcreteProcess::waitFor (void) -{ - if (! hasExited) - { - int wstat; - int r = waitpid ((pid_t) pid, &wstat, 0); - - if (r == -1) - { - if (java::lang::Thread::interrupted()) - throw new InterruptedException (JvNewStringLatin1 (strerror - (errno))); - } - else - { - hasExited = true; - - if (WIFEXITED (wstat)) - status = WEXITSTATUS (wstat); - else - status = -1; - } - } - - return status; -} - static char * new_string (jstring string) { @@ -120,14 +86,134 @@ myclose (int &fd) fd = -1; } +// There has to be a signal handler in order to be able to +// sigwait() on SIGCHLD. The information passed is ignored as it +// will be recovered by the waitpid() call. +static void +sigchld_handler (int) +{ + // Ignore. +} + + +// Get ready to enter the main reaper thread loop. void -java::lang::ConcreteProcess::startProcess (jstringArray progarray, - jstringArray envp, - java::io::File *dir) +java::lang::ConcreteProcess$ProcessManager::init () { - using namespace java::io; + using namespace java::lang; + // Remenber our PID so other threads can kill us. + reaperPID = (jlong) pthread_self (); + + // SIGCHLD is blocked in all threads in posix-threads.cc. + // Setup the SIGCHLD handler. + struct sigaction sa; + memset (&sa, 0, sizeof (sa)); + + sa.sa_handler = sigchld_handler; + // We only want signals when the things exit. + sa.sa_flags = SA_NOCLDSTOP; + + if (-1 == sigaction (SIGCHLD, &sa, NULL)) + goto error; + + // All OK. + return; + +error: + throw new InternalError (JvNewStringUTF (strerror (errno))); +} + +void +java::lang::ConcreteProcess$ProcessManager::waitForSignal () +{ + using namespace java::lang; + + sigset_t mask; + // Wait for SIGCHLD + sigemptyset (&mask); + sigaddset (&mask, SIGCHLD); + + int sig; + int c = sigwait (&mask, &sig); + + if (c != 0) + goto error; - hasExited = false; + // All OK. + return; + +error: + throw new InternalError (JvNewStringUTF (strerror (c))); +} + +jboolean java::lang::ConcreteProcess$ProcessManager::reap () +{ + using namespace java::lang; + + pid_t pid; + + for (;;) + { + // Get the return code from a dead child process. + int status; + pid = waitpid ((pid_t) - 1, &status, WNOHANG); + if (pid == -1) + { + if (errno == ECHILD) + return false; + else + goto error; + } + + if (pid == 0) + return true; // No children to wait for. + + // Look up the process in our pid map. + ConcreteProcess * process = removeProcessFromMap ((jlong) pid); + + if (process) + { + JvSynchronize sync (process); + process->status = WIFEXITED (status) ? WEXITSTATUS (status) : -1; + process->state = ConcreteProcess::STATE_TERMINATED; + process->processTerminationCleanup(); + process->notifyAll (); + } + else + { + // Unknown child. How did this happen? + fprintf (stderr, "Reaped unknown child pid = %ld\n", (long) pid); + } + } + +error: + throw new InternalError (JvNewStringUTF (strerror (errno))); +} + +void +java::lang::ConcreteProcess$ProcessManager::signalReaper () +{ + int c = pthread_kill ((pthread_t) reaperPID, SIGCHLD); + if (c == 0) + return; + // pthread_kill() failed. + throw new InternalError (JvNewStringUTF (strerror (c))); +} + +void +java::lang::ConcreteProcess::nativeDestroy () +{ + int c = kill ((pid_t) pid, SIGKILL); + if (c == 0) + return; + // kill() failed. + throw new InternalError (JvNewStringUTF (strerror (errno))); +} + +void +java::lang::ConcreteProcess::nativeSpawn () +{ + using namespace java::io; // Initialize all locals here to make cleanup simpler. char **args = NULL; @@ -142,7 +228,6 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, errp[1] = -1; msgp[0] = -1; msgp[1] = -1; - java::lang::Throwable *exc = NULL; errorStream = NULL; inputStream = NULL; outputStream = NULL; @@ -150,8 +235,7 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, try { // Transform arrays to native form. - args = (char **) _Jv_Malloc ((progarray->length + 1) - * sizeof (char *)); + args = (char **) _Jv_Malloc ((progarray->length + 1) * sizeof (char *)); // Initialize so we can gracefully recover. jstring *elts = elements (progarray); @@ -185,24 +269,32 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, // status. if (pipe (inp) || pipe (outp) || pipe (errp) || pipe (msgp) || fcntl (msgp[1], F_SETFD, FD_CLOEXEC)) - throw new IOException (JvNewStringLatin1 (strerror (errno))); + throw new IOException (JvNewStringUTF (strerror (errno))); // We create the streams before forking. Otherwise if we had an // error while creating the streams we would have run the child // with no way to communicate with it. - errorStream = new FileInputStream (new FileChannelImpl(errp[0], FileChannelImpl::READ)); - inputStream = new FileInputStream (new FileChannelImpl(inp[0], FileChannelImpl::READ)); - outputStream = new FileOutputStream (new FileChannelImpl(outp[1], FileChannelImpl::WRITE)); + errorStream = + new FileInputStream (new + FileChannelImpl (errp[0], FileChannelImpl::READ)); + inputStream = + new FileInputStream (new + FileChannelImpl (inp[0], FileChannelImpl::READ)); + outputStream = + new FileOutputStream (new FileChannelImpl (outp[1], + FileChannelImpl::WRITE)); // We don't use vfork() because that would cause the local // environment to be set by the child. - if ((pid = (jlong) fork ()) == -1) - throw new IOException (JvNewStringLatin1 (strerror (errno))); - if (pid == 0) + // Use temporary for fork result to avoid dirtying an extra page. + pid_t pid_tmp; + if ((pid_tmp = fork ()) == -1) + throw new IOException (JvNewStringUTF (strerror (errno))); + + if (pid_tmp == 0) { // Child process, so remap descriptors, chdir and exec. - if (envp) { // Preserve PATH and LD_LIBRARY_PATH unless specified @@ -212,16 +304,16 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, environ = env; if (path_val && getenv ("PATH") == NULL) { - char *path_env = (char *) _Jv_Malloc (strlen (path_val) - + 5 + 1); + char *path_env = + (char *) _Jv_Malloc (strlen (path_val) + 5 + 1); strcpy (path_env, "PATH="); strcat (path_env, path_val); putenv (path_env); } if (ld_path_val && getenv ("LD_LIBRARY_PATH") == NULL) { - char *ld_path_env - = (char *) _Jv_Malloc (strlen (ld_path_val) + 16 + 1); + char *ld_path_env = + (char *) _Jv_Malloc (strlen (ld_path_val) + 16 + 1); strcpy (ld_path_env, "LD_LIBRARY_PATH="); strcat (ld_path_env, ld_path_val); putenv (ld_path_env); @@ -264,6 +356,8 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, // Parent. Close extra file descriptors and mark ours as // close-on-exec. + pid = (jlong) pid_tmp; + myclose (outp[0]); myclose (inp[1]); myclose (errp[1]); @@ -272,9 +366,9 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, char c; int r = read (msgp[0], &c, 1); if (r == -1) - throw new IOException (JvNewStringLatin1 (strerror (errno))); + throw new IOException (JvNewStringUTF (strerror (errno))); else if (r != 0) - throw new IOException (JvNewStringLatin1 (strerror (c))); + throw new IOException (JvNewStringUTF (strerror (c))); } catch (java::lang::Throwable *thrown) { @@ -324,15 +418,13 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, myclose (errp[1]); myclose (msgp[1]); - exc = thrown; + exception = thrown; } myclose (msgp[0]); cleanup (args, env, path); - if (exc != NULL) - throw exc; - else + if (exception == NULL) { fcntl (outp[1], F_SETFD, FD_CLOEXEC); fcntl (inp[0], F_SETFD, FD_CLOEXEC); |