From 4df67a2849ee280896ed74b9ec0a7334060b0f0f Mon Sep 17 00:00:00 2001 From: Egor Date: Thu, 1 Feb 2024 17:11:01 +0200 Subject: [PATCH] add fork job system --- Makefile | 2 + src/job.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/job.h | 10 +++++ src/main.c | 5 +++ src/net.c | 2 + src/netpoll.c | 16 +++++-- src/netsock.h | 1 + 7 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 src/job.c create mode 100644 src/job.h diff --git a/Makefile b/Makefile index 96a3546..83f14d6 100644 --- 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 index 0000000..ac2efe1 --- /dev/null +++ b/src/job.c @@ -0,0 +1,120 @@ +#include "common.h" +#include "job.h" +#ifndef _WIN32 +#include +#include +#include +#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 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 diff --git a/src/main.c b/src/main.c index ab74a76..e69e4cd 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,7 @@ #include "common.h" #include "net.h" #include "irc.h" +#include "job.h" #include 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))) { diff --git a/src/net.c b/src/net.c index 10d42bd..52382ed 100644 --- 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) { diff --git a/src/netpoll.c b/src/netpoll.c index 86bef42..9203300 100644 --- a/src/netpoll.c +++ b/src/netpoll.c @@ -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; diff --git a/src/netsock.h b/src/netsock.h index 3ba7e3b..fe7834c 100644 --- a/src/netsock.h +++ b/src/netsock.h @@ -76,6 +76,7 @@ void net_cleanup(void); #include #include #include +#include typedef int SOCKET; #define PRISocket "d" #define INVALID_SOCKET (-1) -- 2.56.0