]> PatchyGit - patchyircd.git/commitdiff
add fork job system
authorEgor <egor@patchysicp.xyz>
Thu, 1 Feb 2024 15:11:01 +0000 (17:11 +0200)
committerEgor <egor@patchysicp.xyz>
Thu, 1 Feb 2024 15:11:01 +0000 (17:11 +0200)
Makefile
src/job.c [new file with mode: 0644]
src/job.h [new file with mode: 0644]
src/main.c
src/net.c
src/netpoll.c
src/netsock.h

index 96a3546..83f14d6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,7 @@ SOURCES := \
        src/admin.c      \
        src/irc.c        \
        src/ircfmt.c     \
+       src/job.c        \
        src/net.c        \
        src/netpoll.c    \
        src/netsock.c    \
@@ -16,6 +17,7 @@ HEADERS := \
        src/admin.h      \
        src/irc.h        \
        src/ircfmt.h     \
+       src/job.h        \
        src/net.h        \
        src/netpoll.h    \
        src/netsock.h    \
diff --git a/src/job.c b/src/job.c
new file mode 100644 (file)
index 0000000..ac2efe1
--- /dev/null
+++ b/src/job.c
@@ -0,0 +1,120 @@
+#include "common.h"
+#include "job.h"
+#ifndef _WIN32
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#endif
+
+struct jobent {
+       struct client_data *client;
+       jobproc_t job;
+       contproc_t then;
+};
+static struct jobent *jobtab;
+static int joblen = 0, jobcap = 0;
+
+#ifndef _WIN32
+static pid_t current_child = -1;
+static int current_result = 0;
+static void job_child(int signum)
+{
+       (void)signum;
+       int wstatus;
+       pid_t pid;
+       while ((pid = waitpid(-1, &wstatus, WNOHANG)) > 0) {
+               if (pid == current_child) {
+                       current_child = -1;
+                       current_result = WIFEXITED(wstatus) ? WEXITSTATUS(wstatus) : -1;
+               }
+       }
+}
+void job_init(void)
+{
+       struct sigaction sa;
+       sa.sa_handler = job_child;
+       sigemptyset(&sa.sa_mask);
+       sa.sa_flags = SA_RESTART;
+       if (sigaction(SIGCHLD, &sa, NULL) == -1)
+               perror("sigaction");
+}
+static void job_process(void)
+{
+       if (joblen && !jobtab[0].job && current_child == -1) {
+               jobtab[0].then(jobtab[0].client, current_result);
+               memmove(jobtab, jobtab+1, sizeof(struct jobent)*(joblen-1));
+               joblen--;
+       }
+       if (joblen && jobtab[0].job) {
+               pid_t pid = fork();
+               if (pid == -1)
+                       abort();
+               else if (pid == 0)
+                       _exit(jobtab[0].job(jobtab[0].client));
+               else
+                       current_child = pid;
+       }
+}
+void job_process_begin(void)
+{
+       sigset_t mask;
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGCHLD);
+       sigprocmask(SIG_BLOCK, &mask, 0);
+       job_process();
+}
+void job_process_end(void)
+{
+       job_process();
+       sigset_t mask;
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGCHLD);
+       sigprocmask(SIG_UNBLOCK, &mask, 0);
+}
+#else
+void job_init(void)
+{
+}
+void job_process_begin(void)
+{
+       struct jobent *ent = jobtab;
+       while (joblen) {
+               int res = ent->job(ent->client);
+               ent->then(ent->client, res);
+               joblen--;
+               ent++;
+       }
+}
+void job_process_end(void)
+{
+}
+#endif
+
+void job_add(struct client_data *cl, jobproc_t job, contproc_t then)
+{
+       if (!job)
+               return;
+       struct jobent ent = { cl, job, then };
+       if (joblen == jobcap) {
+               jobcap = jobcap == 0 ? 16 : jobcap * 2;
+               jobtab = realloc(jobtab, sizeof(struct jobent)*jobcap);
+               if (!jobtab)
+                       abort();
+       }
+       jobtab[joblen++] = ent;
+}
+void job_kill(struct client_data *cl)
+{
+       struct jobent *p, *q;
+       p = q = jobtab;
+#ifndef _WIN32
+       if (joblen && jobtab[0].client == cl)
+               current_child = -1;
+#endif
+       while (p < jobtab+joblen) {
+               if (p->client != cl)
+                       *q++ = *p;
+               p++;
+       }
+       joblen = q-jobtab;
+}
diff --git a/src/job.h b/src/job.h
new file mode 100644 (file)
index 0000000..688b242
--- /dev/null
+++ b/src/job.h
@@ -0,0 +1,10 @@
+#ifndef JOB_H_
+#define JOB_H_
+typedef int (*jobproc_t)(struct client_data *cl);
+typedef void (*contproc_t)(struct client_data *cl, int res);
+void job_init(void);
+void job_process_begin(void);
+void job_process_end(void);
+void job_add(struct client_data *client, jobproc_t job, contproc_t then);
+void job_kill(struct client_data *client);
+#endif
index ab74a76..e69e4cd 100644 (file)
@@ -1,6 +1,7 @@
 #include "common.h"
 #include "net.h"
 #include "irc.h"
