From 547a41898e6a0420f65304f0c6e28529d067c8d4 Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Mon, 29 Sep 2014 16:57:29 +0200 Subject: [PATCH] httrcall: Implemented optional limiting of child processes. --- doc/httrcall.doc | 11 ++++++++- src/httrcall.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/doc/httrcall.doc b/doc/httrcall.doc index c4fa48e..cda8c95 100644 --- a/doc/httrcall.doc +++ b/doc/httrcall.doc @@ -7,7 +7,7 @@ httrcall - Call transient ashd handlers SYNOPSIS -------- -*httrcall* [*-h*] 'PROGRAM' ['ARGS'...] +*httrcall* [*-h*] [*-l* 'LIMIT'] 'PROGRAM' ['ARGS'...] DESCRIPTION ----------- @@ -29,6 +29,15 @@ OPTIONS Print a brief help message to standard output and exit. +*-l* 'LIMIT':: + + If specified, only 'LIMIT' copies of the handler program are + allowed to run at one time. If furter request are received + while 'LIMIT' children are running, *httrcall* will block, + waiting for one to exit before forking new ones. If no *-l* + option is specified, *httrcall* imposes no limit on the number + of children that may run. + AUTHOR ------ Fredrik Tolf diff --git a/src/httrcall.c b/src/httrcall.c index 0d7d845..c3e7e0d 100644 --- a/src/httrcall.c +++ b/src/httrcall.c @@ -33,28 +33,70 @@ #include #include -static char **prog; +struct current { + struct current *next, *prev; + pid_t pid; +}; -static void serve(struct hthead *req, int fd) -{ - if(stdforkserve(prog, req, fd, NULL, NULL) < 0) - simpleerror(fd, 500, "Server Error", "The server appears to be overloaded."); -} +static char **prog; +static struct current *running = NULL; +static int nrunning = 0, limit = 0; +static volatile int exited; -static void chldhandler(int sig) +static void checkexit(int block) { pid_t pid; int st; + struct current *rec; - while((pid = waitpid(-1, &st, WNOHANG)) > 0) { + exited = 0; + while((pid = waitpid(-1, &st, block?0:WNOHANG)) > 0) { if(WCOREDUMP(st)) flog(LOG_WARNING, "child process %i dumped core", pid); + for(rec = running; rec != NULL; rec = rec->next) { + if(rec->pid == pid) { + if(rec->next) + rec->next->prev = rec->prev; + if(rec->prev) + rec->prev->next = rec->next; + if(rec == running) + running = rec->next; + free(rec); + nrunning--; + break; + } + } } } +static void serve(struct hthead *req, int fd) +{ + pid_t new; + struct current *rec; + + while((limit > 0) && (nrunning >= limit)) + checkexit(1); + if((new = stdforkserve(prog, req, fd, NULL, NULL)) < 0) { + simpleerror(fd, 500, "Server Error", "The server appears to be overloaded."); + return; + } + omalloc(rec); + rec->pid = new; + rec->next = running; + if(running != NULL) + running->prev = rec; + running = rec; + nrunning++; +} + +static void chldhandler(int sig) +{ + exited = 1; +} + static void usage(FILE *out) { - fprintf(out, "usage: httrcall [-h] PROGRAM [ARGS...]\n"); + fprintf(out, "usage: httrcall [-h] [-l LIMIT] PROGRAM [ARGS...]\n"); } int main(int argc, char **argv) @@ -63,11 +105,14 @@ int main(int argc, char **argv) struct hthead *req; int fd; - while((c = getopt(argc, argv, "+h")) >= 0) { + while((c = getopt(argc, argv, "+hl:")) >= 0) { switch(c) { case 'h': usage(stdout); exit(0); + case 'l': + limit = atoi(optarg); + break; default: usage(stderr); exit(1); @@ -78,8 +123,12 @@ int main(int argc, char **argv) exit(1); } prog = argv + optind; - signal(SIGCHLD, chldhandler); + sigaction(SIGCHLD, &(struct sigaction) { + .sa_handler = chldhandler, + }, NULL); while(1) { + if(exited) + checkexit(0); if((fd = recvreq(0, &req)) < 0) { if(errno == EINTR) continue; -- 2.11.0