httrcall: Implemented optional limiting of child processes.
authorFredrik Tolf <fredrik@dolda2000.com>
Mon, 29 Sep 2014 14:57:29 +0000 (16:57 +0200)
committerFredrik Tolf <fredrik@dolda2000.com>
Mon, 29 Sep 2014 14:57:29 +0000 (16:57 +0200)
doc/httrcall.doc
src/httrcall.c

index c4fa48e..cda8c95 100644 (file)
@@ -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 <fredrik@dolda2000.com>
index 0d7d845..c3e7e0d 100644 (file)
 #include <proc.h>
 #include <resp.h>
 
-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;