
From dgaudet@arctic.org Mon May 17 09:30:52 1999
Date: Mon, 17 May 1999 09:30:37 -0700 (PDT)
From: Dean Gaudet <dgaudet@arctic.org>
To: new-httpd@apache.org
Subject: [PATCH] select-thread-hybrid-01.patch
X-Comment: Visit http://www.arctic.org/~dgaudet/legal for information regarding copyright and disclaimer.
Reply-To: new-httpd@apache.org

http://www.arctic.org/~dgaudet/apache/2.0/select-thread-hybrid-01.patch

OK I've managed to serve a few requests with this, so it's time to post ;) 

Building: 

Get and build bind-8.x (I'm using bind-8.2).  You want the wonderful
eventlib which the ISC folks have written for us, and released under a
BSD-style license.  This is a convenient select/poll wrapper which
provides timer and fd events.  Paul's comments say he had inputs from lots
of folks -- including the X folks... so I'm guessing Jim Gettys' comments
were taken into account... and so I'm just trusting the code rather than
looking at it.

(Redhat users:  I tried using the installed bind-devel kit, but it doesn't
work, something is bogus about their library.)

Get apache-apr... apply the patch. 

Use some variant of the config.status below to configure the server. 

Notes: 

- I tore up http_main.c.  Just completely gutted it.  I got tired of
stubbing out things.  We can add things back incrementally. 

- no signals, no restart, no multiple processes... 

- no scoreboard -- major rework needed here.  We need to divorce ourselves
from the concept of a one-to-one mapping between threads/processes and
requests.  We'll have connections which are being handled by the event
loop.  I think the more appropriate thing is to split the scoreboard into
a "worker" section, and a "connection" section.  But even still -- we can
potentially have thousands of connections in progress... that's a lot of
shared memory to chew up (shared mem is not pageable on many systems).  A
better solution is required -- such as building the scoreboard only when
serving /server-status. 

- It's similar to one of manoj/ryan's older servers with the fdqueue at
the moment, but using eventlib instead... and it should show how I think
we should pass events back and forth between workers and event thread.

Dean

#!/bin/sh
##
##  config.status -- APACI auto-generated configuration restore script
##
##  Use this shell script to re-run the APACI configure script for
##  restoring your configuration. Additional parameters can be supplied.
##

CFLAGS="-g -O2 -Wall" \
LIBS="/home/dgaudet/ap/bind/src/lib/libbind_r.a" \
INCLUDES="-I/home/dgaudet/ap/bind/src/include" \
./configure \
"--with-layout=Apache" \
"--prefix=/home/dgaudet/ev" \
"--disable-module=status" \
"$@"


? out
? a
? main/a
? main/http_main_old.c
Index: include/http_conf_globals.h
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/include/http_conf_globals.h,v
retrieving revision 1.8
diff -u -r1.8 http_conf_globals.h
--- http_conf_globals.h	1999/03/15 15:34:49	1.8
+++ http_conf_globals.h	1999/05/17 16:17:15
@@ -116,6 +116,8 @@
  */
 extern char ap_coredump_dir[MAX_STRING_LEN];
 
+server_rec *server_conf; /* XXX this is shared now, prefix with ap_ */
+
 #ifdef __cplusplus
 }
 #endif
Index: include/http_event.h
===================================================================
RCS file: http_event.h
diff -N http_event.h
--- /dev/null	Mon May 17 09:17:18 1999
+++ http_event.h	Mon May 17 09:17:16 1999
@@ -0,0 +1,54 @@
+#ifndef HTTP_EVENT_H_INCLUDED
+#define HTTP_EVENT_H_INCLUDED
+
+/******************************************************************************/
+
+/* the event loop --> worker queue */
+/* XXX: generalise this */
+typedef struct workq_t workq_t;
+struct workq_t {
+    workq_t *next;
+    enum {
+	WORKQ_NEW_CONNECTION,
+	WORKQ_MAX
+    } type;
+    union {
+	struct {
+	    int fd;
+	    struct sockaddr sa_client;
+	} new_connection;
+    } d;
+};
+
+void workq_enqueue(workq_t *item);
+workq_t *workq_dequeue(void);
+
+
+/******************************************************************************/
+
+/* the worker thread --> event loop queue */
+
+typedef struct responseq_t responseq_t;
+struct responseq_t {
+    enum {
+	RESPONSEQ_GOES_HERE,
+	RESPONSEQ_MAX
+    } type;
+    union {
+	struct {
+	    int blah;
+	} fill_in_the_blank;
+    } d;
+};
+
+void responseq_enqueue(responseq_t *resp);
+responseq_t *responseq_dequeue(void);
+
+/******************************************************************************/
+
+void *ap_worker_thread(void *);
+
+void ap_event_loop(void);
+
+
+#endif
Index: include/http_main.h
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/include/http_main.h,v
retrieving revision 1.5
diff -u -r1.5 http_main.h
--- http_main.h	1999/04/09 04:10:35	1.5
+++ http_main.h	1999/05/17 16:17:16
@@ -120,8 +120,6 @@
 int ap_get_timeout(request_rec *r);
 
 API_EXPORT(void) ap_child_terminate(request_rec *r);
-int ap_update_child_status(int child_num, int thread_num, int status, request_rec *r);
-void ap_time_process_request(int child_num, int thread_num, int status);
 unsigned int ap_set_callback_and_alarm(void (*fn) (int), int x);
 API_EXPORT(int) ap_check_alarm(void);
 
Index: include/httpd.h
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/include/httpd.h,v
retrieving revision 1.14
diff -u -r1.14 httpd.h
--- httpd.h	1999/04/14 21:03:19	1.14
+++ httpd.h	1999/05/17 16:17:16
@@ -819,8 +819,6 @@
 
     /* Information about the connection itself */
 
-    int child_num;		/* The number of the child handling conn_rec */
-    int thread_num;             /* number of the thread handling conn_rec */
     BUFF *client;		/* Connection to the guy */
 
     /* Who is the client? */
@@ -1042,7 +1040,6 @@
 API_EXPORT(int) ap_can_exec(const struct stat *);
 API_EXPORT(void) ap_chdir_file(const char *file);
 API_EXPORT(int) ap_get_max_daemons(void);
-API_EXPORT(const server_rec *) ap_get_server_conf(void);
 
 #ifndef HAVE_CANONICAL_FILENAME
 /*
@@ -1152,6 +1149,10 @@
 #define BO_TIMEOUT 2
 
 #define ap_is_aborted(abort) (abort->aborted ==1)
+
+/* XXX get these working again */
+#define NO_OTHER_CHILD
+#define NO_RELIABLE_PIPED_LOGS
 
 #ifdef __cplusplus
 }
Index: include/scoreboard.h
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/include/scoreboard.h,v
retrieving revision 1.7
diff -u -r1.7 scoreboard.h
--- scoreboard.h	1999/04/09 04:10:35	1.7
+++ scoreboard.h	1999/05/17 16:17:16
@@ -209,8 +209,13 @@
 void increment_counts(int child_num, int thread_num, request_rec *r);
 void update_scoreboard_global(void);
 API_EXPORT(int) find_child_by_pid(int pid);
-int ap_update_child_status(int child_num, int thread_num, int status, request_rec *r);
-void ap_time_process_request(int child_num, int thread_num, int status);
+#if 0
+int ap_update_child_status(conn_rec *, int status, request_rec *r);
+void ap_time_process_request(conn_rec *, int status);
+#else
+#define ap_update_child_status(a,b,c) (0)
+#define ap_time_process_request(a,b) do {} while(0)
+#endif
 
 
 
Index: main/Makefile.tmpl
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/main/Makefile.tmpl,v
retrieving revision 1.8
diff -u -r1.8 Makefile.tmpl
--- Makefile.tmpl	1999/04/17 03:35:54	1.8
+++ Makefile.tmpl	1999/05/17 16:17:16
@@ -11,7 +11,7 @@
       http_config.o http_core.o http_log.o \
       http_main.o http_protocol.o http_request.o http_vhost.o \
       util.o util_date.o util_script.o util_uri.o util_md5.o \
-      scoreboard.o rfc1413.o fdqueue.o acceptlock.o http_accept.o
+      rfc1413.o http_event.o http_worker.o
 
 .c.o:
 	$(CC) -c $(INCLUDES) $(CFLAGS) $<
Index: main/http_core.c
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/main/http_core.c,v
retrieving revision 1.12
diff -u -r1.12 http_core.c
--- http_core.c	1999/04/14 21:03:28	1.12
+++ http_core.c	1999/05/17 16:17:18
@@ -595,7 +595,7 @@
 	&& conn->remote_host == NULL
 	&& (type == REMOTE_DOUBLE_REV
 	    || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
-	old_stat = ap_update_child_status(conn->child_num, conn->thread_num,
+	old_stat = ap_update_child_status(conn,
 					  SERVER_BUSY_DNS, (request_rec*)NULL);
 	/* ZZZ change to AP functions. */
 	iaddr = &(conn->remote_addr.sin_addr);
@@ -623,8 +623,7 @@
 	}
     }
     if (old_stat != SERVER_DEAD) {
-	(void)ap_update_child_status(conn->child_num, conn->thread_num,
-				     old_stat, (request_rec*)NULL);
+	(void)ap_update_child_status(conn, old_stat, (request_rec*)NULL);
     }
 
 /*
Index: main/http_event.c
===================================================================
RCS file: http_event.c
diff -N http_event.c
--- /dev/null	Mon May 17 09:17:18 1999
+++ http_event.c	Mon May 17 09:17:18 1999
@@ -0,0 +1,312 @@
+/* ====================================================================
+ * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer.  
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in 
+ *    the documentation and/or other materials provided with the 
+ *    distribution. 
+ * 
+ * 3. All advertising materials mentioning features or use of this 
+ *    software must display the following acknowledgment: 
+ *    "This product includes software developed by the Apache Group 
+ *    for use in the Apache HTTP server project (http://www.apache.org/)." 
+ * 
+ * 4. The names "Apache Server" and "Apache Group" must not be used to 
+ *    endorse or promote products derived from this software without 
+ *    prior written permission. For written permission, please contact 
+ *    apache@apache.org. 
+ * 
+ * 5. Products derived from this software may not be called "Apache" 
+ *    nor may "Apache" appear in their names without prior written 
+ *    permission of the Apache Group. 
+ * 
+ * 6. Redistributions of any form whatsoever must retain the following 
+ *    acknowledgment: 
+ *    "This product includes software developed by the Apache Group 
+ *    for use in the Apache HTTP server project (http://www.apache.org/)." 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY 
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR 
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
+ * OF THE POSSIBILITY OF SUCH DAMAGE. 
+ * ==================================================================== 
+ * 
+ * This software consists of voluntary contributions made by many 
+ * individuals on behalf of the Apache Group and was originally based 
+ * on public domain software written at the National Center for 
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign. 
+ * For more information on the Apache Group and the Apache HTTP server 
+ * project, please see <http://www.apache.org/>. 
+ * 
+ */ 
+ 
+#define CORE_PRIVATE 
+
+#include "httpd.h" 
+#include "http_event.h"
+#include "http_log.h"
+#include "http_conf_globals.h"
+
+#include <pthread.h>
+#include <isc/eventlib.h>	/* thank you ISC! */
+
+/* XXX -- do this dynamically */
+#define MAX_WORKERS 10
+static pthread_t worker_thread[MAX_WORKERS];
+
+static evContext event_context;
+static int response_queue[2];
+
+/******************************************************************************/
+
+/* the event loop --> worker queue */
+/* XXX: generalise this */
+
+static pthread_mutex_t workq_mutex;
+static pthread_cond_t workq_cond;
+static workq_t *workq_head;
+static workq_t **workq_tail;
+
+static void workq_init(void)
+{
+    pthread_mutex_init(&workq_mutex, NULL);
+    pthread_cond_init(&workq_cond, NULL);
+    workq_head = NULL;
+    workq_tail = &workq_head;
+}
+
+void workq_enqueue(workq_t *item)
+{
+    pthread_mutex_lock(&workq_mutex);
+    item->next = NULL;
+    *workq_tail = item;
+    workq_tail = &item->next;
+    pthread_cond_signal(&workq_cond);
+    pthread_mutex_unlock(&workq_mutex);
+}
+
+workq_t *workq_dequeue(void)
+{
+    workq_t *res;
+
+    pthread_mutex_lock(&workq_mutex);
+    while (workq_head == NULL) {
+	pthread_cond_wait(&workq_cond, &workq_mutex);
+    }
+    res = workq_head;
+    workq_head = res->next;
+    if (!workq_head) {
+	workq_tail = &workq_head;
+    }
+    pthread_mutex_unlock(&workq_mutex);
+    return res;
+}
+
+/******************************************************************************/
+
+/* the worker thread --> event loop queue */
+
+static int response_queue[2];
+
+static void response_event(evContext ctx, void *uap, int fd, int eventmask)
+{
+    /* no events to handle yet */
+}
+
+static void responseq_init(void)
+{
+    /* create the queue for handing responses back to the event thread */
+    if (pipe(response_queue)) {
+	ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+		    "pipe(response_queue) failed");
+	exit(1);
+    }
+    if (evSelectFD(event_context, response_queue[0], EV_READ, response_event, NULL, NULL)) {
+	ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+		    "evSelectFD(response_queue[0]) failed");
+	exit(1);
+    }
+}
+
+void responseq_enqueue(responseq_t *resp)
+{
+    int rc;
+
+    do {
+	rc = write(response_queue[1], &resp, sizeof(resp));
+    } while (rc < 0 && errno == EINTR);
+    if (rc != sizeof(resp)) {
+	/* XXX handle this more gracefully... */
+	ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+		    "response_queue write failed");
+	exit(1);
+    }
+}
+
+responseq_t *responseq_dequeue(void)
+{
+    int rc;
+    responseq_t *resp;
+
+    do {
+	rc = read(response_queue[0], &resp, sizeof(resp));
+    } while (rc < 0 && errno == EINTR);
+    if (rc < 0) {
+	if (errno == EAGAIN) {
+	    return NULL;
+	}
+	/* XXX handle this more gracefully... */
+	ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+		    "response_queue read failed");
+	exit(1);
+    }
+    else if (rc != sizeof(resp)) {
+	/* XXX handle this more gracefully... */
+	ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, server_conf,
+		    "response_queue read failed");
+	exit(1);
+    }
+    return resp;
+}
+
+/******************************************************************************/
+
+static void accept_event(evContext ctx, void *uap, int fd, int eventmask)
+{
+    int csd;
+    struct sockaddr sa_client;
+    int clen;
+
+    for (;;) {
+	clen = sizeof(sa_client);
+	csd = accept(fd, &sa_client, &clen);
+	if (csd >= 0) {
+	    workq_t *work = malloc(sizeof(workq_t));
+	    work->type = WORKQ_NEW_CONNECTION;
+	    work->d.new_connection.fd = csd;
+	    work->d.new_connection.sa_client = sa_client;
+	    workq_enqueue(work);
+	}
+	else {
+	    switch (errno) {
+	    case EAGAIN:
+	    	return;
+	    case EINTR:
+		break;
+
+	    /* Our old behaviour here was to continue after accept()
+	     * errors.  But this leads us into lots of troubles
+	     * because most of the errors are quite fatal.  For
+	     * example, EMFILE can be caused by slow descriptor
+	     * leaks (say in a 3rd party module, or libc).  It's
+	     * foolish for us to continue after an EMFILE.  We also
+	     * seem to tickle kernel bugs on some platforms which
+	     * lead to never-ending loops here.  So it seems best
+	     * to just exit in most cases.
+	     */
+#ifdef EPROTO
+		/* EPROTO on certain older kernels really means
+		 * ECONNABORTED, so we need to ignore it for them.
+		 * See discussion in new-httpd archives nh.9701
+		 * search for EPROTO.
+		 *
+		 * Also see nh.9603, search for EPROTO:
+		 * There is potentially a bug in Solaris 2.x x<6,
+		 * and other boxes that implement tcp sockets in
+		 * userland (i.e. on top of STREAMS).  On these
+		 * systems, EPROTO can actually result in a fatal
+		 * loop.  See PR#981 for example.  It's hard to
+		 * handle both uses of EPROTO.
+		 */
+	    case EPROTO:
+#endif
+#ifdef ECONNABORTED
+	    case ECONNABORTED:
+#endif
+		/* Linux generates the rest of these, other tcp
+		 * stacks (i.e. bsd) tend to hide them behind
+		 * getsockopt() interfaces.  They occur when
+		 * the net goes sour or the client disconnects
+		 * after the three-way handshake has been done
+		 * in the kernel but before userland has picked
+		 * up the socket.
+		 */
+#ifdef ECONNRESET
+	    case ECONNRESET:
+#endif
+#ifdef ETIMEDOUT
+	    case ETIMEDOUT:
+#endif
+#ifdef EHOSTUNREACH
+	    case EHOSTUNREACH:
+#endif
+#ifdef ENETUNREACH
+	    case ENETUNREACH:
+#endif
+		break;
+	    default:
+		ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
+			    "accept: (client socket)");
+		exit(1);
+	    }
+	}
+    }
+}
+
+
+/******************************************************************************/
+
+
+void ap_event_loop(void)
+{
+    int i;
+    listen_rec *lr;
+
+    if (evCreate(&event_context)) {
+	ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+		    "evCreate failed");
+	exit(1);
+    }
+
+    /* insert events for the listening sockets */
+    for (lr = ap_listeners; lr; lr = lr->next) {
+	if (evSelectFD(event_context, lr->fd, EV_READ, accept_event, lr, NULL)) {
+	    ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+			"evSelectFD failed");
+	    exit(1);
+	}
+    }
+
+    responseq_init();
+    workq_init();
+
+    /* create worker threads */
+    for (i = 0; i < MAX_WORKERS; ++i) {
+	if (pthread_create(&worker_thread[i], NULL, ap_worker_thread, NULL)) {
+	    ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+			"pthread_create: unable to create event thread");
+	    exit(1);
+	}
+    }
+
+    if (evMainLoop(event_context)) {
+	ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+		    "evMainLoop failed");
+	exit(1);
+    }
+}
Index: main/http_main.c
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/main/http_main.c,v
retrieving revision 1.79
diff -u -r1.79 http_main.c
--- http_main.c	1999/04/29 20:09:44	1.79
+++ http_main.c	1999/05/17 16:17:19
@@ -93,24 +93,17 @@
 #include "util_uri.h" 
 #include "scoreboard.h" 
 
