re PR libgcj/29324 (add wait handling hook)

PR libgcj/29324
	* include/posix-threads.h (_Jv_BlockSigchld): Declare.
	(_Jv_UnBlockSigchld): Same.
	* posix-threads.cc: Include posix-threads.h.
	(block_sigchld) Rename to...
	(_Jv_BlockSigchld) ... this.
	(_Jv_UnBlockSigchld): New function.
	(_Jv_InitThreads): Call _Jv_BlockSigchld in place of block_sigchld.
	(_Jv_ThreadStart): Same.
	* java/lang/PosixProcess$ProcessManager.h: Regenerate.
	* java/lang/PosixProcess.java: Clean up imports.
	(ProcessManager): Make final.
	(ProcessManager.queue): Genericise and make private.
	(ProcessManager.pidToProcess): Remove.
	(ProcessManager.liveProcesses): New field.
	(ProcessManager.reaperPID): Remove.
	(ProcessManager.nativeData): New field.
	(ProcessManager.removeProcessFromMap): Remove.
	(ProcessManager.addProcessToMap):Remove.
	(ProcessManager.addToLiveProcesses): New method.
	(ProcessManager.run): Rewritten.
	(ProcessManager.reap): Change method signature,
	(getErrorStream): Correct formatting.
	(getInputStream): Same.
	(spawn): Add process to liveProcesses list.
	(pid): Make package private.
	* java/lang/PosixProcess.h: Regenerate.
	* java/lang/natPosixProcess.cc: Include posix.h and posix-threads.h.
	Add useing namespace java::lang.
	(ProcessManagerInternal): New struct.
	(sigchld_handler): Rewritten.
	(init): Rewritten.
	(waitForSignal): Same.
	(reap): Same.
	(signalReaper): Same.
	(nativeDestroy): Call kill as ::kill.
	(nativeSpawn): Correct formatting.
	* classpath/lib/java/lang/PosixProcess$EOFInputStream.class: Regenerate.
	* classpath/lib/java/lang/PosixProcess.class: Same.
	* classpath/lib/java/lang/PosixProcess$ProcessManager.class: Same.

