Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JDK-8274320: os::fork_and_exec() should be using posix_spawn #5698

Changes from all commits
File filter

Filter by extension

Filter by extension

Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -60,6 +60,7 @@
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <spawn.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/types.h>
@@ -1936,40 +1937,16 @@ char** os::get_environ() { return environ; }
// doesn't block SIGINT et al.
// -this function is unsafe to use in non-error situations, mainly
// because the child process will inherit all parent descriptors.
int os::fork_and_exec(const char* cmd, bool prefer_vfork) {
const char * argv[4] = {"sh", "-c", cmd, NULL};

pid_t pid ;

int os::fork_and_exec(const char* cmd) {
const char* argv[4] = {"sh", "-c", cmd, NULL};
pid_t pid = -1;
char** env = os::get_environ();

// Use always vfork on AIX, since its safe and helps with analyzing OOM situations.
// Otherwise leave it up to the caller.
AIX_ONLY(prefer_vfork = true;)
#ifdef __APPLE__
pid = ::fork();
pid = prefer_vfork ? ::vfork() : ::fork();

if (pid < 0) {
// fork failed
return -1;

} else if (pid == 0) {
// child process

::execve("/bin/sh", (char* const*)argv, env);

// execve failed

} else {
// copied from J2SE ..._waitForProcessExit() in UNIXProcess_md.c; we don't
// care about the actual exit code, for now.

// Note: cast is needed because posix_spawn() requires - for compatibility with ancient
// C-code - a non-const argv/envp pointer array. But it is fine to hand in literal
// strings and just cast the constness away. See also ProcessImpl_md.c.
int rc = ::posix_spawn(&pid, "/bin/sh", NULL, NULL, (char**) argv, env);
if (rc == 0) {
int status;

// Wait for the child process to exit. This returns immediately if
// the child has already exited. */
while (::waitpid(pid, &status, 0) < 0) {
@@ -1979,7 +1956,6 @@ int os::fork_and_exec(const char* cmd, bool prefer_vfork) {
default: return -1;

if (WIFEXITED(status)) {
// The child exited normally; get its exit code.
return WEXITSTATUS(status);
@@ -1994,6 +1970,9 @@ int os::fork_and_exec(const char* cmd, bool prefer_vfork) {
// Unknown exit code; pass it through
return status;
} else {
// Don't log, we are inside error handling
return -1;

@@ -5616,7 +5616,7 @@ int os::PlatformMonitor::wait(jlong millis) {

// Run the specified command in a separate process. Return its exit value,
// or -1 on failure (e.g. can't create a new process).
int os::fork_and_exec(const char* cmd, bool dummy /* ignored */) {
int os::fork_and_exec(const char* cmd) {
DWORD exit_code;
@@ -515,10 +515,7 @@ class os: AllStatic {

// run cmd in a separate process and return its exit code; or -1 on failures.
// Note: only safe to use in fatal error situations.
// The "prefer_vfork" argument is only used on POSIX platforms to
// indicate whether vfork should be used instead of fork to spawn the
// child process (ignored on AIX, which always uses vfork).
static int fork_and_exec(const char *cmd, bool prefer_vfork = false);
static int fork_and_exec(const char *cmd);

// Call ::exit() on all platforms but Windows
static void exit(int num);
@@ -1684,7 +1684,7 @@ void VM_ReportJavaOutOfMemory::doit() {
tty->print_cr("\"%s\"...", cmd);

if (os::fork_and_exec(cmd, true) < 0) {
if (os::fork_and_exec(cmd) < 0) {
tty->print_cr("os::fork_and_exec failed: %s (%s=%d)",
os::strerror(errno), os::errno_name(errno), errno);