+#if 0
 #include "http_accept.h"
 #include <poll.h> 
 #include <netinet/tcp.h> 
+#endif
+
+#include "http_event.h"
+
 #include <stdio.h> 
 
-#ifdef USE_SHMGET_SCOREBOARD
-#include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#endif
- 
 #include "pthread.h" 
-/*#include initialization if any 
-#include threadabstractionlayer; 
-#include networkiolayer 
-#include lock */ 
- 
-#include <setjmp.h> 
  
 /* This next function is never used. It is here to ensure that if we 
  * make all the modules into shared libraries that core httpd still 
@@ -123,14 +116,10 @@
     ap_add_cgi_vars(NULL); 
 }
 
-#include "explain.h"
-
 #if !defined(max)
 #define max(a,b)        (a > b ? a : b)
 #endif
 
-DEF_Explain
-
 /* Defining GPROF when compiling uses the moncontrol() function to
  * disable gprof profiling in the parent, and enable it only for
  * request processing in children (or in one_process mode).  It's
@@ -217,36 +206,9 @@
 pool *pchild;		/* Pool for httpd child stuff */
 
 
-/* thread local storage code that isn't used right now */
-
-#if 0
-/* stuff that needs thread local store in main */
-typedef struct {
-    jmp_buf thread_exit;
-    int generation;
-} tls_main_t;
-
-static pthread_key_t tls_main_key;        /* ZZZZ */
-
-static tls_main_t *gettls(pthread_key_t tls_main_key)
-{
-    tls_main_t *tls_p;
-    tls_p = pthread_getspecific(tls_main_key);
-    if (!tls_p) {
-        tls_p = NULL;
-        fprintf(stderr, "pthread_getspecific failed\n");
-    }
-
-    return tls_p;
-}
-#define tls() ((tls_main_t *) gettls(tls_main_key)) /* ZZZZZ */
-#endif
-
-
-
 /* *Non*-shared http_main globals... */
 
-static server_rec *server_conf;
+server_rec *server_conf; /* XXX this is shared now */
 static pid_t pgrp;
 
 /* one_process --- debugging mode variable; can be set from the command line
@@ -346,11 +308,6 @@
     return max_daemons_limit;
 }
 
-API_EXPORT(const server_rec *) ap_get_server_conf(void)
-{
-    return (server_conf);
-}
-
 
 /*
  * This routine adds the real server base identity to the version string,
@@ -386,12 +343,6 @@
    static void clean_child_exit(int code) __attribute__ ((noreturn)); */
 void clean_child_exit(int code)
 {
-    int child_num = find_child_by_pid(getpid());
-    int i;
-
-    for (i = 0; i < ap_threads_per_child + ap_acceptors_per_child; i++)
-        ap_update_child_status(child_num, i, SERVER_DEAD, (request_rec *) NULL);
-
     if (pchild) {
 	ap_child_exit_modules(pchild, server_conf);
 	ap_destroy_pool(pchild);
@@ -399,15 +350,10 @@
 
     exit(code);
 }
-
-static void graceful_killer(void)
-{
-    stop_accepting_connections(pconf);
-}
 
+/* XXX  huh? */
 int ap_get_timeout(request_rec *r)
 {
-
     if (r->connection->keptalive) {
         return(r->server->keep_alive_timeout);
     }
@@ -416,1035 +362,207 @@
     }
 }
 
-static void usage(char *bin)
+
+static int make_sock(pool *p, const struct sockaddr_in *server) 
+     /* abstract sockaddr_in */
 {
-    char pad[MAX_STRING_LEN];
-    unsigned i;
+    int s;
+    int one = 1;
+    char addr[512];
 
-    for (i = 0; i < strlen(bin); i++)
-	pad[i] = ' ';
-    pad[i] = '\0';
-#ifdef SHARED_CORE
-    fprintf(stderr, "Usage: %s [-R directory] [-d directory] [-f file]\n", bin);
-#else
-    fprintf(stderr, "Usage: %s [-d directory] [-f file]\n", bin);
-#endif
-    fprintf(stderr, "       %s [-C \"directive\"] [-c \"directive\"]\n", pad);
-    fprintf(stderr, "       %s [-v] [-V] [-h] [-l] [-L] [-S] [-t]\n", pad);
-    fprintf(stderr, "Options:\n");
-#ifdef SHARED_CORE
-    fprintf(stderr, "  -R directory     : specify an alternate location for shared object files\n");
+    if (server->sin_addr.s_addr != htonl(INADDR_ANY))
+	ap_snprintf(addr, sizeof(addr), "address %s port %d",
+		inet_ntoa(server->sin_addr), ntohs(server->sin_port));
+    else
+	ap_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
+
+    /* note that because we're about to slack we don't use psocket */
+    if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+	ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
+		    "make_sock: failed to get a socket for %s", addr);
+        printf("make_sock: failed to get socket for %s\n", addr);
+	exit(1);
+    }
+
+    /* Solaris (probably versions 2.4, 2.5, and 2.5.1 with various levels
+     * of tcp patches) has some really weird bugs where if you dup the
+     * socket now it breaks things across SIGHUP restarts.  It'll either
+     * be unable to bind, or it won't respond.
+     */
+#if defined (SOLARIS2) && SOLARIS2 < 260
+#define WORKAROUND_SOLARIS_BUG
 #endif
-    fprintf(stderr, "  -D name          : define a name for use in <IfDefine name> directives\n");
-    fprintf(stderr, "  -d directory     : specify an alternate initial ServerRoot\n");
-    fprintf(stderr, "  -f file          : specify an alternate ServerConfigFile\n");
-    fprintf(stderr, "  -C \"directive\"   : process directive before reading config files\n");
-    fprintf(stderr, "  -c \"directive\"   : process directive after  reading config files\n");
-    fprintf(stderr, "  -v               : show version number\n");
-    fprintf(stderr, "  -V               : show compile settings\n");
-    fprintf(stderr, "  -h               : list available command line options (this page)\n");
-    fprintf(stderr, "  -l               : list compiled-in modules\n");
-    fprintf(stderr, "  -L               : list available configuration directives\n");
-    fprintf(stderr, "  -S               : show parsed settings (currently only vhost settings)\n");
-    fprintf(stderr, "  -t               : run syntax test for configuration files only\n");
-#ifdef WIN32
-    fprintf(stderr, "  -k shutdown      : tell running Apache to shutdown\n");
-    fprintf(stderr, "  -k restart       : tell running Apache to do a graceful restart\n");
+
+    /* PR#1282 Unixware 1.x appears to have the same problem as solaris */
+#if defined (UW) && UW < 200
+#define WORKAROUND_SOLARIS_BUG
 #endif
-    exit(1);
-}
-/*
- * More machine-dependent networking gooo... on some systems,
- * you've got to be *really* sure that all the packets are acknowledged
- * before closing the connection, since the client will not be able
- * to see the last response if their TCP buffer is flushed by a RST
- * packet from us, which is what the server's TCP stack will send
- * if it receives any request data after closing the connection.
- *
- * In an ideal world, this function would be accomplished by simply
- * setting the socket option SO_LINGER and handling it within the
- * server's TCP stack while the process continues on to the next request.
- * Unfortunately, it seems that most (if not all) operating systems
- * block the server process on close() when SO_LINGER is used.
- * For those that don't, see USE_SO_LINGER below.  For the rest,
- * we have created a home-brew lingering_close.
- *
- * Many operating systems tend to block, puke, or otherwise mishandle
- * calls to shutdown only half of the connection.  You should define
- * NO_LINGCLOSE in ap_config.h if such is the case for your system.
- */
-#ifndef MAX_SECS_TO_LINGER
-#define MAX_SECS_TO_LINGER 30
+
+    /* PR#1973 NCR SVR4 systems appear to have the same problem */
+#if defined (MPRAS)
+#define WORKAROUND_SOLARIS_BUG
 #endif
 
-#ifdef USE_SO_LINGER
-#define NO_LINGCLOSE		/* The two lingering options are exclusive */
+#ifndef WORKAROUND_SOLARIS_BUG
+    s = ap_slack(s, AP_SLACK_HIGH);
 
-static void sock_enable_linger(int s) // ZZZZZ abstract the socket, s
-{
-    struct linger li;                 // ZZZZZ SocketOptions...
+    ap_note_cleanups_for_socket(p, s);	/* arrange to close on exec or restart */
+#endif
 
-    li.l_onoff = 1;
-    li.l_linger = MAX_SECS_TO_LINGER;
+#ifndef MPE
+/* MPE does not support SO_REUSEADDR and SO_KEEPALIVE */
+#ifndef _OSD_POSIX
+    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) {
+	ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
+		    "make_sock: for %s, setsockopt: (SO_REUSEADDR)", addr);
+        printf("make_sock: failed to setsockopt for %s\n", addr);
+	close(s);
+	return 0; 
+    }
+#endif /*_OSD_POSIX*/
+    one = 1;
+#ifndef BEOS
+/* BeOS does not support SO_KEEPALIVE */
+    if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(int)) < 0) {
+	ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
+		    "make_sock: for %s, setsockopt: (SO_KEEPALIVE)", addr);
+	close(s);
+	return 0;
+    }
+#endif
+#endif
 
-    if (setsockopt(s, SOL_SOCKET, SO_LINGER, // ZZZZZ abstract, return SUCCESS or not
-		   (char *) &li, sizeof(struct linger)) < 0) {
-	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
-	            "setsockopt: (SO_LINGER)");
-	/* not a fatal error */
+    /*
+     * To send data over high bandwidth-delay connections at full
+     * speed we must force the TCP window to open wide enough to keep the
+     * pipe full.  The default window size on many systems
+     * is only 4kB.  Cross-country WAN connections of 100ms
+     * at 1Mb/s are not impossible for well connected sites.
+     * If we assume 100ms cross-country latency,
+     * a 4kB buffer limits throughput to 40kB/s.
+     *
+     * To avoid this problem I've added the SendBufferSize directive
+     * to allow the web master to configure send buffer size.
+     *
+     * The trade-off of larger buffers is that more kernel memory
+     * is consumed.  YMMV, know your customers and your network!
+     *
+     * -John Heidemann <johnh@isi.edu> 25-Oct-96
+     *
+     * If no size is specified, use the kernel default.
+     */
+#ifndef BEOS			/* BeOS does not support SO_SNDBUF */
+    if (server_conf->send_buffer_size) {
+	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
+		(char *) &server_conf->send_buffer_size, sizeof(int)) < 0) {
+	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
+			"make_sock: failed to set SendBufferSize for %s, "
+			"using default", addr);
+	    /* not a fatal error */
+	}
     }
