SYNOPSIS
--------
-*httrcall* [*-h*] 'PROGRAM' ['ARGS'...]
+*httrcall* [*-h*] [*-l* 'LIMIT'] 'PROGRAM' ['ARGS'...]
DESCRIPTION
-----------
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>
#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)
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);
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;