--- /dev/null
+#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;
+}
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;
}
}
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;
}
}
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;