-}
+#endif
 
-#else
-#define sock_enable_linger(s)	/* NOOP */
-#endif /* USE_SO_LINGER */
+#ifdef MPE
+/* MPE requires CAP=PM and GETPRIVMODE to bind to ports less than 1024 */
+    if (ntohs(server->sin_port) < 1024)
+	GETPRIVMODE();
+#endif
+    if (bind(s, (struct sockaddr *) server, sizeof(struct sockaddr_in)) == -1) {
+	ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
+	    "make_sock: could not bind to %s", addr);
+#ifdef MPE
+	if (ntohs(server->sin_port) < 1024)
+	    GETUSERMODE();
+#endif
+	close(s);
+	exit(1);
+    }
+#ifdef MPE
+    if (ntohs(server->sin_port) < 1024)
+	GETUSERMODE();
+#endif
 
-#ifndef NO_LINGCLOSE
+    if (listen(s, ap_listenbacklog) == -1) {
+	ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
+	    "make_sock: unable to listen for connections on %s", addr);
+	close(s);
+	exit(1);
+    }
 
-/* Since many clients will abort a connection instead of closing it,
- * attempting to log an error message from this routine will only
- * confuse the webmaster.  There doesn't seem to be any portable way to
- * distinguish between a dropped connection and something that might be
- * worth logging.
- */
-/*ZZZ this routine needs to be adapted for use with poll()*/
-static void lingering_close(request_rec *r)     
-{
-  /*ZZZ remove the hardwired 512. This is an IO Buffer Size */
-    char dummybuf[512];    
-    struct pollfd pd;
-    int lsd;
-    int max_wait;
+#ifdef WORKAROUND_SOLARIS_BUG
+    s = ap_slack(s, AP_SLACK_HIGH);
 
-    /* Prevent a slow-drip client from holding us here indefinitely */
+    ap_note_cleanups_for_socket(p, s);	/* arrange to close on exec or restart */
+#endif
 
-    max_wait = 30;
-    ap_bsetopt(r->connection->client, BO_TIMEOUT, &max_wait);
+#ifndef WIN32
+    /* protect various fd_sets */
+    if (s >= FD_SETSIZE) {
+	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
+	    "make_sock: problem listening on %s, filedescriptor (%u) "
+	    "larger than FD_SETSIZE (%u) "
+	    "found, you probably need to rebuild Apache with a "
+	    "larger FD_SETSIZE", addr, s, FD_SETSIZE);
+	close(s);
+	return 0;
+    }
+#endif
 
-    /* Send any leftover data to the client, but never try to again */
+    return s;
+}
 
-    if (ap_bflush(r->connection->client) == -1) {
-	ap_bclose(r->connection->client);
-	return;
-    }
-    ap_bsetflag(r->connection->client, B_EOUT, 1);
 
-    /* Close our half of the connection --- send the client a FIN */
+/*
+ * During a restart we keep track of the old listeners here, so that we
+ * can re-use the sockets.  We have to do this because we won't be able
+ * to re-open the sockets ("Address already in use").
+ *
+ * Unlike the listeners ring, old_listeners is a NULL terminated list.
+ *
+ * copy_listeners() makes the copy, find_listener() finds an old listener
+ * and close_unused_listener() cleans up whatever wasn't used.
+ */
+static listen_rec *old_listeners;
 
-    lsd = r->connection->client->fd;
+/* unfortunately copy_listeners may be called before listeners is a ring */
+static void copy_listeners(pool *p)
+{
+    listen_rec *lr;
 
-    if ((shutdown(lsd, 1) != 0)  /* ZZZ abstract shutdown */
-        || ap_is_aborted(r->connection)) {
-	ap_bclose(r->connection->client);
+    ap_assert(old_listeners == NULL);
+    if (ap_listeners == NULL) {
 	return;
     }
-
-    /* Set up to wait for readable data on socket... */
-    pd.fd = lsd;
-    pd.events = POLLIN;
-
-    /* Wait for readable data or error condition on socket;
-     * slurp up any data that arrives...  We exit when we go for an
-     * interval of tv length without getting any more data, get an error
-     * from poll(), get an error or EOF on a read, or the timer expires.
-     */
-    /* We use a 2 second timeout because current (Feb 97) browsers
-     * fail to close a connection after the server closes it.  Thus,
-     * to avoid keeping the child busy, we are only lingering long enough
-     * for a client that is actively sending data on a connection.
-     * This should be sufficient unless the connection is massively
-     * losing packets, in which case we might have missed the RST anyway.
-     * These parameters are reset on each pass, since they might be
-     * changed by poll.
-     */
+    lr = ap_listeners;
     do {
-        pd.revents = 0;
-    } while ((poll(&pd, 1, 2) == 1)   
-             && read(lsd, dummybuf, sizeof(dummybuf)));
-      /* && (time() = epoch) < max_wait); */    /* ZZZZ time function is not good... */
-
-    /* Should now have seen final ack.  Safe to finally kill socket */
-    ap_bclose(r->connection->client);
+	listen_rec *nr = malloc(sizeof *nr);
+	if (nr == NULL) {
+	    fprintf(stderr, "Ouch!  malloc failed in copy_listeners()\n");
+	    exit(1);
+	}
+	*nr = *lr;
+	ap_kill_cleanups_for_socket(p, nr->fd);
+        nr->next = old_listeners;
+	old_listeners = nr;
+	lr = lr->next;
+    } while (lr && lr != ap_listeners);
 }
-#endif /* ndef NO_LINGCLOSE */
 
-/*****************************************************************
- * dealing with other children
- */
 
