aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/lang/natPosixProcess.cc
diff options
context:
space:
mode:
authorDavid Daney <daney@gcc.gnu.org>2004-08-12 16:20:11 +0000
committerDavid Daney <daney@gcc.gnu.org>2004-08-12 16:20:11 +0000
commitc58f29001dee1b4f6dfb09cc2a49f2739b106553 (patch)
treed4c32b005acd50085c465f85fda29e5885955ec5 /libjava/java/lang/natPosixProcess.cc
parentdb151e9d837b9a27d2de105869186e2f9b7ca353 (diff)
downloadgcc-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.cc220
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);