mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-10 01:29:05 -04:00
[subprocs] use posix_spawn in place of fork+exec #2194
This commit is contained in:
parent
9d7fb54535
commit
8585c0a8a9
92
src/lib/fd.c
92
src/lib/fd.c
@ -8,6 +8,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#ifdef __MINGW64__
|
#ifdef __MINGW64__
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#else
|
||||||
|
#include <spawn.h>
|
||||||
#endif
|
#endif
|
||||||
#if (defined(__linux__))
|
#if (defined(__linux__))
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
@ -142,6 +144,7 @@ int ncfdplane_destroy(ncfdplane* n){
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef __MINGW64__
|
||||||
// get 2 pipes, and ensure they're both set to close-on-exec
|
// get 2 pipes, and ensure they're both set to close-on-exec
|
||||||
static int
|
static int
|
||||||
lay_pipes(int pipes[static 2]){
|
lay_pipes(int pipes[static 2]){
|
||||||
@ -168,45 +171,67 @@ lay_pipes(int pipes[static 2]){
|
|||||||
// ncfdplane around the read end, involving creation of a new thread. the
|
// ncfdplane around the read end, involving creation of a new thread. the
|
||||||
// parent then returns.
|
// parent then returns.
|
||||||
static pid_t
|
static pid_t
|
||||||
launch_pipe_process(int* pipefd, int* pidfd){
|
launch_pipe_process(int* pipefd, int* pidfd, unsigned usepath,
|
||||||
#ifndef __MINGW64__
|
const char* bin, char* const arg[], char* const env[]){
|
||||||
*pidfd = -1;
|
*pidfd = -1;
|
||||||
int pipes[2];
|
int pipes[2];
|
||||||
if(lay_pipes(pipes)){
|
if(lay_pipes(pipes)){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
pid_t p = -1;
|
pid_t p = -1;
|
||||||
// on linux, we try to use the brand-new pidfd capability via clone3(). if
|
|
||||||
// that fails, fall through to fork(), which is all we try to use on freebsd.
|
|
||||||
// FIXME clone3 is not yet supported on debian sparc64/alpha as of 2020-07
|
|
||||||
#ifdef USING_PIDFD
|
#ifdef USING_PIDFD
|
||||||
|
// on linux, we try to use the brand-new pidfd capability via clone3(). if
|
||||||
|
// that fails, fall through to posix_spawn(), our only option on freebsd.
|
||||||
|
// FIXME clone3 is not yet supported on debian sparc64/alpha as of 2020-07
|
||||||
struct clone_args clargs;
|
struct clone_args clargs;
|
||||||
memset(&clargs, 0, sizeof(clargs));
|
memset(&clargs, 0, sizeof(clargs));
|
||||||
clargs.pidfd = (uintptr_t)pidfd;
|
clargs.pidfd = (uintptr_t)pidfd;
|
||||||
clargs.flags = CLONE_CLEAR_SIGHAND | CLONE_FS | CLONE_PIDFD;
|
clargs.flags = CLONE_CLEAR_SIGHAND | CLONE_FS | CLONE_PIDFD;
|
||||||
clargs.exit_signal = SIGCHLD;
|
clargs.exit_signal = SIGCHLD;
|
||||||
p = syscall(__NR_clone3, &clargs, sizeof(clargs));
|
p = syscall(__NR_clone3, &clargs, sizeof(clargs));
|
||||||
#endif
|
|
||||||
if(p < 0){
|
|
||||||
p = fork();
|
|
||||||
}
|
|
||||||
if(p == 0){ // child
|
if(p == 0){ // child
|
||||||
if(dup2(pipes[1], STDOUT_FILENO) < 0 || dup2(pipes[1], STDERR_FILENO) < 0){
|
if(dup2(pipes[1], STDOUT_FILENO) < 0 || dup2(pipes[1], STDERR_FILENO) < 0){
|
||||||
logerror("Couldn't dup() %d (%s)\n", pipes[1], strerror(errno));
|
logerror("Couldn't dup() %d (%s)\n", pipes[1], strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}else if(p > 0){ // parent
|
if(env){
|
||||||
|
execvpe(bin, arg, env);
|
||||||
|
}else if(usepath){
|
||||||
|
execvp(bin, arg);
|
||||||
|
}else{
|
||||||
|
execv(bin, arg);
|
||||||
|
}
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}else if(p < 0){
|
||||||
|
logwarn("clone3() failed (%s), using posix_spawn()\n", strerror(errno));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(p < 0){
|
||||||
|
posix_spawn_file_actions_t factions;
|
||||||
|
if(posix_spawn_file_actions_init(&factions)){
|
||||||
|
logerror("couldn't initialize spawn file actions\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
posix_spawn_file_actions_adddup2(&factions, pipes[1], STDOUT_FILENO);
|
||||||
|
posix_spawn_file_actions_adddup2(&factions, pipes[1], STDERR_FILENO);
|
||||||
|
int r;
|
||||||
|
if(usepath){
|
||||||
|
r = posix_spawnp(&p, bin, &factions, NULL, arg, env);
|
||||||
|
}else{
|
||||||
|
r = posix_spawn(&p, bin, &factions, NULL, arg, env);
|
||||||
|
}
|
||||||
|
if(r){
|
||||||
|
logerror("posix_spawn %s failed (%s)\n", bin, strerror(errno));
|
||||||
|
}
|
||||||
|
posix_spawn_file_actions_destroy(&factions);
|
||||||
|
}
|
||||||
|
if(p > 0){ // parent
|
||||||
*pipefd = pipes[0];
|
*pipefd = pipes[0];
|
||||||
set_fd_nonblocking(*pipefd, 1, NULL);
|
set_fd_nonblocking(*pipefd, 1, NULL);
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
#else
|
|
||||||
// FIXME use CreateProcess()
|
|
||||||
(void)pipefd;
|
|
||||||
(void)pidfd;
|
|
||||||
return -1;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// nuke the just-spawned process, and reap it. called before the subprocess
|
// nuke the just-spawned process, and reap it. called before the subprocess
|
||||||
// reader thread is launched (which otherwise reaps the subprocess).
|
// reader thread is launched (which otherwise reaps the subprocess).
|
||||||
@ -326,33 +351,15 @@ ncexecvpe(ncplane* n, const ncsubproc_options* opts, unsigned usepath,
|
|||||||
if(opts->flags > 0){
|
if(opts->flags > 0){
|
||||||
logwarn("Provided unsupported flags %016jx\n", (uintmax_t)opts->flags);
|
logwarn("Provided unsupported flags %016jx\n", (uintmax_t)opts->flags);
|
||||||
}
|
}
|
||||||
|
#ifndef __MINGW64__
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
ncsubproc* ret = malloc(sizeof(*ret));
|
ncsubproc* ret = malloc(sizeof(*ret));
|
||||||
if(ret == NULL){
|
if(ret == NULL){
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset(ret, 0, sizeof(*ret));
|
memset(ret, 0, sizeof(*ret));
|
||||||
ret->pid = launch_pipe_process(&fd, &ret->pidfd);
|
ret->pid = launch_pipe_process(&fd, &ret->pidfd, usepath, bin, arg, env);
|
||||||
if(ret->pid == 0){
|
if(ret->pid < 0){
|
||||||
if(env){
|
|
||||||
#ifdef __linux__
|
|
||||||
execvpe(bin, arg, env);
|
|
||||||
#elif defined(__APPLE__) || defined(__gnu_hurd__)
|
|
||||||
(void)env;
|
|
||||||
execvp(bin, arg); // FIXME env? use posix_spawn()!
|
|
||||||
#elif defined(__MINGW64__) // use CreateProcess()!
|
|
||||||
(void)arg;
|
|
||||||
(void)env;
|
|
||||||
#else
|
|
||||||
exect(bin, arg, env);
|
|
||||||
#endif
|
|
||||||
}else if(usepath){
|
|
||||||
execvp(bin, arg);
|
|
||||||
}else{
|
|
||||||
execv(bin, arg);
|
|
||||||
}
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}else if(ret->pid < 0){
|
|
||||||
free(ret);
|
free(ret);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -362,6 +369,17 @@ ncexecvpe(ncplane* n, const ncsubproc_options* opts, unsigned usepath,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
#else
|
||||||
|
// FIXME use CreateProcess()
|
||||||
|
(void)n;
|
||||||
|
(void)usepath;
|
||||||
|
(void)bin;
|
||||||
|
(void)arg;
|
||||||
|
(void)env;
|
||||||
|
(void)cbfxn;
|
||||||
|
(void)donecbfxn;
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ncsubproc* ncsubproc_createv(ncplane* n, const ncsubproc_options* opts,
|
ncsubproc* ncsubproc_createv(ncplane* n, const ncsubproc_options* opts,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user