-#ifndef NO_OTHER_CHILD
-API_EXPORT(void) ap_register_other_child(int pid,
-		       void (*maintenance) (int reason, void *, ap_wait_t status),
-			  void *data, int write_fd)
-{
-    other_child_rec *ocr;
-
-    ocr = ap_palloc(pconf, sizeof(*ocr));
-    ocr->pid = pid;
-    ocr->maintenance = maintenance;
-    ocr->data = data;
-    ocr->write_fd = write_fd;
-    ocr->next = other_children;
-    other_children = ocr;
-}
-
-/* note that since this can be called by a maintenance function while we're
- * scanning the other_children list, all scanners should protect themself
- * by loading ocr->next before calling any maintenance function.
- */
-API_EXPORT(void) ap_unregister_other_child(void *data)
+static int find_listener(listen_rec *lr)
 {
-    other_child_rec **pocr, *nocr;
-
-    for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) {
-	if ((*pocr)->data == data) {
-	    nocr = (*pocr)->next;
-	    (*(*pocr)->maintenance) (OC_REASON_UNREGISTER, (*pocr)->data, -1);
-	    *pocr = nocr;
-	    /* XXX: um, well we've just wasted some space in pconf ? */
-	    return;
+    listen_rec *or;
+    for (or = old_listeners; or; or = or->next) {
+	if (!memcmp(&or->local_addr, &lr->local_addr, sizeof(or->local_addr))) {
+	    or->used = 1;+            return or->fd;
 	}
     }
+    return -1;
 }
 
-/* test to ensure that the write_fds are all still writable, otherwise
- * invoke the maintenance functions as appropriate */
-static void probe_writable_fds(void)
-{
-    return;
-#if 0
-    fd_set writable_fds;
-    int fd_max;
-    other_child_rec *ocr, *nocr;
-    struct timeval tv;
-    int rc;
 
-    if (other_children == NULL)
-	return;
-
-    fd_max = 0;
-    FD_ZERO(&writable_fds);
-    do {
-	for (ocr = other_children; ocr; ocr = ocr->next) {
-	    if (ocr->write_fd == -1)
-		continue;
-	    FD_SET(ocr->write_fd, &writable_fds);
-	    if (ocr->write_fd > fd_max) {
-		fd_max = ocr->write_fd;
-	    }
-	}
-	if (fd_max == 0)
-	    return;
-
-	tv.tv_sec = 0;
-	tv.tv_usec = 0;
-	rc = ap_select(fd_max + 1, NULL, &writable_fds, NULL, &tv);
-    } while (rc == -1 && errno == EINTR);
-
-    if (rc == -1) {
-	/* XXX: uhh this could be really bad, we could have a bad file
-	 * descriptor due to a bug in one of the maintenance routines */
-	ap_log_unixerr("probe_writable_fds", "select",
-		    "could not probe writable fds", server_conf);
-	return;
-    }
-    if (rc == 0)
-	return;
-
-    for (ocr = other_children; ocr; ocr = nocr) {
-	nocr = ocr->next;
-	if (ocr->write_fd == -1)
-	    continue;
-	if (FD_ISSET(ocr->write_fd, &writable_fds))
-	    continue;
-	(*ocr->maintenance) (OC_REASON_UNWRITABLE, ocr->data, -1);
-    }
-#endif
-}
-
-/* possibly reap an other_child, return 0 if yes, -1 if not */
-static int reap_other_child(int pid, ap_wait_t status)
-{
-    other_child_rec *ocr, *nocr;
-
-    for (ocr = other_children; ocr; ocr = nocr) {
-	nocr = ocr->next;
-	if (ocr->pid != pid)
-	    continue;
-	ocr->pid = -1;
-	(*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
-	return 0;
-    }
-    return -1;
-}
-#endif
-
-static void reclaim_child_processes(int terminate)
-{
-    int i, status;
-    long int waittime = 1024 * 16;	/* in usecs */
-    struct timeval tv;
-    int waitret, tries;
-    int not_dead_yet;
-#ifndef NO_OTHER_CHILD
-    other_child_rec *ocr, *nocr;
-#endif
-
-    ap_sync_scoreboard_image();
-
-    for (tries = terminate ? 4 : 1; tries <= 9; ++tries) {
-	/* don't want to hold up progress any more than 
-	 * necessary, but we need to allow children a few moments to exit.
-	 * Set delay with an exponential backoff.
-	 */
-	tv.tv_sec = waittime / 1000000;
-	tv.tv_usec = waittime % 1000000;
-	waittime = waittime * 4;
-	ap_select(0, NULL, NULL, NULL, &tv);
-
-	/* now see who is done */
-	not_dead_yet = 0;
-	for (i = 0; i < max_daemons_limit; ++i) {
-	    int pid = ap_scoreboard_image->parent[i].pid;
-
-	    if (pid == my_pid || pid == 0)
-		continue;
-
-	    waitret = waitpid(pid, &status, WNOHANG);
-	    if (waitret == pid || waitret == -1) {
-		ap_scoreboard_image->parent[i].pid = 0;
-		continue;
-	    }
-	    ++not_dead_yet;
-	    switch (tries) {
-	    case 1:     /*  16ms */
-	    case 2:     /*  82ms */
-		break;
-	    case 3:     /* 344ms */
-	    case 4:     /*  16ms */
-	    case 5:     /*  82ms */
-	    case 6:     /* 344ms */
-	    case 7:     /* 1.4sec */
-		/* ok, now it's being annoying */
-		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
-			    server_conf,
-		   "child process %d still did not exit, sending a SIGTERM",
-			    pid);
-		kill(pid, SIGTERM);
-		break;
-	    case 8:     /*  6 sec */
-		/* die child scum */
-		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
-		   "child process %d still did not exit, sending a SIGKILL",
-			    pid);
-		kill(pid, SIGKILL);
-		break;
-	    case 9:     /* 14 sec */
-		/* gave it our best shot, but alas...  If this really 
-		 * is a child we are trying to kill and it really hasn't
-		 * exited, we will likely fail to bind to the port
-		 * after the restart.
-		 */
-		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
-			    "could not make child process %d exit, "
-			    "attempting to continue anyway", pid);
-		break;
-	    }
-	}
-#ifndef NO_OTHER_CHILD
-	for (ocr = other_children; ocr; ocr = nocr) {
-	    nocr = ocr->next;
-	    if (ocr->pid == -1)
-		continue;
-
-	    waitret = waitpid(ocr->pid, &status, WNOHANG);
-	    if (waitret == ocr->pid) {
-		ocr->pid = -1;
-		(*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
-	    }
-	    else if (waitret == 0) {
-		(*ocr->maintenance) (OC_REASON_RESTART, ocr->data, -1);
-		++not_dead_yet;
-	    }
-	    else if (waitret == -1) {
-		/* uh what the heck? they didn't call unregister? */
-		ocr->pid = -1;
-		(*ocr->maintenance) (OC_REASON_LOST, ocr->data, -1);
-	    }
-	}
-#endif
-	if (!not_dead_yet) {
-	    /* nothing left to wait for */
-	    break;
-	}
-    }
-}
-
-/* Finally, this routine is used by the caretaker process to wait for
- * a while...
- */
-
-/* number of calls to wait_or_timeout between writable probes */
-#ifndef INTERVAL_OF_WRITABLE_PROBES
-#define INTERVAL_OF_WRITABLE_PROBES 10
-#endif
-static int wait_or_timeout_counter;
-
-static int wait_or_timeout(ap_wait_t *status)
-{
-    struct timeval tv;
-    int ret;
-
-    ++wait_or_timeout_counter;
-    if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
-	wait_or_timeout_counter = 0;
-#ifndef NO_OTHER_CHILD
-	probe_writable_fds();
-#endif
-    }
-    ret = waitpid(-1, status, WNOHANG);
-    if (ret == -1 && errno == EINTR) {
-	return -1;
-    }
-    if (ret > 0) {
-	return ret;
-    }
-#ifdef NEED_WAITPID
-    if ((ret = reap_children(status)) > 0) {
-	return ret;
-    }
-#endif
-    tv.tv_sec = SCOREBOARD_MAINTENANCE_INTERVAL / 1000000;
-    tv.tv_usec = SCOREBOARD_MAINTENANCE_INTERVAL % 1000000;
-    ap_select(0, NULL, NULL, NULL, &tv);
-    return -1;
-}
-
-#if defined(NSIG)
-#define NumSIG NSIG
-#elif defined(_NSIG)
-#define NumSIG _NSIG
-#elif defined(__NSIG)
-#define NumSIG __NSIG
-#else
-#define NumSIG 32   /* for 1998's unixes, this is still a good assumption */
-#endif
-
-#ifdef SYS_SIGLIST /* platform has sys_siglist[] */
-#define INIT_SIGLIST()  /*nothing*/
-#else /* platform has no sys_siglist[], define our own */
-#define SYS_SIGLIST ap_sys_siglist
-#define INIT_SIGLIST() siglist_init();
-
-const char *ap_sys_siglist[NumSIG];
-
-static void siglist_init(void)
-{
-    int sig;
-
-    ap_sys_siglist[0] = "Signal 0";
-#ifdef SIGHUP
-    ap_sys_siglist[SIGHUP] = "Hangup";
-#endif
-#ifdef SIGINT
-    ap_sys_siglist[SIGINT] = "Interrupt";
-#endif
-#ifdef SIGQUIT
-    ap_sys_siglist[SIGQUIT] = "Quit";
-#endif
-#ifdef SIGILL
-    ap_sys_siglist[SIGILL] = "Illegal instruction";
-#endif
-#ifdef SIGTRAP
-    ap_sys_siglist[SIGTRAP] = "Trace/BPT trap";
-#endif
-#ifdef SIGIOT
-    ap_sys_siglist[SIGIOT] = "IOT instruction";
-#endif
-#ifdef SIGABRT
-    ap_sys_siglist[SIGABRT] = "Abort";
-#endif
-#ifdef SIGEMT
-    ap_sys_siglist[SIGEMT] = "Emulator trap";
-#endif
-#ifdef SIGFPE
-    ap_sys_siglist[SIGFPE] = "Arithmetic exception";
-#endif
-#ifdef SIGKILL
-    ap_sys_siglist[SIGKILL] = "Killed";
-#endif
-#ifdef SIGBUS
-    ap_sys_siglist[SIGBUS] = "Bus error";
-#endif
-#ifdef SIGSEGV
-    ap_sys_siglist[SIGSEGV] = "Segmentation fault";
-#endif
-#ifdef SIGSYS
-    ap_sys_siglist[SIGSYS] = "Bad system call";
-#endif
-#ifdef SIGPIPE
-    ap_sys_siglist[SIGPIPE] = "Broken pipe";
-#endif
-#ifdef SIGALRM
-    ap_sys_siglist[SIGALRM] = "Alarm clock";
-#endif
-#ifdef SIGTERM
-    ap_sys_siglist[SIGTERM] = "Terminated";
-#endif
-#ifdef SIGUSR1
-    ap_sys_siglist[SIGUSR1] = "User defined signal 1";
-#endif
-#ifdef SIGUSR2
-    ap_sys_siglist[SIGUSR2] = "User defined signal 2";
-#endif
-#ifdef SIGCLD
-    ap_sys_siglist[SIGCLD] = "Child status change";
-#endif
-#ifdef SIGCHLD
-    ap_sys_siglist[SIGCHLD] = "Child status change";
-#endif
-#ifdef SIGPWR
-    ap_sys_siglist[SIGPWR] = "Power-fail restart";
-#endif
-#ifdef SIGWINCH
-    ap_sys_siglist[SIGWINCH] = "Window changed";
-#endif
-#ifdef SIGURG
-    ap_sys_siglist[SIGURG] = "urgent socket condition";
-#endif
-#ifdef SIGPOLL
-    ap_sys_siglist[SIGPOLL] = "Pollable event occurred";
-#endif
-#ifdef SIGIO
-    ap_sys_siglist[SIGIO] = "socket I/O possible";
-#endif
-#ifdef SIGSTOP
-    ap_sys_siglist[SIGSTOP] = "Stopped (signal)";
-#endif
-#ifdef SIGTSTP
-    ap_sys_siglist[SIGTSTP] = "Stopped";
-#endif
-#ifdef SIGCONT
-    ap_sys_siglist[SIGCONT] = "Continued";
-#endif
-#ifdef SIGTTIN
-    ap_sys_siglist[SIGTTIN] = "Stopped (tty input)";
-#endif
-#ifdef SIGTTOU
-    ap_sys_siglist[SIGTTOU] = "Stopped (tty output)";
-#endif
-#ifdef SIGVTALRM
-    ap_sys_siglist[SIGVTALRM] = "virtual timer expired";
-#endif
-#ifdef SIGPROF
-    ap_sys_siglist[SIGPROF] = "profiling timer expired";
-#endif
-#ifdef SIGXCPU
-    ap_sys_siglist[SIGXCPU] = "exceeded cpu limit";
-#endif
-#ifdef SIGXFSZ
-    ap_sys_siglist[SIGXFSZ] = "exceeded file size limit";
-#endif
-    for (sig=0; sig < sizeof(ap_sys_siglist)/sizeof(ap_sys_siglist[0]); ++sig)
-        if (ap_sys_siglist[sig] == NULL)
-            ap_sys_siglist[sig] = "";
-}
-#endif /* platform has sys_siglist[] */
-
-/* handle all varieties of core dumping signals */
-static void sig_coredump(int sig)
-{
-    chdir(ap_coredump_dir);
-    signal(sig, SIG_DFL);
-#ifndef WIN32
-    kill(getpid(), sig);
-#else
-    raise(sig);
-#endif
-    /* At this point we've got sig blocked, because we're still inside
-     * the signal handler.  When we leave the signal handler it will
-     * be unblocked, and we'll take the signal... and coredump or whatever
-     * is appropriate for this particular Unix.  In addition the parent
-     * will see the real signal we received -- whereas if we called
-     * abort() here, the parent would only see SIGABRT.
-     */
-}
-
-/*****************************************************************
- * Connection structures and accounting...
- */
-
-/* XXX - alarms will need to be blockable at some point */
-
-static int alarms_blocked = 0;
-static int exit_after_unblock = 0;
-static void just_die(int sig)
-{				/* SIGHUP to child process??? */
-    /* if alarms are blocked we have to wait to die otherwise we might
-     * end up with corruption in alloc.c's internal structures */
-    if (alarms_blocked) {
-	exit_after_unblock = 1;
-    }
-    else {
-	clean_child_exit(0);
-    }
-}
-
-static void graceful_sig_handler(int sig)
-{
-    ap_max_requests_per_child = 1;
-}
-
-/*****************************************************************
- * Connection structures and accounting...
- */
-
-/* volatile just in case */
-static int volatile shutdown_pending;
-static int volatile restart_pending;
-static int volatile is_graceful;
-ap_generation_t volatile ap_my_generation;
-
-/*
- * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
- * functions to initiate shutdown or restart without relying on signals. 
- * Previously this was initiated in sig_term() and restart() signal handlers, 
- * but we want to be able to start a shutdown/restart from other sources --
- * e.g. on Win32, from the service manager. Now the service manager can
- * call ap_start_shutdown() or ap_start_restart() as appropiate.  Note that
- * these functions can also be called by the child processes, since global
- * variables are no longer used to pass on the required action to the parent.
- *
- * These should only be called from the parent process itself, since the
- * parent process will use the shutdown_pending and restart_pending variables
- * to determine whether to shutdown or restart. The child process should
- * call signal_parent() directly to tell the parent to die -- this will
- * cause neither of those variable to be set, which the parent will
- * assume means something serious is wrong (which it will be, for the
- * child to force an exit) and so do an exit anyway.
- */
-
-void ap_start_shutdown(void)
-{
-    if (shutdown_pending == 1) {
-	/* Um, is this _probably_ not an error, if the user has
-	 * tried to do a shutdown twice quickly, so we won't
-	 * worry about reporting it.
-	 */
-	return;
-    }
-    shutdown_pending = 1;
-}
-
-/* do a graceful restart if graceful == 1 */
-void ap_start_restart(int graceful)
-{
-
-    if (restart_pending == 1) {
-	/* Probably not an error - don't bother reporting it */
-	return;
-    }
-    restart_pending = 1;
-    is_graceful = graceful;
-}
-
-static void sig_term(int sig)
-{
-    ap_start_shutdown();
-}
-
-static void restart(int sig)
-{
-#ifndef WIN32
-    ap_start_restart(sig == SIGWINCH);
-#else
-    ap_start_restart(1);
-#endif
-}
-
-static void set_signals(void)
-{
-#ifndef NO_USE_SIGACTION
-    struct sigaction sa;
-
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = 0;
-
-    if (!one_process) {
-	sa.sa_handler = sig_coredump;
-#if defined(SA_ONESHOT)
-	sa.sa_flags = SA_ONESHOT;
-#elif defined(SA_RESETHAND)
-	sa.sa_flags = SA_RESETHAND;
-#endif
-	if (sigaction(SIGSEGV, &sa, NULL) < 0)
-	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGSEGV)");
-#ifdef SIGBUS
-	if (sigaction(SIGBUS, &sa, NULL) < 0)
-	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGBUS)");
-#endif
-#ifdef SIGABORT
-	if (sigaction(SIGABORT, &sa, NULL) < 0)
-	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABORT)");
-#endif
-#ifdef SIGABRT
-	if (sigaction(SIGABRT, &sa, NULL) < 0)
-	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABRT)");
-#endif
-#ifdef SIGILL
-	if (sigaction(SIGILL, &sa, NULL) < 0)
-	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGILL)");
-#endif
-	sa.sa_flags = 0;
-    }
-    sa.sa_handler = sig_term;
-    if (sigaction(SIGTERM, &sa, NULL) < 0)
-	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGTERM)");
-#ifdef SIGINT
-    if (sigaction(SIGINT, &sa, NULL) < 0)
-        ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGINT)");
-#endif
-#ifdef SIGXCPU
-    sa.sa_handler = SIG_DFL;
-    if (sigaction(SIGXCPU, &sa, NULL) < 0)
-	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXCPU)");
-#endif
-#ifdef SIGXFSZ
-    sa.sa_handler = SIG_DFL;
-    if (sigaction(SIGXFSZ, &sa, NULL) < 0)
-	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXFSZ)");
-#endif
-#ifdef SIGPIPE
-    sa.sa_handler = SIG_IGN;
-    if (sigaction(SIGPIPE, &sa, NULL) < 0)
-	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGPIPE)");
-#endif
-
-    /* we want to ignore HUPs and WINCH while we're busy processing one */
-    sigaddset(&sa.sa_mask, SIGHUP);
-    sigaddset(&sa.sa_mask, SIGWINCH);
-    sa.sa_handler = restart;
-    if (sigaction(SIGHUP, &sa, NULL) < 0)
-	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGHUP)");
-    if (sigaction(SIGWINCH, &sa, NULL) < 0)
-	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGWINCH)");
-#else
-    if (!one_process) {
-	signal(SIGSEGV, sig_coredump);
-#ifdef SIGBUS
-	signal(SIGBUS, sig_coredump);
-#endif /* SIGBUS */
-#ifdef SIGABORT
-	signal(SIGABORT, sig_coredump);
-#endif /* SIGABORT */
-#ifdef SIGABRT
-	signal(SIGABRT, sig_coredump);
-#endif /* SIGABRT */
-#ifdef SIGILL
-	signal(SIGILL, sig_coredump);
-#endif /* SIGILL */
-#ifdef SIGXCPU
-	signal(SIGXCPU, SIG_DFL);
-#endif /* SIGXCPU */
-#ifdef SIGXFSZ
-	signal(SIGXFSZ, SIG_DFL);
-#endif /* SIGXFSZ */
-    }
-
-    signal(SIGTERM, sig_term);
-#ifdef SIGHUP
-    signal(SIGHUP, restart);
-#endif /* SIGHUP */
-#ifdef SIGWINCH
-    signal(SIGWINCH, restart);
-#endif /* SIGWINCH */
-#ifdef SIGPIPE
-    signal(SIGPIPE, SIG_IGN);
-#endif /* SIGPIPE */
-
-#endif
-}
-
-/*****************************************************************
- * Here follows a long bunch of generic server bookkeeping stuff...
- */
-
-/* check to see if we have the 'suexec' setuid wrapper installed */
-static int init_suexec(void)
-{
-/* XXX: how to do suexec test? */
-#if 0
-    struct stat wrapper;
-
-    if ((stat(SUEXEC_BIN, &wrapper)) != 0)
-	return (ap_suexec_enabled);
-
-    if ((wrapper.st_mode & S_ISUID) && wrapper.st_uid == 0) {
-	ap_suexec_enabled = 1;
-    }
-
-    return (ap_suexec_enabled);
-#else
-    return 0;
-#endif
-}
-
-/*****************************************************************
- * Connection structures and accounting...
- */
-
-
-static conn_rec *new_connection(pool *p, server_rec *server, BUFF *inout,
-                                const struct sockaddr_in *remaddr,   /* ZZZ */
-                                const struct sockaddr_in *saddr,     /* ZZZ */
-			     int c-{
-    conn_rec *conn = (conn_rec *) ap_pcalloc(p, sizeof(conn_rec));
-
-    /* Got a connection structure, so initialize what fields we can
-     * (the rest are zeroed out by pcalloc).
-     */
-
-    conn->child_num = child_num;
-    conn->thread_num = thread_num;
-
-    conn->pool = p;
-    conn->local_addr = *saddr;
-    conn->server = server; /* just a guess for now */
-    ap_update_vhost_given_ip(conn);
-    conn->base_server = conn->server;
-    conn->client = inout;
-
-    conn->remote_addr = *remaddr;
-    conn->remote_ip = ap_pstrdup(conn->pool,
-			      inet_ntoa(conn->remote_addr.sin_addr));
-
-    return conn;
-}
-
-static void sock_disable_nagle(int s) /* ZZZ abstract */
-{
-    /* The Nagle algorithm says that we should delay sending partial
-     * packets in hopes of getting more data.  We don't want to do
-     * this; we are not telnet.  There are bad interactions between
-     * persistent connections and Nagle's algorithm that have very severe
-     * performance penalties.  (Failing to disable Nagle is not much of a
-     * problem with simple HTTP.)
-     *
-     * In spite of these problems, failure here is not a shooting offense.
-     */
-    int just_say_no = 1;
-
-    if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &just_say_no,
-		   sizeof(int)) < 0) {
-	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
-		    "setsockopt: (TCP_NODELAY)");
-    }
-}
-
-static int make_sock(pool *p, const struct sockaddr_in *server) 
-     /* abstract sockaddr_in */
-{
-    int s;
-    int one = 1;
-    char addr[512];
-
-    if (server->sin_addr.s_addr != htonl(INADDR_ANY))
-	ap_snprintf(addr, sizeof(addr), "address %s port %d",
-		inet_ntoa(server->sin_addr), ntohs(server->sin_port));
-    else
-	ap_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
-
-    /* note that because we're about to slack we don't use psocket */
-    if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
-	ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
-		    "make_sock: failed to get a socket for %s", addr);
-        printf("make_sock: failed to get socket for %s\n", addr);
-	exit(1);
-    }
-
-    /* Solaris (probably versions 2.4, 2.5, and 2.5.1 with various levels
-     * of tcp patches) has some really weird bugs where if you dup the
-     * socket now it breaks things across SIGHUP restarts.  It'll either
-     * be unable to bind, or it won't respond.
-     */
-#if defined (SOLARIS2) && SOLARIS2 < 260
-#define WORKAROUND_SOLARIS_BUG
-#endif
-
-    /* PR#1282 Unixware 1.x appears to have the same problem as solaris */
-#if defined (UW) && UW < 200
-#define WORKAROUND_SOLARIS_BUG
-#endif
-
-    /* PR#1973 NCR SVR4 systems appear to have the same problem */
-#if defined (MPRAS)
-#define WORKAROUND_SOLARIS_BUG
-#endif
-
-#ifndef WORKAROUND_SOLARIS_BUG
-    s = ap_slack(s, AP_SLACK_HIGH);
-
-    ap_note_cleanups_for_socket(p, s);	/* arrange to close on exec or restart */
-#endif
-
-#ifndef MPE
-/* MPE does not support SO_REUSEADDR and SO_KEEPALIVE */
-#ifndef _OSD_POSIX
-    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) {
-	ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
-		    "make_sock: for %s, setsockopt: (SO_REUSEADDR)", addr);
-        printf("make_sock: failed to setsockopt for %s\n", addr);
-	close(s);
-	return 0; 
-    }
-#endif /*_OSD_POSIX*/
-    one = 1;
-#ifndef BEOS
-/* BeOS does not support SO_KEEPALIVE */
-    if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(int)) < 0) {
-	ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
-		    "make_sock: for %s, setsockopt: (SO_KEEPALIVE)", addr);
-	close(s);
-	return 0;
-    }
-#endif
-#endif
-
-    sock_disable_nagle(s);
-    sock_enable_linger(s);
-
-    /*
-     * To send data over high bandwidth-delay connections at full
-     * speed we must force the TCP window to open wide enough to keep the
-     * pipe full.  The default window size on many systems
-     * is only 4kB.  Cross-country WAN connections of 100ms
-     * at 1Mb/s are not impossible for well connected sites.
-     * If we assume 100ms cross-country latency,
-     * a 4kB buffer limits throughput to 40kB/s.
-     *
-     * To avoid this problem I've added the SendBufferSize directive
-     * to allow the web master to configure send buffer size.
-     *
-     * The trade-off of larger buffers is that more kernel memory
-     * is consumed.  YMMV, know your customers and your network!
-     *
-     * -John Heidemann <johnh@isi.edu> 25-Oct-96
-     *
-     * If no size is specified, use the kernel default.
-     */
-#ifndef BEOS			/* BeOS does not support SO_SNDBUF */
-    if (server_conf->send_buffer_size) {
-	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
-		(char *) &server_conf->send_buffer_size, sizeof(int)) < 0) {
-	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
-			"make_sock: failed to set SendBufferSize for %s, "
-			"using default", addr);
-	    /* not a fatal error */
-	}
-    }
-#endif
-
-#ifdef MPE
-/* MPE requires CAP=PM and GETPRIVMODE to bind to ports less than 1024 */
-    if (ntohs(server->sin_port) < 1024)
-	GETPRIVMODE();
-#endif
-    if (bind(s, (struct sockaddr *) server, sizeof(struct sockaddr_in)) == -1) {
-	ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
-	    "make_sock: could not bind to %s", addr);
-#ifdef MPE
-	if (ntohs(server->sin_port) < 1024)
-	    GETUSERMODE();
-#endif
-	close(s);
-	exit(1);
-    }
-#ifdef MPE
-    if (ntohs(server->sin_port) < 1024)
-	GETUSERMODE();
-#endif
-
-    if (listen(s, ap_listenbacklog) == -1) {
-	ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
-	    "make_sock: unable to listen for connections on %s", addr);
-	close(s);
-	exit(1);
-    }
-
-#ifdef WORKAROUND_SOLARIS_BUG
-    s = ap_slack(s, AP_SLACK_HIGH);
-
-    ap_note_cleanups_for_socket(p, s);	/* arrange to close on exec or restart */
-#endif
-
-#ifndef WIN32
-    /* protect various fd_sets */
-    if (s >= FD_SETSIZE) {
-	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
-	    "make_sock: problem listening on %s, filedescriptor (%u) "
-	    "larger than FD_SETSIZE (%u) "
-	    "found, you probably need to rebuild Apache with a "
-	    "larger FD_SETSIZE", addr, s, FD_SETSIZE);
-	close(s);
-	return 0;
-    }
-#endif
-
-    return s;
-}
-
-
-/*
- * During a restart we keep track of the old listeners here, so that we
- * can re-use the sockets.  We have to do this because we won't be able
- * to re-open the sockets ("Address already in use").
- *
- * Unlike the listeners ring, old_listeners is a NULL terminated list.
- *
- * copy_listeners() makes the copy, find_listener() finds an old listener
- * and close_unused_listener() cleans up whatever wasn't used.
- */
-static listen_rec *old_listeners;
-
-/* unfortunately copy_listeners may be called before listeners is a ring */
-static void copy_listeners(pool *p)
-{
-    listen_rec *lr;
-
-    ap_assert(old_listeners == NULL);
-    if (ap_listeners == NULL) {
-	return;
-    }
-    lr = ap_listeners;
-    do {
-	listen_rec *nr = malloc(sizeof *nr);
-	if (nr == NULL) {
-	    fprintf(stderr, "Ouch!  malloc failed in copy_listeners()\n");
-	    exit(1);
-	}
-	*nr = *lr;
-	ap_kill_cleanups_for_socket(p, nr->fd);
-        nr->next = old_listeners;
-	old_listeners = nr;
-	lr = lr->next;
-    } while (lr && lr != ap_listeners);
-}
-
-
-static int find_listener(listen_rec *lr)
-{
-    listen_rec *or;
-    for (or = old_listeners; or; or = or->next) {
-	if (!memcmp(&or->local_addr, &lr->local_addr, sizeof(or->local_addr))) {
-	    or->used = 1;
-            return or->fd;
-	}
-    }
-    return -1;
-}
-
-
 static void close_unused_listeners(void)
 {
     listen_rec *or, *next;
@@ -1501,132 +619,6 @@
 }
 
 
