summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--osdep/subprocess-posix.c47
-rw-r--r--osdep/subprocess.c27
-rw-r--r--osdep/subprocess.h2
3 files changed, 66 insertions, 10 deletions
diff --git a/osdep/subprocess-posix.c b/osdep/subprocess-posix.c
index 8165f7f641..fb11179618 100644
--- a/osdep/subprocess-posix.c
+++ b/osdep/subprocess-posix.c
@@ -17,6 +17,7 @@
#include "osdep/posix-spawn.h"
#include <poll.h>
+#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -43,7 +44,7 @@ void mp_subprocess2(struct mp_subprocess_opts *opts,
int status = -1;
int comm_pipe[MP_SUBPROCESS_MAX_FDS][2];
int devnull = -1;
- pid_t pid = -1;
+ pid_t pid = 0;
bool spawned = false;
bool killed_by_us = false;
int cancel_fd = -1;
@@ -84,11 +85,35 @@ void mp_subprocess2(struct mp_subprocess_opts *opts,
}
char **env = opts->env ? opts->env : environ;
- if (posix_spawnp(&pid, opts->exe, &fa, NULL, opts->args, env)) {
- pid = -1;
- goto done;
+
+ 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)
+ goto done;
+ if (fres == 0) {
+ // child
+ setsid();
+ if (posix_spawnp(&pid, opts->exe, &fa, NULL, opts->args, env))
+ _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;
+ spawned = true;
+ } else {
+ if (posix_spawnp(&pid, opts->exe, &fa, NULL, opts->args, env))
+ goto done;
+ spawned = true;
}
- spawned = true;
for (int n = 0; n < opts->num_fds; n++)
SAFE_CLOSE(comm_pipe[n][1]);
@@ -122,7 +147,8 @@ void mp_subprocess2(struct mp_subprocess_opts *opts,
int n = map_fds[idx];
if (n < 0) {
// cancel_fd
- kill(pid, SIGKILL);
+ if (pid)
+ kill(pid, SIGKILL);
killed_by_us = true;
break;
} else {
@@ -144,7 +170,8 @@ void mp_subprocess2(struct mp_subprocess_opts *opts,
// a separate thread and use pthread_cancel(), or use other weird
// and laborious tricks in order to react to mp_cancel.
// So this isn't handled yet.
- while (waitpid(pid, &status, 0) < 0 && errno == EINTR) {}
+ if (pid)
+ while (waitpid(pid, &status, 0) < 0 && errno == EINTR) {}
done:
if (fa_destroy)
@@ -155,10 +182,12 @@ done:
}
SAFE_CLOSE(devnull);
- if (!spawned || (WIFEXITED(status) && WEXITSTATUS(status) == 127)) {
+ if (!spawned || (pid && WIFEXITED(status) && WEXITSTATUS(status) == 127)) {
res->error = MP_SUBPROCESS_EINIT;
- } else if (WIFEXITED(status)) {
+ } else if (pid && WIFEXITED(status)) {
res->exit_status = WEXITSTATUS(status);
+ } else if (spawned && opts->detach) {
+ // ok
} else if (killed_by_us) {
res->error = MP_SUBPROCESS_EKILLED_BY_US;
} else {
diff --git a/osdep/subprocess.c b/osdep/subprocess.c
index 9da5c10c1c..8bb2acd0b7 100644
--- a/osdep/subprocess.c
+++ b/osdep/subprocess.c
@@ -65,7 +65,30 @@ int mp_subprocess(char **args, struct mp_cancel *cancel, void *ctx,
return res.exit_status;
}
-#endif
+void mp_subprocess_detached(struct mp_log *log, char **args)
+{
+ mp_msg_flush_status_line(log);
+
+ struct mp_subprocess_opts opts = {
+ .exe = args[0],
+ .args = args,
+ .fds = {
+ {.fd = 0, .src_fd = 0,},
+ {.fd = 1, .src_fd = 1,},
+ {.fd = 2, .src_fd = 2,},
+ },
+ .num_fds = 3,
+ .detach = true,
+ };
+ struct mp_subprocess_result res;
+ mp_subprocess2(&opts, &res);
+ if (res.error < 0) {
+ mp_err(log, "Starting subprocess failed: %s\n",
+ mp_subprocess_err_str(res.error));
+ }
+}
+
+#else
struct subprocess_args {
struct mp_log *log;
@@ -100,6 +123,8 @@ void mp_subprocess_detached(struct mp_log *log, char **args)
talloc_free(p);
}
+#endif
+
const char *mp_subprocess_err_str(int num)
{
// Note: these are visible to the public client API
diff --git a/osdep/subprocess.h b/osdep/subprocess.h
index 6aa2981f1d..ea9c43ba34 100644
--- a/osdep/subprocess.h
+++ b/osdep/subprocess.h
@@ -48,12 +48,14 @@ struct mp_subprocess_opts {
struct mp_subprocess_fd fds[MP_SUBPROCESS_MAX_FDS];
int num_fds;
struct mp_cancel *cancel; // if !NULL, asynchronous process abort (kills it)
+ bool detach; // if true, do not wait for process to end
};
struct mp_subprocess_result {
int error; // one of MP_SUBPROCESS_* (>0 on error)
// NB: if WIFEXITED applies, error==0, and this is WEXITSTATUS
// on win32, this can use the full 32 bit
+ // if started with detach==true, this is always 0
uint32_t exit_status; // if error==0==MP_SUBPROCESS_OK, 0 otherwise
};