httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@arctic.org>
Subject reliable piped logs
Date Mon, 07 Jul 1997 03:58:49 GMT
Ok this works, I feel dumb for looking at far more complicated solutions. 
This uses an unnamed pipe(), and the parent keeps both halves of the pipe
open.  Since the parent has the read-fd open, the children won't get EPIPE
and won't ever have a stale pipe filehandle.  The children don't ever need
to get a "new pipe" when the logger is respawned, because the logger gets
the read handle of the same pipe the children already have open.

I tested this on linux 2.0.30, solaris 2.5.1, and irix 5.3.  It really
should work everywhere since this is just posix pipe() semantics.

The test program below spawns one "httpd" child that logs a message every
second.  It spawns a logger, and then watches both of them, respawning as
necessary.  I tried a bunch of things involving suspending/killing the
logger, the parent, and so on, and couldn't really get it to fail in an
unexpected way. 

To implement this in apache we have to add a few functions to the API. 
First of all we need a method of modules/whatever telling the parent about
pids of things they've spawned, and give a callback for when that child
exits.  Then to clean things up we need to unify the logging code... which
I think someone was working on?  Randy?  I can write the first bit this
week, and if no one is cleaning up the last bit I'll do it too.

Dean

test-logger.c:

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>


static int fork_logger (int *logger_fds)
{
    int pid;
    char buf[513];
    int rc;

    pid = fork();
    if (pid == -1) {
	perror ("fork logger");
	exit (1);
    }
    if (pid) {
	printf ("%lu parent: forked logger, pid = %d\n", time(NULL), pid);
	return (pid);
    }
    /* this is the logger */
    close (logger_fds[1]);

    for(;;) {
	rc = read (logger_fds[0], buf, sizeof (buf)-1);
	if (rc > 0) {
	    buf[rc] = 0;
	    printf ("%lu logger: %s\n", time(NULL), buf);
	} else if (rc == -1) {
	    printf ("%lu logger read error: %s\n", time(NULL),
		strerror (errno));
	}
    }
    exit (0);
}


static int fork_httpd (int *logger_fds)
{
    int pid;
    char buf[513];
    int rc;
    int len;

    pid = fork();
    if (pid == -1) {
	perror ("fork httpd");
	exit (1);
    }
    if (pid) {
	printf ("%lu parent: forked httpd, pid = %d\n", time(NULL), pid);
	return (pid);
    }
    /* this is the httpd */
    close (logger_fds[0]);

    for(;;) {
	len = sprintf (buf, "hey there %lu", time(NULL));
	rc = write (logger_fds[1], buf, len);
	if (rc == -1) {
	    printf ("%lu httpd write error: %s\n", time(NULL),
		strerror (errno));
	} else if (rc < len) {
	    printf ("%lu httpd incomplete write, %d < %d: %s\n", time(NULL),
		rc, len, buf);
	} else {
	    printf ("%lu httpd wrote: %s\n", time(NULL), buf);
	}
	sleep (1);
    }
    exit (0);
}

void main( void )
{
    int logger_fds[2];
    int logger_pid;
    int httpd_pid;
    int pid;
    int status;

    if (pipe (logger_fds) == -1) {
	perror ("pipe");
	exit (1);
    }

    logger_pid = fork_logger(logger_fds);
    httpd_pid = fork_httpd(logger_fds);

    for(;;) {
	pid = wait(&status);
	if (pid == logger_pid) {
	    printf ("%lu parent: logger died, status %d, restarting\n",
		time(NULL), status);
	    logger_pid = fork_logger(logger_fds);
	} else if (pid == httpd_pid) {
	    printf ("%lu parent: httpd die, status %d, restarting\n",
		time(NULL), status);
	    httpd_pid = fork_httpd(logger_fds);
	}
    }
}




Mime
View raw message