Commit c58f2900 by David Daney

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
parent db151e9d
......@@ -532,7 +532,8 @@ inner_nat_headers = java/io/ObjectOutputStream$$PutField.h \
gnu/java/net/PlainSocketImpl$$SocketInputStream.h \
gnu/java/net/PlainSocketImpl$$SocketOutputStream.h \
gnu/java/nio/PipeImpl$$SinkChannelImpl.h \
gnu/java/nio/PipeImpl$$SourceChannelImpl.h
gnu/java/nio/PipeImpl$$SourceChannelImpl.h \
$(PLATFORM_INNER_NAT_HDRS)
nat_headers = $(ordinary_nat_headers) $(inner_nat_headers)
nat_headers_install = $(ordinary_nat_headers)
......@@ -642,6 +643,11 @@ gnu/java/nio/PipeImpl$$SourceChannelImpl.h: gnu/java/nio/PipeImpl.class
$(GCJH) -classpath '' -bootclasspath $(top_builddir) \
'gnu/java/nio/PipeImpl$$SourceChannelImpl'
## Only used by PosixProcess.java
java/lang/ConcreteProcess$$ProcessManager.h: java/lang/ConcreteProcess.class
$(GCJH) -classpath '' -bootclasspath $(top_builddir) \
'java/lang/ConcreteProcess$$ProcessManager'
## Headers we maintain by hand and which we want to install.
extra_headers = java/lang/Object.h java/lang/Class.h
......
......@@ -125,6 +125,7 @@ PANGOFT2_LIBS = @PANGOFT2_LIBS@
PERL = @PERL@
PKG_CONFIG = @PKG_CONFIG@
PLATFORMOBJS = @PLATFORMOBJS@
PLATFORM_INNER_NAT_HDRS = @PLATFORM_INNER_NAT_HDRS@
RANLIB = @RANLIB@
STRIP = @STRIP@
SYSDEP_SOURCES = @SYSDEP_SOURCES@
......@@ -506,7 +507,8 @@ inner_nat_headers = java/io/ObjectOutputStream$$PutField.h \
gnu/java/net/PlainSocketImpl$$SocketInputStream.h \
gnu/java/net/PlainSocketImpl$$SocketOutputStream.h \
gnu/java/nio/PipeImpl$$SinkChannelImpl.h \
gnu/java/nio/PipeImpl$$SourceChannelImpl.h
gnu/java/nio/PipeImpl$$SourceChannelImpl.h \
$(PLATFORM_INNER_NAT_HDRS)
nat_headers = $(ordinary_nat_headers) $(inner_nat_headers)
......@@ -5662,6 +5664,10 @@ gnu/java/nio/PipeImpl$$SourceChannelImpl.h: gnu/java/nio/PipeImpl.class
$(GCJH) -classpath '' -bootclasspath $(top_builddir) \
'gnu/java/nio/PipeImpl$$SourceChannelImpl'
java/lang/ConcreteProcess$$ProcessManager.h: java/lang/ConcreteProcess.class
$(GCJH) -classpath '' -bootclasspath $(top_builddir) \
'java/lang/ConcreteProcess$$ProcessManager'
$(extra_headers) $(srcdir)/java/lang/Object.h $(srcdir)/java/lang/Class.h:
@:
......
......@@ -386,6 +386,7 @@ EXTRA_CC_FILES=
AC_SUBST(EXTRA_CC_FILES)
PLATFORMOBJS=
PLATFORM_INNER_NAT_HDRS=
case "$TARGET_ECOS" in
no) case "$host" in
*mingw*)
......@@ -400,6 +401,7 @@ case "$TARGET_ECOS" in
PLATFORMNET=Posix
PLATFORMOBJS=posix.lo
PLATFORMH=posix.h
PLATFORM_INNER_NAT_HDRS='java/lang/ConcreteProcess$$ProcessManager.h'
;;
esac
;;
......@@ -412,6 +414,7 @@ case "$TARGET_ECOS" in
;;
esac
AC_SUBST(PLATFORMOBJS)
AC_SUBST(PLATFORM_INNER_NAT_HDRS)
AC_CONFIG_LINKS(include/platform.h:include/$PLATFORMH)
AC_EGREP_HEADER(uint32_t, stdint.h, AC_DEFINE(HAVE_INT32_DEFINED, 1,
......
......@@ -128,6 +128,7 @@ PANGOFT2_LIBS = @PANGOFT2_LIBS@
PERL = @PERL@
PKG_CONFIG = @PKG_CONFIG@
PLATFORMOBJS = @PLATFORMOBJS@
PLATFORM_INNER_NAT_HDRS = @PLATFORM_INNER_NAT_HDRS@
RANLIB = @RANLIB@
STRIP = @STRIP@
SYSDEP_SOURCES = @SYSDEP_SOURCES@
......
// javaprims.h - Main external header file for libgcj. -*- c++ -*-
/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation
/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation
This file is part of libgcj.
......@@ -150,6 +151,7 @@ extern "Java"
class Comparable;
class Compiler;
class ConcreteProcess;
class ConcreteProcess$ProcessManager;
class Double;
class Error;
class Exception;
......
......@@ -128,6 +128,7 @@ PANGOFT2_LIBS = @PANGOFT2_LIBS@
PERL = @PERL@
PKG_CONFIG = @PKG_CONFIG@
PLATFORMOBJS = @PLATFORMOBJS@
PLATFORM_INNER_NAT_HDRS = @PLATFORM_INNER_NAT_HDRS@
RANLIB = @RANLIB@
STRIP = @STRIP@
SYSDEP_SOURCES = @SYSDEP_SOURCES@
......
/* Runtime.java -- access to the VM process
Copyright (C) 1998, 2002, 2003 Free Software Foundation
Copyright (C) 1998, 2002, 2003, 2004 Free Software Foundation
This file is part of GNU Classpath.
......@@ -734,8 +734,11 @@ public class Runtime
* @param dir the directory to use, may be null
* @return the newly created process
* @throws NullPointerException if cmd or env have null elements
* @throws IOException if the exec fails
*/
native Process execInternal(String[] cmd, String[] env, File dir);
native Process execInternal(String[] cmd, String[] env, File dir)
throws IOException;
/**
* Get the system properties. This is done here, instead of in System,
......
......@@ -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);
......
// posix-threads.cc - interface between libjava and POSIX threads.
/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation
/* Copyright (C) 1998, 1999, 2000, 2001, 2004 Free Software Foundation
This file is part of libgcj.
......@@ -34,6 +34,7 @@ details. */
#include <java/lang/System.h>
#include <java/lang/Long.h>
#include <java/lang/OutOfMemoryError.h>
#include <java/lang/InternalError.h>
// This is used to implement thread startup.
struct starter
......@@ -332,6 +333,17 @@ _Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio)
#endif
}
static void
block_sigchld()
{
sigset_t mask;
sigemptyset (&mask);
sigaddset (&mask, SIGCHLD);
int c = pthread_sigmask (SIG_BLOCK, &mask, NULL);
if (c != 0)
throw new java::lang::InternalError (JvNewStringUTF (strerror (c)));
}
void
_Jv_ThreadRegister (_Jv_Thread_t *data)
{
......@@ -358,6 +370,8 @@ _Jv_ThreadRegister (_Jv_Thread_t *data)
_Jv_self_cache[current_index].high_sp_bits = BAD_HIGH_SP_VALUE;
}
# endif
// Block SIGCHLD which is used in natPosixProcess.cc.
block_sigchld();
}
void
......@@ -403,6 +417,10 @@ _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data,
return;
data->flags |= FLAG_START;
// Block SIGCHLD which is used in natPosixProcess.cc.
// The current mask is inherited by the child thread.
block_sigchld();
param.sched_priority = thread->getPriority();
pthread_attr_init (&attr);
......
......@@ -128,6 +128,7 @@ PANGOFT2_LIBS = @PANGOFT2_LIBS@
PERL = @PERL@
PKG_CONFIG = @PKG_CONFIG@
PLATFORMOBJS = @PLATFORMOBJS@
PLATFORM_INNER_NAT_HDRS = @PLATFORM_INNER_NAT_HDRS@
RANLIB = @RANLIB@
STRIP = @STRIP@
SYSDEP_SOURCES = @SYSDEP_SOURCES@
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment