mirror of
https://github.com/reactos/ninja.git
synced 2025-02-22 04:30:55 +00:00
Merge pull request #1118 from nico/posixspawn2
Use posix_spawn() instead of fork()/exec().
This commit is contained in:
commit
aea5a4d41f
@ -22,6 +22,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <spawn.h>
|
||||||
|
|
||||||
|
extern char** environ;
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
@ -50,62 +53,60 @@ bool Subprocess::Start(SubprocessSet* set, const string& command) {
|
|||||||
#endif // !USE_PPOLL
|
#endif // !USE_PPOLL
|
||||||
SetCloseOnExec(fd_);
|
SetCloseOnExec(fd_);
|
||||||
|
|
||||||
pid_ = fork();
|
posix_spawn_file_actions_t action;
|
||||||
if (pid_ < 0)
|
if (posix_spawn_file_actions_init(&action) != 0)
|
||||||
Fatal("fork: %s", strerror(errno));
|
Fatal("posix_spawn_file_actions_init: %s", strerror(errno));
|
||||||
|
|
||||||
if (pid_ == 0) {
|
if (posix_spawn_file_actions_addclose(&action, output_pipe[0]) != 0)
|
||||||
close(output_pipe[0]);
|
Fatal("posix_spawn_file_actions_addclose: %s", strerror(errno));
|
||||||
|
|
||||||
// Track which fd we use to report errors on.
|
posix_spawnattr_t attr;
|
||||||
int error_pipe = output_pipe[1];
|
if (posix_spawnattr_init(&attr) != 0)
|
||||||
do {
|
Fatal("posix_spawnattr_init: %s", strerror(errno));
|
||||||
if (sigaction(SIGINT, &set->old_int_act_, 0) < 0)
|
|
||||||
break;
|
|
||||||
if (sigaction(SIGTERM, &set->old_term_act_, 0) < 0)
|
|
||||||
break;
|
|
||||||
if (sigaction(SIGHUP, &set->old_hup_act_, 0) < 0)
|
|
||||||
break;
|
|
||||||
if (sigprocmask(SIG_SETMASK, &set->old_mask_, 0) < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!use_console_) {
|
short flags = 0;
|
||||||
// Put the child in its own process group, so ctrl-c won't reach it.
|
|
||||||
if (setpgid(0, 0) < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Open /dev/null over stdin.
|
flags |= POSIX_SPAWN_SETSIGMASK;
|
||||||
int devnull = open("/dev/null", O_RDONLY);
|
if (posix_spawnattr_setsigmask(&attr, &set->old_mask_) != 0)
|
||||||
if (devnull < 0)
|
Fatal("posix_spawnattr_setsigmask: %s", strerror(errno));
|
||||||
break;
|
// Signals which are set to be caught in the calling process image are set to
|
||||||
if (dup2(devnull, 0) < 0)
|
// default action in the new process image, so no explicit
|
||||||
break;
|
// POSIX_SPAWN_SETSIGDEF parameter is needed.
|
||||||
close(devnull);
|
|
||||||
|
|
||||||
if (dup2(output_pipe[1], 1) < 0 ||
|
// TODO: Consider using POSIX_SPAWN_USEVFORK on Linux with glibc?
|
||||||
dup2(output_pipe[1], 2) < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Now can use stderr for errors.
|
if (!use_console_) {
|
||||||
error_pipe = 2;
|
// Put the child in its own process group, so ctrl-c won't reach it.
|
||||||
close(output_pipe[1]);
|
flags |= POSIX_SPAWN_SETPGROUP;
|
||||||
}
|
// No need to posix_spawnattr_setpgroup(&attr, 0), it's the default.
|
||||||
// In the console case, output_pipe is still inherited by the child and
|
|
||||||
// closed when the subprocess finishes, which then notifies ninja.
|
|
||||||
|
|
||||||
execl("/bin/sh", "/bin/sh", "-c", command.c_str(), (char *) NULL);
|
// Open /dev/null over stdin.
|
||||||
} while (false);
|
if (posix_spawn_file_actions_addopen(&action, 0, "/dev/null", O_RDONLY,
|
||||||
|
0) != 0) {
|
||||||
// If we get here, something went wrong; the execl should have
|
Fatal("posix_spawn_file_actions_addopen: %s", strerror(errno));
|
||||||
// replaced us.
|
|
||||||
char* err = strerror(errno);
|
|
||||||
if (write(error_pipe, err, strlen(err)) < 0) {
|
|
||||||
// If the write fails, there's nothing we can do.
|
|
||||||
// But this block seems necessary to silence the warning.
|
|
||||||
}
|
}
|
||||||
_exit(1);
|
|
||||||
|
if (posix_spawn_file_actions_adddup2(&action, output_pipe[1], 1) != 0)
|
||||||
|
Fatal("posix_spawn_file_actions_adddup2: %s", strerror(errno));
|
||||||
|
if (posix_spawn_file_actions_adddup2(&action, output_pipe[1], 2) != 0)
|
||||||
|
Fatal("posix_spawn_file_actions_adddup2: %s", strerror(errno));
|
||||||
|
// In the console case, output_pipe is still inherited by the child and
|
||||||
|
// closed when the subprocess finishes, which then notifies ninja.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (posix_spawnattr_setflags(&attr, flags) != 0)
|
||||||
|
Fatal("posix_spawnattr_setflags: %s", strerror(errno));
|
||||||
|
|
||||||
|
const char* spawned_args[] = { "/bin/sh", "-c", command.c_str(), NULL };
|
||||||
|
if (posix_spawn(&pid_, "/bin/sh", &action, &attr,
|
||||||
|
const_cast<char**>(spawned_args), environ) != 0)
|
||||||
|
Fatal("posix_spawn: %s", strerror(errno));
|
||||||
|
|
||||||
|
if (posix_spawnattr_destroy(&attr) != 0)
|
||||||
|
Fatal("posix_spawnattr_destroy: %s", strerror(errno));
|
||||||
|
if (posix_spawn_file_actions_destroy(&action) != 0)
|
||||||
|
Fatal("posix_spawn_file_actions_destroy: %s", strerror(errno));
|
||||||
|
|
||||||
close(output_pipe[1]);
|
close(output_pipe[1]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -226,7 +226,8 @@ TEST_F(SubprocessTest, SetWithLots) {
|
|||||||
rlimit rlim;
|
rlimit rlim;
|
||||||
ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlim));
|
ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlim));
|
||||||
if (rlim.rlim_cur < kNumProcs) {
|
if (rlim.rlim_cur < kNumProcs) {
|
||||||
printf("Raise [ulimit -n] well above %u (currently %lu) to make this test go\n", kNumProcs, rlim.rlim_cur);
|
printf("Raise [ulimit -n] above %u (currently %lu) to make this test go\n",
|
||||||
|
kNumProcs, rlim.rlim_cur);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user