aboutsummaryrefslogtreecommitdiff
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.cc515
1 files changed, 0 insertions, 515 deletions
diff --git a/libjava/java/lang/natPosixProcess.cc b/libjava/java/lang/natPosixProcess.cc
deleted file mode 100644
index fbd3f6a..0000000
--- a/libjava/java/lang/natPosixProcess.cc
+++ /dev/null
@@ -1,515 +0,0 @@
-// natPosixProcess.cc - Native side of POSIX process code.
-
-/* Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007
- Free Software Foundation
-
- This file is part of libgcj.
-
-This software is copyrighted work licensed under the terms of the
-Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
-details. */
-
-#include <config.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
-#include <signal.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <pthread.h>
-
-#include <posix.h>
-#include <posix-threads.h>
-#include <jvm.h>
-
-#include <java/lang/PosixProcess$ProcessManager.h>
-#include <java/lang/PosixProcess.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>
-#include <java/io/File.h>
-#include <java/io/FileDescriptor.h>
-#include <gnu/java/nio/channels/FileChannelImpl.h>
-#include <java/io/FileInputStream.h>
-#include <java/io/FileOutputStream.h>
-#include <java/io/IOException.h>
-#include <java/lang/OutOfMemoryError.h>
-#include <java/lang/PosixProcess$EOFInputStream.h>
-
-using gnu::java::nio::channels::FileChannelImpl;
-using namespace java::lang;
-
-extern char **environ;
-
-static char *
-new_string (jstring string)
-{
- jsize s = _Jv_GetStringUTFLength (string);
- char *buf = (char *) _Jv_Malloc (s + 1);
- _Jv_GetStringUTFRegion (string, 0, string->length(), buf);
- buf[s] = '\0';
- return buf;
-}
-
-static void
-cleanup (char **args, char **env, char *path)
-{
- if (args != NULL)
- {
- for (int i = 0; args[i] != NULL; ++i)
- _Jv_Free (args[i]);
- _Jv_Free (args);
- }
- if (env != NULL)
- {
- for (int i = 0; env[i] != NULL; ++i)
- _Jv_Free (env[i]);
- _Jv_Free (env);
- }
- if (path != NULL)
- _Jv_Free (path);
-}
-
-// This makes our error handling a bit simpler and it lets us avoid
-// thread bugs where we close a possibly-reopened file descriptor for
-// a second time.
-static void
-myclose (int &fd)
-{
- if (fd != -1)
- close (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
-#ifdef SA_SIGINFO
-sigchld_handler (int sig, siginfo_t *si, void *third)
-#else
-sigchld_handler (int sig)
-#endif
-{
- 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)
- {
-#ifdef SA_SIGINFO
- if ((pmi->old_sigaction.sa_flags & SA_SIGINFO) != 0)
- pmi->old_sigaction.sa_sigaction(sig, si, third);
- else
-#endif
- (*pmi->old_sigaction.sa_handler)(sig);
- }
- }
-}
-
-
-// Get ready to enter the main reaper thread loop.
-void
-java::lang::PosixProcess$ProcessManager::init ()
-{
- // 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));
-
- if (0 != ::pipe(pmi->pipe_ends))
- goto error;
-
- // 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);
-
- 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));
-
-#ifdef SA_SIGINFO
- sa.sa_sigaction = sigchld_handler;
- // We only want signals when the things exit.
- sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
-#else
- sa.sa_handler = sigchld_handler;
- // We only want signals when the things exit.
- sa.sa_flags = SA_NOCLDSTOP;
-#endif
-
- if (-1 == sigaction (SIGCHLD, &sa, &pmi->old_sigaction))
- goto error;
- }
- // All OK.
- return;
-
-error:
- throw new InternalError (JvNewStringUTF (strerror (errno)));
-}
-
-void
-java::lang::PosixProcess$ProcessManager::waitForSignal ()
-{
- // Wait for SIGCHLD
- _Jv_UnBlockSigchld();
- ProcessManagerInternal *pmi = (ProcessManagerInternal *)nativeData;
-
- // Try to read multiple (64) notifications in one go.
- char c[64];
- ::read(pmi->pipe_ends[0], c, sizeof (c));
-
- _Jv_BlockSigchld();
-
- return;
-}
-
-jboolean java::lang::PosixProcess$ProcessManager::reap (PosixProcess *p)
-{
- 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 ()
-{
- 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);
- if (c == 0)
- return;
- // kill() failed.
- throw new InternalError (JvNewStringUTF (strerror (errno)));
-}
-
-void
-java::lang::PosixProcess::nativeSpawn ()
-{
- using namespace java::io;
-
- // Initialize all locals here to make cleanup simpler.
- char **args = NULL;
- char **env = NULL;
- char *path = NULL;
- int inp[2], outp[2], errp[2], msgp[2];
- inp[0] = -1;
- inp[1] = -1;
- outp[0] = -1;
- outp[1] = -1;
- errp[0] = -1;
- errp[1] = -1;
- msgp[0] = -1;
- msgp[1] = -1;
- errorStream = NULL;
- inputStream = NULL;
- outputStream = NULL;
-
- try
- {
- // Transform arrays to native form.
- args = (char **) _Jv_Malloc ((progarray->length + 1) * sizeof (char *));
-
- // Initialize so we can gracefully recover.
- jstring *elts = elements (progarray);
- for (int i = 0; i <= progarray->length; ++i)
- args[i] = NULL;
-
- for (int i = 0; i < progarray->length; ++i)
- args[i] = new_string (elts[i]);
- args[progarray->length] = NULL;
-
- if (envp)
- {
- bool need_path = true;
- bool need_ld_library_path = true;
- int i;
-
- // Preserve PATH and LD_LIBRARY_PATH unless specified
- // explicitly. We need three extra slots. Potentially PATH
- // and LD_LIBRARY_PATH will be added plus the NULL
- // termination.
- env = (char **) _Jv_Malloc ((envp->length + 3) * sizeof (char *));
- elts = elements (envp);
-
- // Initialize so we can gracefully recover.
- for (i = 0; i < envp->length + 3; ++i)
- env[i] = NULL;
-
- for (i = 0; i < envp->length; ++i)
- {
- env[i] = new_string (elts[i]);
- if (!strncmp (env[i], "PATH=", sizeof("PATH=")))
- need_path = false;
- if (!strncmp (env[i], "LD_LIBRARY_PATH=",
- sizeof("LD_LIBRARY_PATH=")))
- need_ld_library_path = false;
- }
-
- if (need_path)
- {
- char *path_val = getenv ("PATH");
- if (path_val)
- {
- env[i] = (char *) _Jv_Malloc (strlen (path_val) +
- sizeof("PATH=") + 1);
- strcpy (env[i], "PATH=");
- strcat (env[i], path_val);
- i++;
- }
- }
- if (need_ld_library_path)
- {
- char *path_val = getenv ("LD_LIBRARY_PATH");
- if (path_val)
- {
- env[i] =
- (char *) _Jv_Malloc (strlen (path_val) +
- sizeof("LD_LIBRARY_PATH=") + 1);
- strcpy (env[i], "LD_LIBRARY_PATH=");
- strcat (env[i], path_val);
- i++;
- }
- }
- env[i] = NULL;
- }
-
- // We allocate this here because we can't call malloc() after
- // the fork.
- if (dir != NULL)
- path = new_string (dir->getPath ());
-
- // Create pipes for I/O. MSGP is for communicating exec()
- // status. If redirecting stderr to stdout, we don't need to
- // create the ERRP pipe.
- if (pipe (inp) || pipe (outp) || pipe (msgp)
- || fcntl (msgp[1], F_SETFD, FD_CLOEXEC))
- throw new IOException (JvNewStringUTF (strerror (errno)));
- if (! redirect && pipe (errp))
- 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.
- if (redirect)
- errorStream = PosixProcess$EOFInputStream::instance;
- else
- 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.
-
- // 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)
- environ = env;
-
- // We ignore errors from dup2 because they should never occur.
- dup2 (outp[0], 0);
- dup2 (inp[1], 1);
- dup2 (redirect ? inp[1] : errp[1], 2);
-
- // Use close and not myclose -- we're in the child, and we
- // aren't worried about the possible race condition.
- close (inp[0]);
- close (inp[1]);
- if (! redirect)
- {
- close (errp[0]);
- close (errp[1]);
- }
- close (outp[0]);
- close (outp[1]);
- close (msgp[0]);
-
- // Change directory.
- if (path != NULL)
- {
- if (chdir (path) != 0)
- {
- char c = errno;
- write (msgp[1], &c, 1);
- _exit (127);
- }
- }
- // Make sure all file descriptors are closed. In
- // multi-threaded programs, there is a race between when a
- // descriptor is obtained, when we can set FD_CLOEXEC, and
- // fork(). If the fork occurs before FD_CLOEXEC is set, the
- // descriptor would leak to the execed process if we did not
- // manually close it. So that is what we do. Since we
- // close all the descriptors, it is redundant to set
- // FD_CLOEXEC on them elsewhere.
- int max_fd;
-#ifdef HAVE_GETRLIMIT
- rlimit rl;
- int rv = getrlimit(RLIMIT_NOFILE, &rl);
- if (rv == 0)
- max_fd = rl.rlim_max - 1;
- else
- max_fd = 1024 - 1;
-#else
- max_fd = 1024 - 1;
-#endif
- while(max_fd > 2)
- {
- if (max_fd != msgp[1])
- close (max_fd);
- max_fd--;
- }
- // Make sure that SIGCHLD is unblocked for the new process.
- sigset_t mask;
- sigemptyset (&mask);
- sigaddset (&mask, SIGCHLD);
- sigprocmask (SIG_UNBLOCK, &mask, NULL);
-
- execvp (args[0], args);
-
- // Send the parent notification that the exec failed.
- char c = errno;
- write (msgp[1], &c, 1);
- _exit (127);
- }
-
- // Parent. Close extra file descriptors and mark ours as
- // close-on-exec.
- pid = (jlong) pid_tmp;
-
- myclose (outp[0]);
- myclose (inp[1]);
- if (! redirect)
- myclose (errp[1]);
- myclose (msgp[1]);
-
- char c;
- int r = read (msgp[0], &c, 1);
- if (r == -1)
- throw new IOException (JvNewStringUTF (strerror (errno)));
- else if (r != 0)
- throw new IOException (JvNewStringUTF (strerror (c)));
- }
- catch (java::lang::Throwable *thrown)
- {
- // Do some cleanup we only do on failure. If a stream object
- // has been created, we must close the stream itself (to avoid
- // duplicate closes when the stream object is collected).
- // Otherwise we simply close the underlying file descriptor.
- // We ignore errors here as they are uninteresting.
-
- try
- {
- if (inputStream != NULL)
- inputStream->close ();
- else
- myclose (inp[0]);
- }
- catch (java::lang::Throwable *ignore)
- {
- }
-
- try
- {
- if (outputStream != NULL)
- outputStream->close ();
- else
- myclose (outp[1]);
- }
- catch (java::lang::Throwable *ignore)
- {
- }
-
- try
- {
- if (errorStream != NULL)
- errorStream->close ();
- else if (! redirect)
- myclose (errp[0]);
- }
- catch (java::lang::Throwable *ignore)
- {
- }
-
- // These are potentially duplicate, but it doesn't matter due to
- // the use of myclose.
- myclose (outp[0]);
- myclose (inp[1]);
- if (! redirect)
- myclose (errp[1]);
- myclose (msgp[1]);
-
- exception = thrown;
- }
-
- myclose (msgp[0]);
- cleanup (args, env, path);
-}