summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server.c106
-rw-r--r--server.h1
-rw-r--r--uring.c37
-rw-r--r--uring.h5
4 files changed, 119 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);
diff --git a/server.h b/server.h
index 43c5b9e..495f7c4 100644
--- a/server.h
+++ b/server.h
@@ -52,6 +52,7 @@ struct server {
unsigned idle_timeout;
unsigned idle_count;
+ struct uring_task exec_task;
struct uring_task task;
struct list_head list;
};
diff --git a/uring.c b/uring.c
index 20d8234..9dcdcf6 100644
--- a/uring.c
+++ b/uring.c
@@ -257,6 +257,43 @@ uring_accept(struct cfg *cfg, struct uring_task *task, struct sockaddr_in46 *add
}
void
+uring_poll(struct cfg *cfg, struct uring_task *task, short poll_mask, callback_t callback)
+{
+ struct io_uring_sqe *sqe = io_uring_get_sqe(&cfg->uev->uring);
+
+ if (!sqe)
+ perrordie("io_uring_sqe");
+
+ if (task->fd < 0) {
+ error("uring_poll called with no fd set\n");
+ return;
+ }
+
+ uring_task_get(cfg, task);
+ task->callback = callback;
+ io_uring_prep_poll_add(sqe, task->fd, poll_mask);
+ io_uring_sqe_set_data(sqe, task);
+}
+
+void
+uring_poll_cancel(struct cfg *cfg, struct uring_task *task)
+{
+ struct io_uring_sqe *sqe = io_uring_get_sqe(&cfg->uev->uring);
+
+ if (!sqe)
+ perrordie("io_uring_sqe");
+
+ if (task->fd < 0) {
+ error("uring_poll_cancel called with no fd set\n");
+ return;
+ }
+
+ task->dead = true;
+ io_uring_prep_poll_remove(sqe, task);
+ io_uring_sqe_set_data(sqe, NULL);
+}
+
+void
uring_cancel(struct cfg *cfg, struct uring_task *task)
{
struct io_uring_sqe *sqe = io_uring_get_sqe(&cfg->uev->uring);
diff --git a/uring.h b/uring.h
index ff6bfb9..83119a1 100644
--- a/uring.h
+++ b/uring.h
@@ -38,6 +38,11 @@ void uring_connect(struct cfg *cfg, struct uring_task *task,
void uring_accept(struct cfg *cfg, struct uring_task *task,
struct sockaddr_in46 *addr, callback_t callback);
+void uring_poll(struct cfg *cfg, struct uring_task *task, short poll_mask,
+ callback_t callback);
+
+void uring_poll_cancel(struct cfg *cfg, struct uring_task *task);
+
void uring_cancel(struct cfg *cfg, struct uring_task *task);
void uring_refdump(struct uring_ev *uev);