From 3ff6ac2e782cdfe1d32240556478a2b5a3b8c057 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Wed, 10 Jun 2020 00:27:53 +0200 Subject: Make server stop/start exec asynchronous --- server.c | 106 +++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 30 deletions(-) (limited to 'server.c') diff --git a/server.c b/server.c index c3bb433..7ec0804 100644 --- a/server.c +++ b/server.c @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include #include #include @@ -5,7 +6,10 @@ #include #include #include -#include +#include +#include +#include +#include #include "main.h" #include "uring.h" @@ -87,6 +91,8 @@ server_delete(struct cfg *cfg, struct server *scfg) uring_cancel(cfg, &local->task); } + uring_poll_cancel(cfg, &scfg->exec_task); + uring_task_put(cfg, &scfg->exec_task); uring_task_put(cfg, &scfg->task); } @@ -229,42 +235,81 @@ out: return false; } +static void +server_exec_free(struct uring_task *task) +{ + //struct server *scfg = container_of(task, struct server, exec_task); + + fprintf(stderr, "%s called\n", __func__); +} + +#ifndef P_PIDFD +#define P_PIDFD 3 +#endif + +static void +server_exec_done(struct cfg *cfg, struct uring_task *task, int res) +{ + struct server *scfg = container_of(task, struct server, exec_task); + int r; + siginfo_t info; + + if (task->dead) + goto out; + + if (!(res & POLLIN)) { + fprintf(stderr, "%s: unexpected result: %i\n", __func__, res); + goto out; + } + + r = waitid(P_PIDFD, scfg->exec_task.fd, &info, WEXITED); + if (r < 0) { + perror("waitid"); + goto out; + } + + fprintf(stderr, "Command executed, return value: %i\n", info.si_status); +out: + uring_task_close_fd(cfg, &scfg->exec_task); +} + +static int +server_exec_child(void *ptr) +{ + const char *cmd = ptr; + + execl(cmd, cmd, NULL); + return errno; +} + +#ifndef CLONE_PIDFD +#define CLONE_PIDFD 0x00001000 +#endif + static bool -exec_cmd(struct cfg *cfg, struct server *scfg, const char *cmd) +server_exec(struct cfg *cfg, struct server *scfg, const char *cmd) { - pid_t pid, wpid; - int wstatus; + char stack[4096]; /* Beautiful/horrible hack :) */ + int pidfd; + int r; if (!cfg || !scfg || !cmd) return false; - pid = fork(); - if (pid < 0) { - perror("fork"); + if (scfg->exec_task.fd >= 0) return false; - } else if (pid > 0) { - do { - wpid = waitpid(pid, &wstatus, 0); - if (wpid < 0) { - perror("waitpid"); - return false; - } - } while (!WIFEXITED(wstatus)); - - fprintf(stderr, "Child %s exited: %i\n", cmd, - WEXITSTATUS(wstatus)); - - if (WEXITSTATUS(wstatus) == 0) - return true; - else - return false; - - } else { - execl(cmd, cmd, NULL); - perror("execl"); - exit(EXIT_FAILURE); + r = clone(server_exec_child, stack + sizeof(stack), + CLONE_VM | CLONE_VFORK | CLONE_PIDFD | SIGCHLD, + (void *)cmd, &pidfd); + if (r < 0) { + perror("clone"); + return false; } + + uring_task_set_fd(&scfg->exec_task, pidfd); + uring_poll(cfg, &scfg->exec_task, POLLIN, server_exec_done); + return true; } bool @@ -276,7 +321,7 @@ server_start(struct cfg *cfg, struct server *scfg) switch (scfg->start_method) { case SERVER_START_METHOD_EXEC: - return exec_cmd(cfg, scfg, scfg->start_exec); + return server_exec(cfg, scfg, scfg->start_exec); case SERVER_START_METHOD_UNDEFINED: default: @@ -295,7 +340,7 @@ server_stop(struct cfg *cfg, struct server *scfg) switch (scfg->stop_method) { case SERVER_STOP_METHOD_EXEC: - return exec_cmd(cfg, scfg, scfg->stop_exec); + return server_exec(cfg, scfg, scfg->stop_exec); case SERVER_STOP_METHOD_RCON: rcon_init(cfg, scfg); @@ -558,6 +603,7 @@ server_new(struct cfg *cfg, const char *name) scfg->stop_method = SERVER_STOP_METHOD_UNDEFINED; scfg->start_method = SERVER_START_METHOD_UNDEFINED; uring_task_init(&scfg->task, "scfg", uring_parent(cfg), server_free); + uring_task_init(&scfg->exec_task, "exec", &scfg->task, server_exec_free); list_init(&scfg->remotes); list_init(&scfg->locals); list_init(&scfg->proxys); -- cgit v1.2.3