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
This commit is contained in:
David Daney
2004-08-12 16:20:11 +00:00
parent db151e9d83
commit c58f29001d
13 changed files with 1218 additions and 628 deletions
+156 -64
View File
@@ -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,15 +86,135 @@ 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::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;
// 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;
hasExited = false;
// Initialize all locals here to make cleanup simpler.
char **args = NULL;
char **env = 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);