-static void show_compile_settings(void)
-{
-    printf("Server version: %s\n", ap_get_server_version());
-    printf("Server built:   %s\n", ap_get_server_built());
-    printf("Server's Module Magic Number: %u:%u\n",
-	   MODULE_MAGIC_NUMBER_MAJOR, MODULE_MAGIC_NUMBER_MINOR);
-    printf("Server compiled with....\n");
-#ifdef BIG_SECURITY_HOLE
-    printf(" -D BIG_SECURITY_HOLE\n");
-#endif
-#ifdef SECURITY_HOLE_PASS_AUTHORIZATION
-    printf(" -D SECURITY_HOLE_PASS_AUTHORIZATION\n");
-#endif
-#ifdef HAVE_MMAP
-    printf(" -D HAVE_MMAP\n");
-#endif
-#ifdef HAVE_SHMGET
-    printf(" -D HAVE_SHMGET\n");
-#endif
-#ifdef USE_MMAP_SCOREBOARD
-    printf(" -D USE_MMAP_SCOREBOARD\n");
-#endif
-#ifdef USE_SHMGET_SCOREBOARD
-    printf(" -D USE_SHMGET_SCOREBOARD\n");
-#endif
-#ifdef USE_OS2_SCOREBOARD
-    printf(" -D USE_OS2_SCOREBOARD\n");
-#endif
-#ifdef USE_POSIX_SCOREBOARD
-    printf(" -D USE_POSIX_SCOREBOARD\n");
-#endif
-#ifdef USE_MMAP_FILES
-    printf(" -D USE_MMAP_FILES\n");
-#ifdef MMAP_SEGMENT_SIZE
-	printf(" -D MMAP_SEGMENT_SIZE=%ld\n",(long)MMAP_SEGMENT_SIZE);
-#endif
-#endif /*USE_MMAP_FILES*/
-#ifdef NO_WRITEV
-    printf(" -D NO_WRITEV\n");
-#endif
-#ifdef NO_LINGCLOSE
-    printf(" -D NO_LINGCLOSE\n");
-#endif
-#ifdef USE_FCNTL_SERIALIZED_ACCEPT
-    printf(" -D USE_FCNTL_SERIALIZED_ACCEPT\n");
-#endif
-#ifdef USE_FLOCK_SERIALIZED_ACCEPT
-    printf(" -D USE_FLOCK_SERIALIZED_ACCEPT\n");
-#endif
-#ifdef USE_USLOCK_SERIALIZED_ACCEPT
-    printf(" -D USE_USLOCK_SERIALIZED_ACCEPT\n");
-#endif
-#ifdef USE_SYSVSEM_SERIALIZED_ACCEPT
-    printf(" -D USE_SYSVSEM_SERIALIZED_ACCEPT\n");
-#endif
-#ifdef USE_PTHREAD_SERIALIZED_ACCEPT
-    printf(" -D USE_PTHREAD_SERIALIZED_ACCEPT\n");
-#endif
-#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
-    printf(" -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT\n");
-#endif
-#ifdef NO_OTHER_CHILD
-    printf(" -D NO_OTHER_CHILD\n");
-#endif
-#ifdef NO_RELIABLE_PIPED_LOGS
-    printf(" -D NO_RELIABLE_PIPED_LOGS\n");
-#endif
-#ifdef BUFFERED_LOGS
-    printf(" -D BUFFERED_LOGS\n");
-#ifdef PIPE_BUF
-	printf(" -D PIPE_BUF=%ld\n",(long)PIPE_BUF);
-#endif
-#endif
-#ifdef MULTITHREAD
-    printf(" -D MULTITHREAD\n");
-#endif
-#ifdef CHARSET_EBCDIC
-    printf(" -D CHARSET_EBCDIC\n");
-#endif
-#ifdef NEED_HASHBANG_EMUL
-    printf(" -D NEED_HASHBANG_EMUL\n");
-#endif
-#ifdef SHARED_CORE
-    printf(" -D SHARED_CORE\n");
-#endif
-
-/* This list displays the compiled-in default paths: */
-#ifdef HTTPD_ROOT
-    printf(" -D HTTPD_ROOT=\"" HTTPD_ROOT "\"\n");
-#endif
-#ifdef SUEXEC_BIN
-    printf(" -D SUEXEC_BIN=\"" SUEXEC_BIN "\"\n");
-#endif
-#ifdef SHARED_CORE_DIR
-    printf(" -D SHARED_CORE_DIR=\"" SHARED_CORE_DIR "\"\n");
-#endif
-#ifdef DEFAULT_PIDLOG
-    printf(" -D DEFAULT_PIDLOG=\"" DEFAULT_PIDLOG "\"\n");
-#endif
-#ifdef DEFAULT_SCOREBOARD
-    printf(" -D DEFAULT_SCOREBOARD=\"" DEFAULT_SCOREBOARD "\"\n");
-#endif
-#ifdef DEFAULT_LOCKFILE
-    printf(" -D DEFAULT_LOCKFILE=\"" DEFAULT_LOCKFILE "\"\n");
-#endif
-#ifdef DEFAULT_XFERLOG
-    printf(" -D DEFAULT_XFERLOG=\"" DEFAULT_XFERLOG "\"\n");
-#endif
-#ifdef DEFAULT_ERRORLOG
-    printf(" -D DEFAULT_ERRORLOG=\"" DEFAULT_ERRORLOG "\"\n");
-#endif
-#ifdef TYPES_CONFIG_FILE
-    printf(" -D TYPES_CONFIG_FILE=\"" TYPES_CONFIG_FILE "\"\n");
-#endif
-#ifdef SERVER_CONFIG_FILE
-    printf(" -D SERVER_CONFIG_FILE=\"" SERVER_CONFIG_FILE "\"\n");
-#endif
-#ifdef ACCESS_CONFIG_FILE
-    printf(" -D ACCESS_CONFIG_FILE=\"" ACCESS_CONFIG_FILE "\"\n");
-#endif
-#ifdef RESOURCE_CONFIG_FILE
-    printf(" -D RESOURCE_CONFIG_FILE=\"" RESOURCE_CONFIG_FILE "\"\n");
-#endif
-}
-
-
 /* Some init code that's common between win32 and unix... well actually
  * some of it is #ifdef'd but was duplicated before anyhow.  This stuff
  * is still a mess.
@@ -1649,119 +641,7 @@
     ap_server_post_read_config = ap_make_array(pcommands, 1, sizeof(char *));
 }
 
-/*****************************************************************
- * Child process main loop.
- */
-
-static void process_socket(pool *p, struct sockaddr *sa_client, int csd, int my_child_num, int my_thread_num)
-{
-    struct sockaddr sa_server; /* ZZZZ */
-    size_t len = sizeof(struct sockaddr);
-    BUFF *conn_io;
-    request_rec *r;
-    conn_rec *current_conn;
-
-    ap_note_cleanups_for_fd(p, csd);
-
-    /* ZZZ change to AP func */
-    if (getsockname(csd, &sa_server, &len) < 0) { 
-	ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "getsockname");
-	return;
-    }
-    (void) ap_update_child_status(my_child_num, my_thread_num,  
-				  SERVER_BUSY_READ, (request_rec *) NULL);
-    conn_io = ap_bcreate(p, B_RDWR | B_SOCKET);
-    ap_bpushfd(conn_io, csd, csd);
-
-    current_conn = new_connection(p, server_conf, conn_io,
-                                  (const struct sockaddr_in *) sa_client, 
-                                  (const struct sockaddr_in *) &sa_server, 
-                                  my_child_num, my_thread_num);
-
-    /*
-     * Read and process each request found on our connection
-     * until no requests are left or we decide to close.
-     */
-
-
-    while ((r = ap_read_request(current_conn)) != NULL) {
-	(void) ap_update_child_status(my_child_num, my_thread_num,
-				      SERVER_BUSY_WRITE, r);
-	if (r->status == HTTP_OK)
-	    ap_process_request(r);
-	if (ap_extended_status)
-	    increment_counts(my_child_num, my_thread_num, r);
-	if (!current_conn->keepalive || ap_is_aborted(current_conn))
-	    break;
-	ap_destroy_pool(r->pool);
-	(void) ap_update_child_status(my_child_num, my_thread_num, 
-				      SERVER_BUSY_KEEPALIVE, 
-				      (request_rec *) NULL);
-#if 0
-	if (ap_scoreboard_image->global.exit_generation > t->generation) {
-	    ap_bclose(conn_io);
-	    fprintf((stderr,"%d child_main: generation maxed\n",my_child_num));
-	    clean_child_exit(0);
-	}
-#endif
-    }
-
-    /*
-     * Close the connection, being careful to send out whatever is still
-     * in our buffers.  If possible, try to avoid a hard close until the
-     * client has ACKed our FIN and/or has stopped sending us data.
-     */
-
-#ifdef NO_LINGCLOSE
-    ap_bclose(conn_io);	/* just close it */
-#else
-    if (r && r->connection
-	&& !ap_is_aborted(r->connection)
-	&& r->connection->client
-	&& (r->connection->client->fd >= 0)) {
-
-	lingering_close(r);
-    }
-    else {
-	ap_bsetflag(conn_io, B_EOUT, 1);
-	ap_bclose(conn_io);
-    }
-#endif
-}
-
-
-static void * worker_thread(void * dummy)
-{
-    proc_info * ti = dummy;
-    int process_slot = ti->pid;
-    int thread_slot = ti->tid;
-    pool *tpool = ti->tpool;
-    struct sockaddr sa_client;
-    int csd;
-    pool *ptrans;		/* Pool for per-transaction stuff */
-
-    free(ti);
-
-    ptrans = ap_make_sub_pool(tpool);
 
-    while (1) {
-        (void) ap_update_child_status(process_slot, thread_slot, SERVER_READY, 
-				  (request_rec *) NULL);
-        csd = get_connection(&sa_client);
-	if (csd < 0) {
-            break;
-        } 
-        process_socket(ptrans, &sa_client, csd, process_slot, thread_slot);
-	ap_clear_pool(ptrans);
-    }
-
-    ap_destroy_pool(tpool);
-    kill(ap_scoreboard_image->parent[process_slot].pid, SIGWINCH);
-    ap_update_child_status(process_slot, thread_slot, SERVER_DEAD,
-        (request_rec *) NULL);
-    return NULL;
-}
-
 /*****************************************************************
  * Here follows a long bunch of generic server bookkeeping stuff...
  */