+#include "job.h"
 #include <locale.h>
 
 static int is_running = 1;
@@ -236,6 +237,7 @@ int main(int argc, char *argv[])
 
        net_init();
        net_poll_init();
+       job_init();
 #ifdef HAS_LUA
        admin_init();
 #endif
@@ -383,13 +385,16 @@ int main(int argc, char *argv[])
                                break;
                }
 
+               job_process_begin();
                if (net_poll_begin() == -1) {
 #ifndef _WIN32
+                       job_process_end();
                        if (errno == EINTR)
                                continue;
 #endif
                        net_perror("ERROR SELECT");
                }
+               job_process_end();
                int ev;
                struct net_pollfd pfd;
                while ((ev = net_poll_get(&pfd))) {
index 10d42bd..52382ed 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -1,6 +1,7 @@
 #include "net.h"
 #include "irc.h"
 #include "ircfmt.h"
+#include "job.h"
 
 struct client_data *allocClient()
 {
@@ -40,6 +41,7 @@ void killConnection(struct client_data *cl, int byChoice)
        if (cl->dying)
                return;
        cl->dying = 1;
+       job_kill(cl);
        if (cl->peername)
                fprintf(stderr, "Client disconnected from Socket: %"PRISocket", IP: %s PORT: %d\n", cl->FD, cl->peername, cl->peerport);
        if (!byChoice && cl->nick && cl->username) {
index 86bef42..9203300 100644 (file)
@@ -58,10 +58,14 @@ int net_poll_begin(void)
        memcpy(&xwritefds, &writefds, sizeof(writefds));
 #ifdef _WIN32
        int highfd = 0;
+       int rv = select(highfd, &xreadfds, &xwritefds, 0, 0);
 #else
+       sigset_t mask;
+       sigprocmask(0, 0, &mask);
+       sigdelset(&mask, SIGCHLD);
        int highfd = nfds ? fds[nfds-1].fd+1 : 0;
+       int rv = pselect(highfd, &xreadfds, &xwritefds, 0, 0, &mask);
 #endif
-       int rv = select(highfd, &xreadfds, &xwritefds, 0, 0);
        lastptr = 0;
        return rv;
 }
@@ -110,7 +114,10 @@ void net_poll_reg_impl(int i, int ev)
 }
 int net_poll_begin(void)
 {
-       int rv = poll(pollfds, nfds, -1);
+       sigset_t mask;
+       sigprocmask(0, 0, &mask);
+       sigdelset(&mask, SIGCHLD);
+       int rv = ppoll(pollfds, nfds, 0, &mask);
        lastptr = 0;
        return rv;
 }
@@ -187,7 +194,10 @@ void net_poll_reg_impl(int i, int ev)
 }
 int net_poll_begin(void)
 {
-       int rv = epoll_wait(epollfd, events, sizeof(events)/sizeof(events[0]), -1);
+       sigset_t mask;
+       sigprocmask(0, 0, &mask);
+       sigdelset(&mask, SIGCHLD);
+       int rv = epoll_pwait(epollfd, events, sizeof(events)/sizeof(events[0]), -1, &mask);
        lastptr = 0;
        nevents = rv;
        return rv;
index 3ba7e3b..fe7834c 100644 (file)
@@ -76,6 +76,7 @@ void net_cleanup(void);
 #include <netdb.h>
 #include <fcntl.h>
 #include <poll.h>
+#include <signal.h>
 typedef int SOCKET;
 #define PRISocket "d"
 #define INVALID_SOCKET (-1)