From-SVN: r124638
This commit is contained in:
David Daney
2007-05-12 17:37:55 +00:00
committed by David Daney
parent c4160806e1
commit 8c0dbf3490
10 changed files with 244 additions and 168 deletions
+82 -69
View File
@@ -30,6 +30,8 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
#include <posix.h>
#include <posix-threads.h>
#include <java/lang/PosixProcess$ProcessManager.h>
#include <java/lang/PosixProcess.h>
@@ -48,6 +50,7 @@ details. */
#include <java/lang/PosixProcess$EOFInputStream.h>
using gnu::java::nio::channels::FileChannelImpl;
using namespace java::lang;
extern char **environ;
@@ -91,13 +94,37 @@ myclose (int &fd)
fd = -1;
}
namespace
{
struct ProcessManagerInternal
{
int pipe_ends[2];
struct sigaction old_sigaction;
};
}
// 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)
sigchld_handler (int sig, siginfo_t *si, void *third)
{
// Ignore.
if (PosixProcess$ProcessManager::nativeData != NULL)
{
ProcessManagerInternal *pmi =
(ProcessManagerInternal *)PosixProcess$ProcessManager::nativeData;
char c = 0;
::write(pmi->pipe_ends[1], &c, 1);
if (pmi->old_sigaction.sa_handler != SIG_DFL
&& pmi->old_sigaction.sa_handler != SIG_IGN)
{
if ((pmi->old_sigaction.sa_flags & SA_SIGINFO) != 0)
pmi->old_sigaction.sa_sigaction(sig, si, third);
else
(*pmi->old_sigaction.sa_handler)(sig);
}
}
}
@@ -105,22 +132,35 @@ sigchld_handler (int)
void
java::lang::PosixProcess$ProcessManager::init ()
{
using namespace java::lang;
// Remenber our PID so other threads can kill us.
reaperPID = (jlong) pthread_self ();
// The nativeData is static to avoid races installing the signal
// handler in the case that it is chained.
if (nativeData == NULL )
{
ProcessManagerInternal *pmi =
(ProcessManagerInternal *)JvAllocBytes(sizeof(ProcessManagerInternal));
// SIGCHLD is blocked in all threads in posix-threads.cc.
// Setup the SIGCHLD handler.
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
if (0 != ::pipe(pmi->pipe_ends))
goto error;
sa.sa_handler = sigchld_handler;
// We only want signals when the things exit.
sa.sa_flags = SA_NOCLDSTOP;
// Make writing non-blocking so that the signal handler will
// never block.
int fl = ::fcntl(pmi->pipe_ends[1], F_GETFL);
::fcntl(pmi->pipe_ends[1], F_SETFL, fl | O_NONBLOCK);
if (-1 == sigaction (SIGCHLD, &sa, NULL))
goto error;
nativeData = (::gnu::gcj::RawDataManaged *)pmi;
// SIGCHLD is blocked in all threads in posix-threads.cc.
// Setup the SIGCHLD handler.
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
sa.sa_sigaction = sigchld_handler;
// We only want signals when the things exit.
sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
if (-1 == sigaction (SIGCHLD, &sa, &pmi->old_sigaction))
goto error;
}
// All OK.
return;
@@ -132,79 +172,52 @@ void
java::lang::PosixProcess$ProcessManager::waitForSignal ()
{
// Wait for SIGCHLD
sigset_t mask;
pthread_sigmask (0, NULL, &mask);
sigdelset (&mask, SIGCHLD);
_Jv_UnBlockSigchld();
ProcessManagerInternal *pmi = (ProcessManagerInternal *)nativeData;
// Use sigsuspend() instead of sigwait() as sigwait() doesn't play
// nicely with the GC's use of signals.
sigsuspend (&mask);
// Try to read multiple (64) notifications in one go.
char c[64];
::read(pmi->pipe_ends[0], c, sizeof (c));
// Do not check sigsuspend return value. The only legitimate return
// is EINTR, but there is a known kernel bug affecting alpha-linux
// wrt sigsuspend+handler+sigreturn that can result in a return value
// of __NR_sigsuspend and errno unset. Don't fail unnecessarily on
// older kernel versions.
_Jv_BlockSigchld();
// All OK.
return;
}
jboolean java::lang::PosixProcess$ProcessManager::reap ()
jboolean java::lang::PosixProcess$ProcessManager::reap (PosixProcess *p)
{
using namespace java::lang;
pid_t rv;
pid_t pid;
// Try to get the return code from the child process.
int status;
rv = ::waitpid ((pid_t)p->pid, &status, WNOHANG);
if (rv == -1)
throw new InternalError (JvNewStringUTF (strerror (errno)));
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 (rv == 0)
return false; // No children to wait for.
if (pid == 0)
return true; // No children to wait for.
// Look up the process in our pid map.
PosixProcess * process = removeProcessFromMap ((jlong) pid);
// Note that if process==NULL, then we have an unknown child.
// This is not common, but can happen, and isn't an error.
if (process)
{
JvSynchronize sync (process);
process->status = WIFEXITED (status) ? WEXITSTATUS (status) : -1;
process->state = PosixProcess::STATE_TERMINATED;
process->processTerminationCleanup();
process->notifyAll ();
}
}
error:
throw new InternalError (JvNewStringUTF (strerror (errno)));
JvSynchronize sync (p);
p->status = WIFEXITED (status) ? WEXITSTATUS (status) : -1;
p->state = PosixProcess::STATE_TERMINATED;
p->processTerminationCleanup();
p->notifyAll ();
return true;
}
void
java::lang::PosixProcess$ProcessManager::signalReaper ()
{
int c = pthread_kill ((pthread_t) reaperPID, SIGCHLD);
if (c == 0)
return;
// pthread_kill() failed.
throw new InternalError (JvNewStringUTF (strerror (c)));
ProcessManagerInternal *pmi = (ProcessManagerInternal *)nativeData;
char c = 0;
::write(pmi->pipe_ends[1], &c, 1);
// Ignore errors. If EPIPE the reaper has already exited.
}
void
java::lang::PosixProcess::nativeDestroy ()
{
int c = kill ((pid_t) pid, SIGKILL);
int c = ::kill ((pid_t) pid, SIGKILL);
if (c == 0)
return;
// kill() failed.
@@ -427,9 +440,9 @@ java::lang::PosixProcess::nativeSpawn ()
char c;
int r = read (msgp[0], &c, 1);
if (r == -1)
throw new IOException (JvNewStringUTF (strerror (errno)));
throw new IOException (JvNewStringUTF (strerror (errno)));
else if (r != 0)
throw new IOException (JvNewStringUTF (strerror (c)));
throw new IOException (JvNewStringUTF (strerror (c)));
}
catch (java::lang::Throwable *thrown)
{