summaryrefslogtreecommitdiff
path: root/libjava/java/lang/natPosixProcess.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/lang/natPosixProcess.cc')
-rw-r--r--libjava/java/lang/natPosixProcess.cc157
1 files changed, 85 insertions, 72 deletions
diff --git a/libjava/java/lang/natPosixProcess.cc b/libjava/java/lang/natPosixProcess.cc
index 252da6e80ab..c7b8b6e5eb0 100644
--- a/libjava/java/lang/natPosixProcess.cc
+++ b/libjava/java/lang/natPosixProcess.cc
@@ -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 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.
- 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)));
+ pid_t rv;
+
+ // 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)));
+
+ if (rv == 0)
+ return false; // No children to wait for.
+
+ 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)
{