@@ -1879,414 +759,53 @@
 			"setgid: unable to set group id to Group %u",
 			(unsigned)ap_group_id);
 	    clean_child_exit(APEXIT_CHILDFATAL);
-	}
-#endif
-    }
-#endif /* ndef WIN32 */
-}
-
-static void child_main(int child_num_arg)
-{
-    sigset_t sig_mask;
-    int signal_received;
-    pthread_t thread;
-    int i, j;
-    int my_child_num = child_num_arg;
-    proc_info *my_info = NULL;
-
-    my_pid = getpid();
-    pchild = ap_make_sub_pool(pconf);
-
-    /*stuff to do before we switch id's, so we have permissions.*/
-    reopen_scoreboard(pchild);
-
-    accept_child_init(pchild, ap_threads_per_child);
-
-    set_group_privs();
-
-    if (!geteuid() && (setuid(ap_user_id) == -1)) {
-        ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
-		     "setuid: unable to change uid");
-	clean_child_exit(APEXIT_CHILDFATAL);
-    }
-
-    ap_child_init_modules(pchild, server_conf);
-
-    /*done with init critical section */
-
-    /* All threads should mask signals out, accoring to sigwait(2) man page */
-    sigemptyset(&sig_mask);
-
-    if (pthread_sigmask(SIG_SETMASK, &sig_mask, NULL) != 0) {
-        ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, "pthread_sigmask");
-    }
-
-    /* Setup worker threads */
- -
-        my_info = NULL;
-	
-	my_info = (proc_info *)malloc(sizeof(proc_info));
-	my_info->pid = my_child_num;
-        my_info->tid = i;
-	my_info->sd = 0;
-	my_info->tpool = ap_make_sub_pool(pchild);
-	
-	/* We are creating threads right now */
-	(void) ap_update_child_status(my_child_num, i, SERVER_STARTING, 
-				      (request_rec *) NULL);
-	if (pthread_create(&thread, NULL, worker_thread, my_info)) {
-	    ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
-			 "pthread_create: unable to create worker thread");
-	    /* 
-	     * We failed to create a thread.  Update the scoreboard,  
-	     * or it will say SERVER_STARTING forever.
-	     */
-	    (void) ap_update_child_status(my_child_num, i, SERVER_DEAD, 
-					  (request_rec *) NULL);
-	    exit(1);   /* We won't always exit here, but for no this is okay */
-	}
-
-	/* We let each thread update it's own scoreboard entry.  This is done
-	 * because it let's us deal with tid better.
-	 */
-    }
-
-    start_accepting_connections(my_child_num);
-
-    /* This thread will be the one responsible for handling signals */
-    sigemptyset(&sig_mask);
-    sigaddset(&sig_mask, SIGWINCH);
-    sigaddset(&sig_mask, SIGTERM);
-    sigaddset(&sig_mask, SIGINT);
-    sigwait(&sig_mask, &signal_received);
-    /* XXX - Do the appropriate thing for each signal */
-    switch (signal_received) {
-        case SIGWINCH:
-       	    graceful_sig_handler(SIGWINCH);
-  	    for (j = 0; j < ap_threads_per_child + ap_acceptors_per_child; 
-		 j++) { 
-                /* Useful for debugging */
-                if (ap_scoreboard_image->servers[child_num_arg][j].status != SERVER_DEAD) {
-                    ap_scoreboard_image->servers[child_num_arg][j].status = SERVER_GRACEFUL;
-                }
-	    } 
-            graceful_killer();
-            clean_child_exit(0);
-    	    break;
-        case SIGTERM:
-            just_die(SIGTERM);
-    	    break;
-        case SIGINT:
-            just_die(SIGINT);
-            break;
-        default:
-            ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
-    	   "received strange signal: %d", signal_received);
-
-    }
-}
-
-static int make_child(server_rec *s, int slot, time_t now) /* ZZZ */
-{
-    int pid;
-
-    if (ap_acceptors_per_child + ap_threads_per_child  > HARD_THREAD_LIMIT) {
-        ap_log_error(APLOG_MARK, APLOG_ERR, s,
-		     "Worker threads plus acceptor threads is greater than HARD_THREAD_LIMIT, please correct");
-	exit(-1);
-    }
-
-
-    if (slot + 1 > max_daemons_limit) {
-	max_daemons_limit = slot + 1;
-    }
-
-    if (one_process) {
-	set_signals();
-	/* Needed even in the one process case because lookup of the process
-	 * pid sometimes must go through the scoreboard */
-        ap_scoreboard_image->parent[slot].pid = getpid();
-	child_main(slot);
-    }
-
-    Explain1("Starting new child in slot %d",slot);
-    if ((pid = fork()) == -1) {
-        ap_log_error(APLOG_MARK, APLOG_ERR, s, "fork: Unable to fork new process");
-        
-	/* fork didn't succeed. Fix the scoreboard or else
-	 * it will say SERVER_STARTING forever and ever
-	 */
-	/* (void) ap_update_child_status(slot, SERVER_DEAD, (request_rec *) NULL);    
-           We never put SERVER_STARTING in scoreboard */
-	/* In case system resources are maxxed out, we don't want
-	   Apache running away with the CPU trying to fork over and
-	   over and over again. */
-	sleep(10);
-
-	return -1;
-    }
-
-    if (!pid) {
-#ifdef AIX_BIND_PROCESSOR
-      /* By default, AIX binds to a single processor.  This bit unbinds
-	 children which will then bind to another CPU.
-      */
-#include <sys/processor.h>
-        int status = bindprocessor(BINDPROCESS, (int)getpid(),
-			       PROCESSOR_CLASS_ANY);
-	if (status != OK)
-	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, server_conf,
-			 "processor unbind failed %d", status);
-#endif
-
-        RAISE_SIGSTOP(MAKE_CHILD);
-        MONCONTROL(1);
-
-	/*
-        signal(SIGWINCH, graceful_sig_handler);
-        signal(SIGTERM, just_die);
-	*/
-        child_main(slot);
-
-	return 0;
+	}
+#endif
     }
-    /* else */
-    ap_scoreboard_image->parent[slot].pid = pid;
-    return 0;
+#endif /* ndef WIN32 */
 }
 
-/* start up a bunch of children */
-static void startup_children(int number_to_start)
+static void child_main(void)
 {
-    int i;
+    sigset_t sig_mask;
 
-    for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
-	if (ap_scoreboard_image->parent[i].pid != 0) {
-	    continue;
-	}
-	if (make_child(server_conf, i, 0) < 0) {
-	    break;
-	}
-	--number_to_start;
+    my_pid = getpid();
+    pchild = ap_make_sub_pool(pconf);
+
+    set_group_privs();
+
+    if (!geteuid() && (setuid(ap_user_id) == -1)) {
+        ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+		     "setuid: unable to change uid");
+	clean_child_exit(APEXIT_CHILDFATAL);
     }
-}
 
+    ap_child_init_modules(pchild, server_conf);
 
-/*
- * idle_spawn_rate is the number of children that will be spawned on the
- * next maintenance cycle if there aren't enough idle servers.  It is
- * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
- * without the need to spawn.
- */
-static int idle_spawn_rate = 1;
-#ifndef MAX_SPAWN_RATE
-#define MAX_SPAWN_RATE	(32)
-#endif
-static int hold_off_on_exponential_spawning;
-
-static void perform_idle_server_maintenance(void)
-{
-    int i, j;
-    int to_kill;
-    int idle_count, idle_thread_count;
-    thread_score *ss;
-    time_t now = 0;
-    int free_length;
-    int free_slots[MAX_SPAWN_RATE];
-    int last_non_dead;
-    int total_non_dead;
-
-    /* initialize the free_list */
-    free_length = 0;
-
-    to_kill = -1;
-    idle_count = 0;
-    last_non_dead = -1;
-    total_non_dead = 0;
-
-    ap_sync_scoreboard_image();
-    for (i = 0; i < ap_daemons_limit; ++i) {
-	/* Initialization to satisfy the compiler. It doesn't know
-	 * that ap_threads_per_child is always > 0 */
-	int status = SERVER_DEAD;
-	int any_dying_threads = 0;
-	int all_dead_threads = 1;
+    /*done with init critical section */
 
-	idle_thread_count = 0;
-	if (i >= max_daemons_limit && free_length == idle_spawn_rate)
-	    break;
-	for (j = 0; j < ap_threads_per_child; j++) {
-            ss = &ap_scoreboard_image->servers[i][j];
-	    status = ss->status;
-
-	    any_dying_threads = any_dying_threads || (status == SERVER_DEAD)
-                                    || (status == SERVER_GRACEFUL);
-	    all_dead_threads = all_dead_threads && (status == SERVER_DEAD);
-
-	    /* We consider a starting server as idle because we started it
-	     * at least a cycle ago, and if it still hasn't finished starting
-	     * then we're just going to swamp things worse by forking more.
-	     * So we hopefully won't need to fork more if we count it.
-	     * This depends on the ordering of SERVER_READY and SERVER_STARTING.
-	     */
-	    if (status <= SERVER_READY) {
-	        ++ idle_thread_count;
-                /* always kill the highest numbered child if we have to...
-                 * no really well thought out reason ... other than observing
-                 * the server behaviour under linux where lower numbered
-                 * children tend to service more hits (and hence are more
-                 * likely to have their data in cpu caches).
-		 */
-	    }
-	}
-	if (all_dead_threads && free_length < idle_spawn_rate) {
-	    free_slots[free_length] = i;
-	    ++free_length;
-	}
-	if (!all_dead_threads) {
-	    max_daemons_limit = i + 1;
-	}
-        if (!any_dying_threads) {
-            ++total_non_dead;
-            last_non_dead = i;
-    
-            if (idle_thread_count > ap_idle_thread_threshold) {
-                idle_count++;
-                to_kill = i;
-            }
-        }
-    }
-    if (idle_count > ap_daemons_max_free) {
-        /* kill off one child... we use SIGWINCH because that'll cause it to
-	 * shut down gracefully, in case it happened to pick up a request
-	 * while we were counting
-	 */
-        kill(ap_scoreboard_image->parent[to_kill].pid, SIGWINCH);
-        idle_spawn_rate = 1;
-    }
-    else if (idle_count < ap_daemons_min_free) {
-        /* terminate the free list */
-        if (free_length == 0) {
-	    /* only report this condition once */
-	    static int reported = 0;
-	    
-	    if (!reported) {
-	        ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
-			     "server reached MaxClients setting, consider"
-			     " raising the MaxClients setting");
-		reported = 1;
-	    }
-	    idle_spawn_rate = 1;
-	}
-	else {
-	    /* ZZZZ */
-	    
-	    if (idle_spawn_rate >= 8) {
-	        ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
-			     "server seems busy, (you may need "
-			     "to increase StartServers, or Min/MaxSpareServers), "
-			     "spawning %d children, there are %d idle, and "
-			     "%d total children", idle_spawn_rate,
-			     idle_count, total_non_dead);
-	    }
-	    for (i = 0; i < free_length; ++i) {
-	        make_child(server_conf, free_slots[i], now);
-	    }
-	    /* the next time around we want to spawn twice as many if this
-	     * wasn't good enough, but not if we've just done a graceful
-	     */
-	    if (hold_off_on_exponential_spawning) {
-	        --hold_off_on_exponential_spawning;
-	    }
-	    else if (idle_spawn_rate < MAX_SPAWN_RATE) {
-	        idle_spawn_rate *= 2;
-	    }
-	}
-    }
-    else {
-      idle_spawn_rate = 1;
+    /* All threads should mask signals out, accoring to sigwait(2) man page */
+    sigemptyset(&sig_mask);
+
+    if (pthread_sigmask(SIG_SETMASK, &sig_mask, NULL) != 0) {
+        ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, "pthread_sigmask");
     }
