mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-18 10:04:42 +02:00
8262955: Unify os::fork_and_exec() across Posix platforms
Reviewed-by: dholmes, hseigel
This commit is contained in:
parent
39b1113838
commit
5b9b170db9
7 changed files with 91 additions and 210 deletions
|
@ -108,7 +108,6 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <sys/vminfo.h>
|
#include <sys/vminfo.h>
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
// Missing prototypes for various system APIs.
|
// Missing prototypes for various system APIs.
|
||||||
extern "C"
|
extern "C"
|
||||||
|
@ -3150,64 +3149,6 @@ size_t os::current_stack_size() {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern char** environ;
|
|
||||||
|
|
||||||
// Run the specified command in a separate process. Return its exit value,
|
|
||||||
// or -1 on failure (e.g. can't fork a new process).
|
|
||||||
// Unlike system(), this function can be called from signal handler. It
|
|
||||||
// doesn't block SIGINT et al.
|
|
||||||
int os::fork_and_exec(char* cmd, bool use_vfork_if_available) {
|
|
||||||
char* argv[4] = { (char*)"sh", (char*)"-c", cmd, NULL};
|
|
||||||
|
|
||||||
pid_t pid = fork();
|
|
||||||
|
|
||||||
if (pid < 0) {
|
|
||||||
// fork failed
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
} else if (pid == 0) {
|
|
||||||
// child process
|
|
||||||
|
|
||||||
// Try to be consistent with system(), which uses "/usr/bin/sh" on AIX.
|
|
||||||
execve("/usr/bin/sh", argv, environ);
|
|
||||||
|
|
||||||
// execve failed
|
|
||||||
_exit(-1);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// copied from J2SE ..._waitForProcessExit() in UNIXProcess_md.c; we don't
|
|
||||||
// care about the actual exit code, for now.
|
|
||||||
|
|
||||||
int status;
|
|
||||||
|
|
||||||
// Wait for the child process to exit. This returns immediately if
|
|
||||||
// the child has already exited. */
|
|
||||||
while (waitpid(pid, &status, 0) < 0) {
|
|
||||||
switch (errno) {
|
|
||||||
case ECHILD: return 0;
|
|
||||||
case EINTR: break;
|
|
||||||
default: return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
// The child exited normally; get its exit code.
|
|
||||||
return WEXITSTATUS(status);
|
|
||||||
} else if (WIFSIGNALED(status)) {
|
|
||||||
// The child exited because of a signal.
|
|
||||||
// The best value to return is 0x80 + signal number,
|
|
||||||
// because that is what all Unix shells do, and because
|
|
||||||
// it allows callers to distinguish between process exit and
|
|
||||||
// process death by signal.
|
|
||||||
return 0x80 + WTERMSIG(status);
|
|
||||||
} else {
|
|
||||||
// Unknown exit code; pass it through.
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the default path to the core file
|
// Get the default path to the core file
|
||||||
// Returns the length of the string
|
// Returns the length of the string
|
||||||
int os::get_core_path(char* buffer, size_t bufferSize) {
|
int os::get_core_path(char* buffer, size_t bufferSize) {
|
||||||
|
|
|
@ -93,7 +93,6 @@
|
||||||
# include <sys/time.h>
|
# include <sys/time.h>
|
||||||
# include <sys/times.h>
|
# include <sys/times.h>
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <sys/wait.h>
|
|
||||||
# include <time.h>
|
# include <time.h>
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
|
|
||||||
|
@ -2610,80 +2609,6 @@ void os::pause() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Darwin has no "environ" in a dynamic library.
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <crt_externs.h>
|
|
||||||
#define environ (*_NSGetEnviron())
|
|
||||||
#else
|
|
||||||
extern char** environ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Run the specified command in a separate process. Return its exit value,
|
|
||||||
// or -1 on failure (e.g. can't fork a new process).
|
|
||||||
// Unlike system(), this function can be called from signal handler. It
|
|
||||||
// doesn't block SIGINT et al.
|
|
||||||
int os::fork_and_exec(char* cmd, bool use_vfork_if_available) {
|
|
||||||
const char * argv[4] = {"sh", "-c", cmd, NULL};
|
|
||||||
|
|
||||||
// fork() in BsdThreads/NPTL is not async-safe. It needs to run
|
|
||||||
// pthread_atfork handlers and reset pthread library. All we need is a
|
|
||||||
// separate process to execve. Make a direct syscall to fork process.
|
|
||||||
// On IA64 there's no fork syscall, we have to use fork() and hope for
|
|
||||||
// the best...
|
|
||||||
pid_t pid = fork();
|
|
||||||
|
|
||||||
if (pid < 0) {
|
|
||||||
// fork failed
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
} else if (pid == 0) {
|
|
||||||
// child process
|
|
||||||
|
|
||||||
// execve() in BsdThreads will call pthread_kill_other_threads_np()
|
|
||||||
// first to kill every thread on the thread list. Because this list is
|
|
||||||
// not reset by fork() (see notes above), execve() will instead kill
|
|
||||||
// every thread in the parent process. We know this is the only thread
|
|
||||||
// in the new process, so make a system call directly.
|
|
||||||
// IA64 should use normal execve() from glibc to match the glibc fork()
|
|
||||||
// above.
|
|
||||||
execve("/bin/sh", (char* const*)argv, environ);
|
|
||||||
|
|
||||||
// execve failed
|
|
||||||
_exit(-1);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// copied from J2SE ..._waitForProcessExit() in UNIXProcess_md.c; we don't
|
|
||||||
// care about the actual exit code, for now.
|
|
||||||
|
|
||||||
int status;
|
|
||||||
|
|
||||||
// Wait for the child process to exit. This returns immediately if
|
|
||||||
// the child has already exited. */
|
|
||||||
while (waitpid(pid, &status, 0) < 0) {
|
|
||||||
switch (errno) {
|
|
||||||
case ECHILD: return 0;
|
|
||||||
case EINTR: break;
|
|
||||||
default: return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
// The child exited normally; get its exit code.
|
|
||||||
return WEXITSTATUS(status);
|
|
||||||
} else if (WIFSIGNALED(status)) {
|
|
||||||
// The child exited because of a signal
|
|
||||||
// The best value to return is 0x80 + signal number,
|
|
||||||
// because that is what all Unix shells do, and because
|
|
||||||
// it allows callers to distinguish between process exit and
|
|
||||||
// process death by signal.
|
|
||||||
return 0x80 + WTERMSIG(status);
|
|
||||||
} else {
|
|
||||||
// Unknown exit code; pass it through
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the kern.corefile setting, or otherwise the default path to the core file
|
// Get the kern.corefile setting, or otherwise the default path to the core file
|
||||||
// Returns the length of the string
|
// Returns the length of the string
|
||||||
int os::get_core_path(char* buffer, size_t bufferSize) {
|
int os::get_core_path(char* buffer, size_t bufferSize) {
|
||||||
|
|
|
@ -97,7 +97,6 @@
|
||||||
# include <sys/times.h>
|
# include <sys/times.h>
|
||||||
# include <sys/utsname.h>
|
# include <sys/utsname.h>
|
||||||
# include <sys/socket.h>
|
# include <sys/socket.h>
|
||||||
# include <sys/wait.h>
|
|
||||||
# include <pwd.h>
|
# include <pwd.h>
|
||||||
# include <poll.h>
|
# include <poll.h>
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
|
@ -5219,68 +5218,6 @@ void os::pause() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern char** environ;
|
|
||||||
|
|
||||||
// Run the specified command in a separate process. Return its exit value,
|
|
||||||
// or -1 on failure (e.g. can't fork a new process).
|
|
||||||
// Unlike system(), this function can be called from signal handler. It
|
|
||||||
// doesn't block SIGINT et al.
|
|
||||||
int os::fork_and_exec(char* cmd, bool use_vfork_if_available) {
|
|
||||||
const char * argv[4] = {"sh", "-c", cmd, NULL};
|
|
||||||
|
|
||||||
pid_t pid ;
|
|
||||||
|
|
||||||
if (use_vfork_if_available) {
|
|
||||||
pid = vfork();
|
|
||||||
} else {
|
|
||||||
pid = fork();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid < 0) {
|
|
||||||
// fork failed
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
} else if (pid == 0) {
|
|
||||||
// child process
|
|
||||||
|
|
||||||
execve("/bin/sh", (char* const*)argv, environ);
|
|
||||||
|
|
||||||
// execve failed
|
|
||||||
_exit(-1);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// copied from J2SE ..._waitForProcessExit() in UNIXProcess_md.c; we don't
|
|
||||||
// care about the actual exit code, for now.
|
|
||||||
|
|
||||||
int status;
|
|
||||||
|
|
||||||
// Wait for the child process to exit. This returns immediately if
|
|
||||||
// the child has already exited. */
|
|
||||||
while (waitpid(pid, &status, 0) < 0) {
|
|
||||||
switch (errno) {
|
|
||||||
case ECHILD: return 0;
|
|
||||||
case EINTR: break;
|
|
||||||
default: return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
// The child exited normally; get its exit code.
|
|
||||||
return WEXITSTATUS(status);
|
|
||||||
} else if (WIFSIGNALED(status)) {
|
|
||||||
// The child exited because of a signal
|
|
||||||
// The best value to return is 0x80 + signal number,
|
|
||||||
// because that is what all Unix shells do, and because
|
|
||||||
// it allows callers to distinguish between process exit and
|
|
||||||
// process death by signal.
|
|
||||||
return 0x80 + WTERMSIG(status);
|
|
||||||
} else {
|
|
||||||
// Unknown exit code; pass it through
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the default path to the core file
|
// Get the default path to the core file
|
||||||
// Returns the length of the string
|
// Returns the length of the string
|
||||||
int os::get_core_path(char* buffer, size_t bufferSize) {
|
int os::get_core_path(char* buffer, size_t bufferSize) {
|
||||||
|
|
|
@ -51,11 +51,17 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <utmpx.h>
|
#include <utmpx.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <crt_externs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ROOT_UID 0
|
#define ROOT_UID 0
|
||||||
|
|
||||||
#ifndef MAP_ANONYMOUS
|
#ifndef MAP_ANONYMOUS
|
||||||
|
@ -1765,3 +1771,75 @@ int os::PlatformMonitor::wait(jlong millis) {
|
||||||
return OS_OK;
|
return OS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Darwin has no "environ" in a dynamic library.
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#define environ (*_NSGetEnviron())
|
||||||
|
#else
|
||||||
|
extern char** environ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char** os::get_environ() { return environ; }
|
||||||
|
|
||||||
|
// Run the specified command in a separate process. Return its exit value,
|
||||||
|
// or -1 on failure (e.g. can't fork a new process).
|
||||||
|
// Notes: -Unlike system(), this function can be called from signal handler. It
|
||||||
|
// 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 ;
|
||||||
|
|
||||||
|
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;)
|
||||||
|
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
|
||||||
|
::_exit(-1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// copied from J2SE ..._waitForProcessExit() in UNIXProcess_md.c; we don't
|
||||||
|
// care about the actual exit code, for now.
|
||||||
|
|
||||||
|
int status;
|
||||||
|
|
||||||
|
// Wait for the child process to exit. This returns immediately if
|
||||||
|
// the child has already exited. */
|
||||||
|
while (::waitpid(pid, &status, 0) < 0) {
|
||||||
|
switch (errno) {
|
||||||
|
case ECHILD: return 0;
|
||||||
|
case EINTR: break;
|
||||||
|
default: return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
// The child exited normally; get its exit code.
|
||||||
|
return WEXITSTATUS(status);
|
||||||
|
} else if (WIFSIGNALED(status)) {
|
||||||
|
// The child exited because of a signal
|
||||||
|
// The best value to return is 0x80 + signal number,
|
||||||
|
// because that is what all Unix shells do, and because
|
||||||
|
// it allows callers to distinguish between process exit and
|
||||||
|
// process death by signal.
|
||||||
|
return 0x80 + WTERMSIG(status);
|
||||||
|
} else {
|
||||||
|
// Unknown exit code; pass it through
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -266,6 +266,8 @@ bool os::unsetenv(const char* name) {
|
||||||
return (SetEnvironmentVariable(name, NULL) == TRUE);
|
return (SetEnvironmentVariable(name, NULL) == TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char** os::get_environ() { return _environ; }
|
||||||
|
|
||||||
// No setuid programs under Windows.
|
// No setuid programs under Windows.
|
||||||
bool os::have_special_privileges() {
|
bool os::have_special_privileges() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -5512,7 +5514,7 @@ int os::PlatformMonitor::wait(jlong millis) {
|
||||||
|
|
||||||
// Run the specified command in a separate process. Return its exit value,
|
// Run the specified command in a separate process. Return its exit value,
|
||||||
// or -1 on failure (e.g. can't create a new process).
|
// or -1 on failure (e.g. can't create a new process).
|
||||||
int os::fork_and_exec(char* cmd, bool use_vfork_if_available) {
|
int os::fork_and_exec(const char* cmd, bool dummy /* ignored */) {
|
||||||
STARTUPINFO si;
|
STARTUPINFO si;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
DWORD exit_code;
|
DWORD exit_code;
|
||||||
|
|
|
@ -34,14 +34,6 @@
|
||||||
#include "utilities/ostream.hpp"
|
#include "utilities/ostream.hpp"
|
||||||
|
|
||||||
#include <stdlib.h> // for environment variables
|
#include <stdlib.h> // for environment variables
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <crt_externs.h>
|
|
||||||
#define environ (*_NSGetEnviron())
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef environ
|
|
||||||
extern char** environ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static JfrOSInterface* _instance = NULL;
|
static JfrOSInterface* _instance = NULL;
|
||||||
|
|
||||||
|
@ -281,14 +273,14 @@ const char* JfrOSInterface::virtualization_name() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int JfrOSInterface::generate_initial_environment_variable_events() {
|
int JfrOSInterface::generate_initial_environment_variable_events() {
|
||||||
if (environ == NULL) {
|
if (os::get_environ() == NULL) {
|
||||||
return OS_ERR;
|
return OS_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EventInitialEnvironmentVariable::is_enabled()) {
|
if (EventInitialEnvironmentVariable::is_enabled()) {
|
||||||
// One time stamp for all events, so they can be grouped together
|
// One time stamp for all events, so they can be grouped together
|
||||||
JfrTicks time_stamp = JfrTicks::now();
|
JfrTicks time_stamp = JfrTicks::now();
|
||||||
for (char** p = environ; *p != NULL; p++) {
|
for (char** p = os::get_environ(); *p != NULL; p++) {
|
||||||
char* variable = *p;
|
char* variable = *p;
|
||||||
char* equal_sign = strchr(variable, '=');
|
char* equal_sign = strchr(variable, '=');
|
||||||
if (equal_sign != NULL) {
|
if (equal_sign != NULL) {
|
||||||
|
|
|
@ -182,6 +182,8 @@ class os: AllStatic {
|
||||||
|
|
||||||
// unset environment variable
|
// unset environment variable
|
||||||
static bool unsetenv(const char* name);
|
static bool unsetenv(const char* name);
|
||||||
|
// Get environ pointer, platform independently
|
||||||
|
static char** get_environ();
|
||||||
|
|
||||||
static bool have_special_privileges();
|
static bool have_special_privileges();
|
||||||
|
|
||||||
|
@ -501,8 +503,12 @@ class os: AllStatic {
|
||||||
|
|
||||||
static bool message_box(const char* title, const char* message);
|
static bool message_box(const char* title, const char* message);
|
||||||
|
|
||||||
// run cmd in a separate process and return its exit code; or -1 on failures
|
// run cmd in a separate process and return its exit code; or -1 on failures.
|
||||||
static int fork_and_exec(char *cmd, bool use_vfork_if_available = false);
|
// 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);
|
||||||
|
|
||||||
// Call ::exit() on all platforms but Windows
|
// Call ::exit() on all platforms but Windows
|
||||||
static void exit(int num);
|
static void exit(int num);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue