subprocess-posix: handle detach inside spawn_process
This commit is contained in:
1 parent
5fb6a76ddf
commit
de1c73a44b
1 file changed
+41
-41
+41
-41
@@ -95,8 +95,12 @@ struct child_args {
|
||||
int *src_fds;
|
||||
int pipe_end;
|
||||
bool failed;
|
||||
bool detach;
|
||||
};
|
||||
|
||||
static pid_t spawn_process_inner(const char *path, struct mp_subprocess_opts *opts,
|
||||
int src_fds[], bool detach);
|
||||
|
||||
// This function is called from a clone(CLONE_VM) context where the child
|
||||
// shares the parent's address space. Use MP_NO_ASAN to avoid false positives
|
||||
// from ASan when the child writes to shared memory.
|
||||
@@ -107,6 +111,14 @@ MP_NO_ASAN static int child_main(void* args)
|
||||
struct mp_subprocess_opts *opts = child_args->opts;
|
||||
int *src_fds = child_args->src_fds;
|
||||
int pipe_end = child_args->pipe_end;
|
||||
bool detach = child_args->detach;
|
||||
|
||||
if (detach) {
|
||||
setsid();
|
||||
if (!spawn_process_inner(path, opts, src_fds, false))
|
||||
goto child_failed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
reset_signals_child();
|
||||
|
||||
@@ -132,24 +144,19 @@ child_failed:
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Returns 0 on any error, valid PID on success.
|
||||
// This function must be async-signal-safe, as it may be called from a fork().
|
||||
static pid_t spawn_process(const char *path, struct mp_subprocess_opts *opts,
|
||||
int src_fds[])
|
||||
static pid_t spawn_process_inner(const char *path, struct mp_subprocess_opts *opts,
|
||||
int src_fds[], bool detach)
|
||||
{
|
||||
pid_t fres = 0;
|
||||
sigset_t sigmask, oldmask;
|
||||
int r = 0;
|
||||
|
||||
sigfillset(&sigmask);
|
||||
pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
|
||||
|
||||
struct child_args child_args = {
|
||||
.path = path,
|
||||
.opts = opts,
|
||||
.src_fds = src_fds,
|
||||
.pipe_end = -1,
|
||||
.failed = false,
|
||||
.detach = detach,
|
||||
};
|
||||
|
||||
int p[2] = {-1, -1};
|
||||
@@ -196,13 +203,14 @@ static pid_t spawn_process(const char *path, struct mp_subprocess_opts *opts,
|
||||
#endif
|
||||
|
||||
// If exec()ing child failed, collect it immediately.
|
||||
if (child_args.failed || r != 0) {
|
||||
while (waitpid(fres, &(int){0}, 0) < 0 && errno == EINTR) {}
|
||||
fres = 0;
|
||||
if (detach || child_args.failed || r != 0) {
|
||||
int child_status = 0;
|
||||
while (waitpid(fres, &child_status, 0) < 0 && errno == EINTR) {}
|
||||
if (r != 0 || !WIFEXITED(child_status) || WEXITSTATUS(child_status) != 0)
|
||||
fres = 0;
|
||||
}
|
||||
|
||||
done:
|
||||
pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
|
||||
#if HAVE_CLONE
|
||||
munmap(stack, stack_size);
|
||||
#endif
|
||||
@@ -212,6 +220,22 @@ done:
|
||||
return fres;
|
||||
}
|
||||
|
||||
// Returns 0 on any error, valid PID on success.
|
||||
static pid_t spawn_process(const char *path, struct mp_subprocess_opts *opts,
|
||||
int src_fds[])
|
||||
{
|
||||
sigset_t sigmask, oldmask;
|
||||
|
||||
sigfillset(&sigmask);
|
||||
pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
|
||||
|
||||
pid_t fres = spawn_process_inner(path, opts, src_fds, opts->detach);
|
||||
|
||||
pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
|
||||
|
||||
return fres;
|
||||
}
|
||||
|
||||
void mp_subprocess2(struct mp_subprocess_opts *opts,
|
||||
struct mp_subprocess_result *res)
|
||||
{
|
||||
@@ -270,35 +294,11 @@ void mp_subprocess2(struct mp_subprocess_opts *opts,
|
||||
src_fds[n] = src_fd;
|
||||
}
|
||||
|
||||
if (opts->detach) {
|
||||
// If we run it detached, we fork a child to start the process; then
|
||||
// it exits immediately, letting PID 1 inherit it. So we don't need
|
||||
// anything else to collect these child PIDs.
|
||||
sigset_t sigmask, oldmask;
|
||||
sigfillset(&sigmask);
|
||||
pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
|
||||
pid_t fres = fork();
|
||||
if (fres < 0) {
|
||||
pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
|
||||
goto done;
|
||||
}
|
||||
if (fres == 0) {
|
||||
// child
|
||||
setsid();
|
||||
if (!spawn_process(path, opts, src_fds))
|
||||
_exit(1);
|
||||
_exit(0);
|
||||
}
|
||||
pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
|
||||
int child_status = 0;
|
||||
while (waitpid(fres, &child_status, 0) < 0 && errno == EINTR) {}
|
||||
if (!WIFEXITED(child_status) || WEXITSTATUS(child_status) != 0)
|
||||
goto done;
|
||||
} else {
|
||||
pid = spawn_process(path, opts, src_fds);
|
||||
if (!pid)
|
||||
goto done;
|
||||
}
|
||||
pid = spawn_process(path, opts, src_fds);
|
||||
if (!pid)
|
||||
goto done;
|
||||
if (opts->detach)
|
||||
pid = 0;
|
||||
|
||||
spawned = true;
|
||||
|
||||
|
||||
Reference in new issue
Block a user