+
+    ap_event_loop();
 }
 
 
+
 /*****************************************************************
  * Executive routines.
  */
 
-static void server_main_loop(int remaining_children_to_start)
-{
-    int child_slot;
-    ap_wait_t status;
-    int pid;
-    int i;
-
-    while (!restart_pending && !shutdown_pending) {
-        pid = wait_or_timeout(&status);
-        
-        if (pid >= 0) {
-            child_slot = find_child_by_pid(pid);
-            if (child_slot >= 0) {
-                for (i = 0; i < ap_threads_per_child + ap_acceptors_per_child; i++)
-                    ap_update_child_status(child_slot, i, SERVER_DEAD, (request_rec *) NULL);
-                
-		if (remaining_children_to_start
-		    && child_slot < ap_daemons_limit) {
-		    /* we're still doing a 1-for-1 replacement of dead
-                     * children with new children
-                     */
-                    /* ZZZ abstract out for AP funcs. */
-		    make_child(server_conf, child_slot, time(NULL));
-		    --remaining_children_to_start;
-		}
-#ifndef NO_OTHER_CHILD
-	    }
-	    else if (reap_other_child(pid, status) == 0) {
-		/* handled */
-#endif
-	    }
-	    else if (is_graceful) {
-		/* Great, we've probably just lost a slot in the
-		    * scoreboard.  Somehow we don't know about this
-		    * child.
-		    */
-		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, server_conf,
-			    "long lost child came home! (pid %d)", pid);
-	    }
-	    /* Don't perform idle maintenance when a child dies,
-             * only do it when there's a timeout.  Remember only a
-             * finite number of children can die, and it's pretty
-             * pathological for a lot to die suddenly.
-             */
-	    continue;
-	}
-	else if (remaining_children_to_start) {
-	    /* we hit a 1 second timeout in which none of the previous
-	     * generation of children needed to be reaped... so assume
-	     * they're all done, and pick up the slack if any is left.
-	     */
-	    startup_children(remaining_children_to_start);
-	    remaining_children_to_start = 0;
-	    /* In any event we really shouldn't do the code below because
-	     * few of the servers we just started are in the IDLE state
-	     * yet, so we'd mistakenly create an extra server.
-	     */
-	    continue;
-	}
-
-	perform_idle_server_maintenance();
-    }
-}
-
 static void one_config_cycle(void)
 {
-    int remaining_children_to_start;
     int listener_count;
 
     copy_listeners(pconf);
-    if (!is_graceful) {
-        ap_restart_time = time(NULL); /* ZZZZZ */
-    }
+    ap_restart_time = time(NULL); /* ZZZZZ */
     ap_clear_pool(pconf);
     ptemp = ap_make_sub_pool(pconf);
     server_conf = ap_read_config(pconf, ptemp, ap_server_confname);
@@ -2296,152 +815,192 @@
     ap_set_version();
     ap_init_modules(pconf, server_conf);
     version_locked++;
-    accept_parent_init(pconf, listener_count);
-    if (!is_graceful) {
-	reinit_scoreboard(pconf);
-    }
 
-    set_signals();
     /* set up get_socket */
 
-    if (ap_daemons_max_free < ap_daemons_min_free + 1)	/* Don't thrash... */
-	ap_daemons_max_free = ap_daemons_min_free + 1;
-
-    /* If we're doing a graceful_restart then we're going to see a lot
-     * of children exiting immediately when we get into the main loop
-     * below (because we just sent them SIGWINCH).  This happens pretty
-     * rapidly... and for each one that exits we'll start a new one until
-     * we reach at least daemons_min_free.  But we may be permitted to
-     * start more than that, so we'll just keep track of how many we're
-     * supposed to start up without the 1 second penalty between each fork.
-     */
-    remaining_children_to_start = ap_daemons_to_start;
-    if (remaining_children_to_start > ap_daemons_limit) {
-	remaining_children_to_start = ap_daemons_limit;
-    }
-    if (!is_graceful) {
-	startup_children(remaining_children_to_start);
-	remaining_children_to_start = 0;
-    }
-    else {
-	/* give the system some time to recover before kicking into
-	    * exponential mode */
-	hold_off_on_exponential_spawning = 10;
-    }
-
     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
 		"%s configured -- resuming normal operations",
 		ap_get_server_version());
     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
 		"Server built: %s", ap_get_server_built());
-    restart_pending = shutdown_pending = 0;
 
     /* XXX: we child_init once per process... */
     ap_child_init_modules(pconf, server_conf);
 
-    server_main_loop(remaining_children_to_start);
+    child_main();
+}
 
-    if (shutdown_pending) {
-        /* Time to gracefully shut down:
-         * Kill child processes, tell them to call child_exit, etc...
-         */
-        if (ap_killpg(pgrp, SIGTERM) < 0) {
-            ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGTERM");
-        }
-        reclaim_child_processes(1);		/* Start with SIGTERM */
-    
-        /* cleanup pid file on normal shutdown */
-        {
-            const char *pidfile = NULL;
-            pidfile = ap_server_root_relative (pconf, ap_pid_fname);
-            if ( pidfile != NULL && unlink(pidfile) == 0)
-                ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,
-            		 server_conf,
-            		 "removed PID file %s (pid=%ld)",
-            		 pidfile, (long)getpid());
-        }
-    
-        ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
-            "caught SIGTERM, shutting down");
-    
-        clean_parent_exit(0);
-    }
+static void standalone_main(int argc, char **argv)
+{
+    ap_standalone = 1;
 
-    /* we've been told to restart */
-    signal(SIGHUP, SIG_IGN);
+    one_config_cycle();
 
-    if (one_process) {
-	/* not worth thinking about */
-	clean_parent_exit(0);
-    }
+}
 
-	/* advance to the next generation */
-	/* XXX: we really need to make sure this new generation number isn't in
-	 * use by any of the children.
-	 */
-	++ap_my_generation;
-	ap_scoreboard_image->global.running_generation = ap_my_generation;
-	update_scoreboard_global();
-
-    if (is_graceful) {
-	int i, j;
-
-	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
-		    "SIGWINCH received.  Doing graceful restart");
-
-	/* kill off the idle ones */
-	if (ap_killpg(pgrp, SIGWINCH) < 0) {
-	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGWINCH");
-	}
 
-	/* This is mostly for debugging... so that we know what is still
-	    * gracefully dealing with existing request.
-	    */
-	
-	for (i = 0; i < ap_daemons_limit; ++i) {
-  	    for (j = 0; j < ap_threads_pe-		 j++) { 
-	        if (ap_scoreboard_image->servers[i][j].status != SERVER_DEAD) {
-		    ap_scoreboard_image->servers[i][j].status = SERVER_GRACEFUL;
-		}
-	    } 
-	}
-    }
-    else {
-      /* Kill 'em all.  Since the child acts the same on the parents SIGTERM 
-       * and a SIGHUP, we may as well use the same signal, because some user
-       * pthreads are stealing signals from us left and right.
-       */
-	if (ap_killpg(pgrp, SIGTERM) < 0) {
-	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGTERM");
-	}
-        reclaim_child_processes(1);		/* Start with SIGTERM */
-	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
-		    "SIGHUP received.  Attempting to restart");
-    }
+static void show_compile_settings(void)
+{
+    printf("Server version: %s\n", ap_get_server_version());
+    printf("Server built:   %s\n", ap_get_server_built());
+    printf("Server's Module Magic Number: %u:%u\n",
+	   MODULE_MAGIC_NUMBER_MAJOR, MODULE_MAGIC_NUMBER_MINOR);
+    printf("Server compiled with....\n");
+#ifdef BIG_SECURITY_HOLE
+    printf(" -D BIG_SECURITY_HOLE\n");
+#endif
+#ifdef SECURITY_HOLE_PASS_AUTHORIZATION
+    printf(" -D SECURITY_HOLE_PASS_AUTHORIZATION\n");
+#endif
+#ifdef HAVE_MMAP
+    printf(" -D HAVE_MMAP\n");
+#endif
+#ifdef HAVE_SHMGET
+    printf(" -D HAVE_SHMGET\n");
+#endif
+#ifdef USE_MMAP_SCOREBOARD
+    printf(" -D USE_MMAP_SCOREBOARD\n");
+#endif
+#ifdef USE_SHMGET_SCOREBOARD
+    printf(" -D USE_SHMGET_SCOREBOARD\n");
+#endif
+#ifdef USE_OS2_SCOREBOARD
+    printf(" -D USE_OS2_SCOREBOARD\n");
+#endif
+#ifdef USE_POSIX_SCOREBOARD
+    printf(" -D USE_POSIX_SCOREBOARD\n");
+#endif
+#ifdef USE_MMAP_FILES
+    printf(" -D USE_MMAP_FILES\n");
+#ifdef MMAP_SEGMENT_SIZE
+	printf(" -D MMAP_SEGMENT_SIZE=%ld\n",(long)MMAP_SEGMENT_SIZE);
+#endif
+#endif /*USE_MMAP_FILES*/
+#ifdef NO_WRITEV
+    printf(" -D NO_WRITEV\n");
+#endif
+#ifdef NO_LINGCLOSE
+    printf(" -D NO_LINGCLOSE\n");
+#endif
+#ifdef USE_FCNTL_SERIALIZED_ACCEPT
+    printf(" -D USE_FCNTL_SERIALIZED_ACCEPT\n");
+#endif
+#ifdef USE_FLOCK_SERIALIZED_ACCEPT
+    printf(" -D USE_FLOCK_SERIALIZED_ACCEPT\n");
+#endif
+#ifdef USE_USLOCK_SERIALIZED_ACCEPT
+    printf(" -D USE_USLOCK_SERIALIZED_ACCEPT\n");
+#endif
+#ifdef USE_SYSVSEM_SERIALIZED_ACCEPT
+    printf(" -D USE_SYSVSEM_SERIALIZED_ACCEPT\n");
+#endif
+#ifdef USE_PTHREAD_SERIALIZED_ACCEPT
+    printf(" -D USE_PTHREAD_SERIALIZED_ACCEPT\n");
+#endif
+#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
+    printf(" -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT\n");
+#endif
+#ifdef NO_OTHER_CHILD
+    printf(" -D NO_OTHER_CHILD\n");
+#endif
+#ifdef NO_RELIABLE_PIPED_LOGS
+    printf(" -D NO_RELIABLE_PIPED_LOGS\n");
+#endif
+#ifdef BUFFERED_LOGS
+    printf(" -D BUFFERED_LOGS\n");
+#ifdef PIPE_BUF
+	printf(" -D PIPE_BUF=%ld\n",(long)PIPE_BUF);
+#endif
+#endif
+#ifdef MULTITHREAD
+    printf(" -D MULTITHREAD\n");
+#endif
+#ifdef CHARSET_EBCDIC
+    printf(" -D CHARSET_EBCDIC\n");
+#endif
+#ifdef NEED_HASHBANG_EMUL
+    printf(" -D NEED_HASHBANG_EMUL\n");
+#endif
+#ifdef SHARED_CORE
+    printf(" -D SHARED_CORE\n");
+#endif
 
+/* This list displays the compiled-in default paths: */
+#ifdef HTTPD_ROOT
+    printf(" -D HTTPD_ROOT=\"" HTTPD_ROOT "\"\n");
+#endif
+#ifdef SUEXEC_BIN
+    printf(" -D SUEXEC_BIN=\"" SUEXEC_BIN "\"\n");
+#endif
+#ifdef SHARED_CORE_DIR
+    printf(" -D SHARED_CORE_DIR=\"" SHARED_CORE_DIR "\"\n");
+#endif
+#ifdef DEFAULT_PIDLOG
+    printf(" -D DEFAULT_PIDLOG=\"" DEFAULT_PIDLOG "\"\n");
+#endif
+#ifdef DEFAULT_SCOREBOARD
+    printf(" -D DEFAULT_SCOREBOARD=\"" DEFAULT_SCOREBOARD "\"\n");
+#endif
+#ifdef DEFAULT_LOCKFILE
+    printf(" -D DEFAULT_LOCKFILE=\"" DEFAULT_LOCKFILE "\"\n");
+#endif
+#ifdef DEFAULT_XFERLOG
+    printf(" -D DEFAULT_XFERLOG=\"" DEFAULT_XFERLOG "\"\n");
+#endif
+#ifdef DEFAULT_ERRORLOG
+    printf(" -D DEFAULT_ERRORLOG=\"" DEFAULT_ERRORLOG "\"\n");
+#endif
+#ifdef TYPES_CONFIG_FILE
+    printf(" -D TYPES_CONFIG_FILE=\"" TYPES_CONFIG_FILE "\"\n");
+#endif
+#ifdef SERVER_CONFIG_FILE
+    printf(" -D SERVER_CONFIG_FILE=\"" SERVER_CONFIG_FILE "\"\n");
+#endif
+#ifdef ACCESS_CONFIG_FILE
+    printf(" -D ACCESS_CONFIG_FILE=\"" ACCESS_CONFIG_FILE "\"\n");
+#endif
+#ifdef RESOURCE_CONFIG_FILE
+    printf(" -D RESOURCE_CONFIG_FILE=\"" RESOURCE_CONFIG_FILE "\"\n");
+#endif
 }
 
