summaryrefslogtreecommitdiff
path: root/server.c
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-10 00:27:53 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-10 00:27:53 +0200
commit3ff6ac2e782cdfe1d32240556478a2b5a3b8c057 (patch)
tree21ffa7f76ea1f65f9d37dbefb644b40983dba61f /server.c
parent09f1abfe18258807c412bce88ad459984add0cd3 (diff)
Make server stop/start exec asynchronous
Diffstat (limited to 'server.c')
-rw-r--r--server.c106
1 files changed, 76 insertions, 30 deletions
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 <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
@@ -5,7 +6,10 @@
#include <inttypes.h>
#include <sys/types.h>
#include <sys/wait.h>
-#include <unistd.h>
+#include <sched.h>
+#include <poll.h>
+#include <errno.h>
+#include <sched.h>
#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);