-static void standalone_main(int argc, char **argv)
+static void usage(char *bin)
 {
-    ap_standalone = 1;
-
-    is_graceful = 0;
-
-    if (!one_process) {
-        detach();
-    }
-    else {
-	MONCONTROL(1);
-    }
-
-    do {
-	one_config_cycle();
-        ++ap_scoreboard_image->global.running_generation;
-    } while (restart_pending);
+    char pad[MAX_STRING_LEN];
+    unsigned i;
 
-    /*add_common_vars(NULL);*/
-}				/* standalone_main */
+    for (i = 0; i < strlen(bin); i++)
+	pad[i] = ' ';
+    pad[i] = '\0';
+#ifdef SHARED_CORE
+    fprintf(stderr, "Usage: %s [-R directory] [-d directory] [-f file]\n", bin);
+#else
+    fprintf(stderr, "Usage: %s [-d directory] [-f file]\n", bin);
+#endif
+    fprintf(stderr, "       %s [-C \"directive\"] [-c \"directive\"]\n", pad);
+    fprintf(stderr, "       %s [-v] [-V] [-h] [-l] [-L] [-S] [-t]\n", pad);
+    fprintf(stderr, "Options:\n");
+#ifdef SHARED_CORE
+    fprintf(stderr, "  -R directory     : specify an alternate location for shared object files\n");
+#endif
+    fprintf(stderr, "  -D name          : define a name for use in <IfDefine name> directives\n");
+    fprintf(stderr, "  -d directory     : specify an alternate initial ServerRoot\n");
+    fprintf(stderr, "  -f file          : specify an alternate ServerConfigFile\n");
+    fprintf(stderr, "  -C \"directive\"   : process directive before reading config files\n");
+    fprintf(stderr, "  -c \"directive\"   : process directive after  reading config files\n");
+    fprintf(stderr, "  -v               : show version number\n");
+    fprintf(stderr, "  -V               : show compile settings\n");
+    fprintf(stderr, "  -h               : list available command line options (this page)\n");
+    fprintf(stderr, "  -l               : list compiled-in modules\n");
+    fprintf(stderr, "  -L               : list available configuration directives\n");
+    fprintf(stderr, "  -S               : show parsed settings (currently only vhost settings)\n");
+    fprintf(stderr, "  -t               : run syntax test for configuration files only\n");
+#ifdef WIN32
+    fprintf(stderr, "  -k shutdown      : tell running Apache to shutdown\n");
+    fprintf(stderr, "  -k restart       : tell running Apache to do a graceful restart\n");
+#endif
+    exit(1);
+}
 
 extern char *optarg;
 extern int optind;
@@ -2542,7 +1101,6 @@
     printf("%s \n", ap_get_server_version());
 #endif
 
-    ap_suexec_enabled = init_suexec();
     server_conf = ap_read_config(pconf, ptemp, ap_server_confname);
 
     if (configtestonly) {
Index: main/http_request.c
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/main/http_request.c,v
retrieving revision 1.4
diff -u -r1.4 http_request.c
--- http_request.c	1999/03/17 17:01:21	1.4
+++ http_request.c	1999/05/17 16:17:20
@@ -1232,14 +1232,11 @@
     int old_stat;
 
     if (ap_extended_status)
-	ap_time_process_request(r->connection->child_num, 
-				r->connection->thread_num, START_PREQUEST);
+	ap_time_process_request(r->connection, START_PREQUEST);
 
     process_request_internal(r);
 
-    old_stat = ap_update_child_status(r->connection->child_num,
-				      r->connection->thread_num,
-                                   SERVER_BUSY_LOG, r);
+    old_stat = ap_update_child_status(r->connection, SERVER_BUSY_LOG, r);
 
     /*
      * We want to flush the last packet if this isn't a pipelining connection
@@ -1251,11 +1248,9 @@
     ap_bhalfduplex(r->connection->client);
     ap_log_transaction(r);
 
-    (void) ap_update_child_status(r->connection->child_num, 
-				  r->connection->thread_num, old_stat, r);
+    (void) ap_update_child_status(r->connection, old_stat, r);
     if (ap_extended_status)
-	ap_time_process_request(r->connection->child_num,
-				r->connection->thread_num, STOP_PREQUEST);
+	ap_time_process_request(r->connection, STOP_PREQUEST);
 
 }
 
Index: main/http_worker.c
===================================================================
RCS file: http_worker.c
diff -N http_worker.c
--- /dev/null	Mon May 17 09:17:18 1999
+++ http_worker.c	Mon May 17 09:17:20 1999
@@ -0,0 +1,323 @@
+/* ====================================================================
+ * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer.  
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in 
+ *    the documentation and/or other materials provided with the 
+ *    distribution. 
+ * 
+ * 3. All advertising materials mentioning features or use of this 
+ *    software must display the following acknowledgment: 
+ *    "This product includes software developed by the Apache Group 
+ *    for use in the Apache HTTP server project (http://www.apache.org/)." 
+ * 
+ * 4. The names "Apache Server" and "Apache Group" must not be used to 
+ *    endorse or promote products derived from this software without 
+ *    prior written permission. For written permission, please contact 
+ *    apache@apache.org. 
+ * 
+ * 5. Products derived from this software may not be called "Apache" 
+ *    nor may "Apache" appear in their names without prior written 
+ *    permission of the Apache Group. 
+ * 
+ * 6. Redistributions of any form whatsoever must retain the following 
+ *    acknowledgment: 
+ *    "This product includes software developed by the Apache Group 
+ *    for use in the Apache HTTP server project (http://www.apache.org/)." 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY 
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR 
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
+ * OF THE POSSIBILITY OF SUCH DAMAGE. 
+ * ==================================================================== 
+ * 
+ * This software consists of voluntary contributions made by many 
+ * individuals on behalf of the Apache Group and was originally based 
+ * on public domain software written at the National Center for 
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign. 
+ * For more information on the Apache Group and the Apache HTTP server 
+ * project, please see <http://www.apache.org/>. 
+ * 
+ */ 
+
+#define CORE_PRIVATE 
+ 
+#include "httpd.h" 
+#include "http_event.h" 
+#include "http_log.h" 
+#include "http_conf_globals.h"
+#include "scoreboard.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_vhost.h"
+#include "http_protocol.h"
+
+#include <poll.h>
+#include <netinet/tcp.h>
+
+/*
+ * More machine-dependent networking gooo... on some systems,
+ * you've got to be *really* sure that all the packets are acknowledged
+ * before closing the connection, since the client will not be able
+ * to see the last response if their TCP buffer is flushed by a RST
+ * packet from us, which is what the server's TCP stack will send
+ * if it receives any request data after closing the connection.
+ *
+ * In an ideal world, this function would be accomplished by simply
+ * setting the socket option SO_LINGER and handling it within the
+ * server's TCP stack while the process continues on to the next request.
+ * Unfortunately, it seems that most (if not all) operating systems
+ * block the server process on close() when SO_LINGER is used.  So
+ * we have created a home-brew lingering_close.
+ *
+ * Many operating systems tend to block, puke, or otherwise mishandle
+ * calls to shutdown only half of the connection.  You should define
+ * NO_LINGCLOSE in ap_config.h if such is the case for your system.
+ */
+#ifndef MAX_SECS_TO_LINGER
+#define MAX_SECS_TO_LINGER 30
+#endif
+
+#ifndef NO_LINGCLOSE
+
+/* Since many clients will abort a connection instead of closing it,
+ * attempting to log an error message from this routine will only
+ * confuse the webmaster.  There doesn't seem to be any portable way to
+ * distinguish between a dropped connection and something that might be
+ * worth logging.
+ */
+/*ZZZ this routine needs to be adapted for use with poll()*/
+static void lingering_close(request_rec *r)     
+{
+  /*ZZZ remove the hardwired 512. This is an IO Buffer Size */
+    char dummybuf[512];    
+    struct pollfd pd;
+    int lsd;
+    int max_wait;
+
+    /* Prevent a slow-drip client from holding us here indefinitely */
+
+    max_wait = 30;
+    ap_bsetopt(r->connection->client, BO_TIMEOUT, &max_wait);
+
+    /* Send any leftover data to the client, but never try to again */
+
+    if (ap_bflush(r->connection->client) == -1) {
+	ap_bclose(r->connection->client);
+	return;
+    }
+    ap_bsetflag(r->connection->client, B_EOUT, 1);
+
+    /* Close our half of the connection --- send the client a FIN */
+
+    lsd = r->connection->client->fd;
+
+    if ((shutdown(lsd, 1) != 0)  /* ZZZ abstract shutdown */
+        || ap_is_aborted(r->connection)) {
+	ap_bclose(r->connection->client);
+	return;
+    }
+
+    /* Set up to wait for readable data on socket... */
+    pd.fd = lsd;
+    pd.events = POLLIN;
+
+    /* Wait for readable data or error condition on socket;
+     * slurp up any data that arrives...  We exit when we go for an
+     * interval of tv length without getting any more data, get an error
+     * from poll(), get an error or EOF on a read, or the timer expires.
+     */
+    /* We use a 2 second timeout because current (Feb 97) browsers
+     * fail to close a connection after the server closes it.  Thus,
+     * to avoid keeping the child busy, we are only lingering long enough
+     * for a client that is actively sending data on a connection.
+     * This should be sufficient unless the connection is massively
+     * losing packets, in which case we might have missed the RST anyway.
+     * These parameters are reset on each pass, since they might be
+     * changed by poll.
+     */
+    do {
+        pd.revents = 0;
+    } while ((poll(&pd, 1, 2) == 1)   
+             && read(lsd, dummybuf, sizeof(dummybuf)));
+      /* && (time() = epoch) < max_wait); */    /* ZZZZ time function is not good... */
+
+    /* Should now have seen final ack.  Safe to finally kill socket */
+    ap_bclose(r->connection->client);
+}
+#endif /* ndef NO_LINGCLOSE */
+
+
+/*****************************************************************
+ * Connection structures and accounting...
+ */
+
+
+static conn_rec *new_connection(pool *p, server_rec *server, BUFF *inout,
+                                const struct sockaddr_in *remaddr,   /* ZZZ */
+                                const struct sockaddr_in *saddr)     /* ZZZ */
+{
+    conn_rec *conn = (conn_rec *) ap_pcalloc(p, sizeof(conn_rec));
+
+    /* Got a connection structure, so initialize what fields we can
+     * (the rest are zeroed out by pcalloc).
+     */
+
+    conn->pool = p;
+    conn->local_addr = *saddr;
+    conn->server = server; /* just a guess for now */
+    ap_update_vhost_given_ip(conn);
+    conn->base_server = conn->server;
+    conn->client = inout;
+
+    conn->remote_addr = *remaddr;
+    conn->remote_ip = ap_pstrdup(conn->pool,
+			      inet_ntoa(conn->remote_addr.sin_addr));
+
+    return conn;
+}
+
+static void sock_disable_nagle(int s) /* ZZZ abstract */
+{
+    /* The Nagle algorithm says that we should delay sending partial
+     * packets in hopes of getting more data.  We don't want to do
+     * this; we are not telnet.  There are bad interactions between
+     * persistent connections and Nagle's algorithm that have very severe
+     * performance penalties.  (Failing to disable Nagle is not much of a
+     * problem with simple HTTP.)
+     *
+     * In spite of these problems, failure here is not a shooting offense.
+     */
+    int just_say_no = 1;
+
+    if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &just_say_no,
+		   sizeof(int)) < 0) {
+	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
+		    "setsockopt: (TCP_NODELAY)");
+    }
+}
+
+/*****************************************************************
+ * Child process main loop.
+ */
+
+static void process_socket(pool *p, struct sockaddr *sa_client, int csd)
+{
+    struct sockaddr sa_server; /* ZZZZ */
+    size_t len = sizeof(struct sockaddr);
+    BUFF *conn_io;
+    request_rec *r;
+    conn_rec *current_conn;
+
+    sock_disable_nagle(csd);
+
+    ap_note_cleanups_for_fd(p, csd);
+
+    /* ZZZ change to AP func */
+    if (getsockname(csd, &sa_server, &len) < 0) { 
+	ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "getsockname");
+	return;
+    }
+#if 0 /* XXX scoreboard */
+    (void) ap_update_child_status(SERVER_BUSY_READ, (request_rec *) NULL);
+#endif
+    conn_io = ap_bcreate(p, B_RDWR | B_SOCKET);
+    ap_bpushfd(conn_io, csd, csd);
+
+    current_conn = new_connection(p, server_conf, conn_io,
+                                  (const struct sockaddr_in *) sa_client, 
+                                  (const struct sockaddr_in *) &sa_server);
+
+    /*
+     * Read and process each request found on our connection
+     * until no requests are left or we decide to close.
+     */
+
+
+    while ((r = ap_read_request(current_conn)) != NULL) {
+	(void) ap_update_child_status(current_conn,
+				      SERVER_BUSY_WRITE, r);
+	if (r->status == HTTP_OK)
+	    ap_process_request(r);
+#if 0
+	if (ap_extended_status)
+	    increment_counts(my_child_num, my_thread_num, r);
+#endif
+	if (!current_conn->keepalive || ap_is_aborted(current_conn))
+	    break;
+	ap_destroy_pool(r->pool);
+	(void) ap_update_child_status(current_conn,
+				      SERVER_BUSY_KEEPALIVE, 
+				      (request_rec *) NULL);
+#if 0
+	if (ap_scoreboard_image->global.exit_generation > t->generation) {
+	    ap_bclose(conn_io);
+	    fprintf((stderr,"%d child_main: generation maxed\n",my_child_num));
+	    clean_child_exit(0);
+	}
+#endif
+    }
+
+    /*
+     * Close the connection, being careful to send out whatever is still
+     * in our buffers.  If possible, try to avoid a hard close until the
+     * client has ACKed our FIN and/or has stopped sending us data.
+     */
+
+#ifdef NO_LINGCLOSE
+    ap_bclose(conn_io);	/* just close it */
+#else
+    if (r && r->connection
+	&& !ap_is_aborted(r->connection)
+	&& r->connection->client
+	&& (r->connection->client->fd >= 0)) {
+
+	lingering_close(r);
+    }
+    else {
+	ap_bsetflag(conn_io, B_EOUT, 1);
+	ap_bclose(conn_io);
+    }
+#endif
+}
+
+
+void *ap_worker_thread(void *dummy)
+{
+    pool *ptrans;		/* Pool for per-transaction stuff */
+    workq_t *work;
+
+    while (1) {
+	work = workq_dequeue();
+	switch (work->type) {
+	case WORKQ_NEW_CONNECTION:
+	    /* XXX -- need to synchronize this pool ... 'cause it may be created
+	     * in one thread and destroyed elsewhere... hack hack hack
+	     */
+	    ptrans = ap_make_root_pool();
+	    process_socket(ptrans, &work->d.new_connection.sa_client,
+		work->d.new_connection.fd);
+	    ap_destroy_pool(ptrans);
+	    free(work);
+	    break;
+	case WORKQ_MAX:
+	    break;
+	}
+    }
+    return NULL;
+}
