httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r..@apache.org
Subject cvs commit: httpd-2.0/server/mpm/threaded Makefile.in config.m4 mpm.h mpm_default.h threaded.c
Date Fri, 16 Feb 2001 19:00:25 GMT
rbb         01/02/16 11:00:24

  Modified:    .        CHANGES
               docs/conf highperformance-std.conf httpd-std.conf
               docs/manual mpm.html
               docs/manual/mod index-bytype.html index.html mpm_common.html
                        prefork.html
               modules/generators config5.m4
               server/mpm MPM.NAMING config.m4
  Added:       docs/manual/mod threaded.html
               server/mpm/threaded Makefile.in config.m4 mpm.h
                        mpm_default.h threaded.c
  Removed:     docs/manual/mod mpmt_pthread.html
               server/mpm/mpmt_pthread Makefile.in Makefile.libdir
                        config.m4 mpm.h mpm_default.h mpmt_pthread.c
  Log:
  Rename the mpmt_pthread module to threaded.  This module has moved from
  the old mpmt_pthread directory to the new threaded directory.
  
  Revision  Changes    Path
  1.95      +5 -0      httpd-2.0/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/CHANGES,v
  retrieving revision 1.94
  retrieving revision 1.95
  diff -u -d -b -w -u -r1.94 -r1.95
  --- CHANGES	2001/02/16 13:38:31	1.94
  +++ CHANGES	2001/02/16 18:59:48	1.95
  @@ -1,5 +1,10 @@
   Changes with Apache 2.0.12-dev
   
  +  *) Rename mpmt_pthread to threaded.  This is more in line with the
  +     fact that mpmt_pthread shouldn't be using pthreads directly, and
  +     it is a smaller name that doesn't tie into anything.
  +     [Ryan Bloom]
  +
     *) Rename the module structures so that the exported symbol matches
        the file name, and it is easier to automate the installation
        process (generating LoadModule directives from the module filenames).
  
  
  
  1.3       +1 -1      httpd-2.0/docs/conf/highperformance-std.conf
  
  Index: highperformance-std.conf
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/docs/conf/highperformance-std.conf,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -d -b -w -u -r1.2 -r1.3
  --- highperformance-std.conf	2001/01/25 21:38:10	1.2
  +++ highperformance-std.conf	2001/02/16 18:59:53	1.3
  @@ -26,7 +26,7 @@
   MaxSpareServers 10
   </IfModule>
   
  -<IfModule mpmt_pthread.c>
  +<IfModule threaded.c>
   MaxClients       8
   StartServers     1
   MinSpareThreads  5
  
  
  
  1.24      +1 -1      httpd-2.0/docs/conf/httpd-std.conf
  
  Index: httpd-std.conf
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/docs/conf/httpd-std.conf,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -d -b -w -u -r1.23 -r1.24
  --- httpd-std.conf	2001/02/15 00:57:17	1.23
  +++ httpd-std.conf	2001/02/16 18:59:54	1.24
  @@ -125,7 +125,7 @@
   # MaxSpareThreads ...... maximum  number of worker threads which are kept spare
   # ThreadsPerChild ...... constant number of worker threads in each server process
   # MaxRequestsPerChild .. maximum  number of requests a server process serves
  -<IfModule mpmt_pthread.c>
  +<IfModule threaded.c>
   StartServers         5
   MaxClients           8
   MinSpareThreads      5
  
  
  
  1.6       +2 -2      httpd-2.0/docs/manual/mpm.html
  
  Index: mpm.html
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/docs/manual/mpm.html,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -d -b -w -u -r1.5 -r1.6
  --- mpm.html	2000/12/21 15:41:16	1.5
  +++ mpm.html	2001/02/16 18:59:56	1.6
  @@ -46,7 +46,7 @@
   <li>The server can be better customized for the needs of the
   particular site.  For example, sites that need a great deal of
   scalability can choose to use a threaded MPM like <a
  -href="mod/mpmt_pthread.html">mpmt_pthread</a>, while sites requiring
  +href="mod/threaded.html">threaded</a>, while sites requiring
   stability or compatibility with older software can use a <a
   href="mod/prefork.html">preforking MPM</a>.  In addition, special
   features like serving different hosts under different userids
  @@ -79,7 +79,7 @@
   <ul>
     <li> BeOS:  mpmt_beos</li>
     <li> OS/2:  spmt_os2</li>
  -  <li> Unix:  mpmt_pthread </li>
  +  <li> Unix:  threaded </li>
     <li> Windows:  winnt</li>
   </ul>
   
  
  
  
  1.14      +1 -1      httpd-2.0/docs/manual/mod/index-bytype.html
  
  Index: index-bytype.html
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/docs/manual/mod/index-bytype.html,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -d -b -w -u -r1.13 -r1.14
  --- index-bytype.html	2001/02/13 20:30:13	1.13
  +++ index-bytype.html	2001/02/16 18:59:59	1.14
  @@ -28,7 +28,7 @@
   <DL>
   <DT><A HREF="core.html">Core</A>
   <DD>Core Apache features.
  -<DT><A HREF="mpmt_pthread.html">mpmt_pthread</A>
  +<DT><A HREF="threaded.html">threaded</A>
   <DD>Multi-Processing Module with Threading via Pthreads; Variable number
   of processes, constant number of threads/child
   <DT><a href="mpm_winnt.html">mpm_winnt</a>
  
  
  
  1.49      +1 -1      httpd-2.0/docs/manual/mod/index.html
  
  Index: index.html
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/docs/manual/mod/index.html,v
  retrieving revision 1.48
  retrieving revision 1.49
  diff -u -d -b -w -u -r1.48 -r1.49
  --- index.html	2001/02/13 20:30:14	1.48
  +++ index.html	2001/02/16 19:00:00	1.49
  @@ -29,7 +29,7 @@
   <DL>
   <DT><A HREF="core.html">Core</A>
   <DD>Core Apache features.
  -<DT><A HREF="mpmt_pthread.html">mpmt_pthread</A>
  +<DT><A HREF="threaded.html">threaded</A>
   <DD>Multi-Processing Module with Threading via Pthreads; Variable number
   of processes, constant number of threads/child
   <DT><a href="mpm_winnt.html">mpm_winnt</a>
  
  
  
  1.10      +21 -21    httpd-2.0/docs/manual/mod/mpm_common.html
  
  Index: mpm_common.html
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/docs/manual/mod/mpm_common.html,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -d -b -w -u -r1.9 -r1.10
  --- mpm_common.html	2001/02/13 20:30:14	1.9
  +++ mpm_common.html	2001/02/16 19:00:00	1.10
  @@ -94,7 +94,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, perchild, prefork, mpm_winnt</p>
  +><STRONG>Module:</STRONG></A> threaded, perchild, prefork, mpm_winnt</p>
   
   <p>This controls the directory to which Apache attempts to switch
   before dumping core.  The default is in the <A
  @@ -125,7 +125,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, perchild, prefork</p>
  +><STRONG>Module:</STRONG></A> threaded, perchild, prefork</p>
   
   The Group directive sets the group under which the server will answer requests.
   In order to use this directive, the stand-alone server must be run initially
  @@ -175,7 +175,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, perchild, prefork, mpm_winnt</p>
  +><STRONG>Module:</STRONG></A> threaded, perchild, prefork, mpm_winnt</p>
   
   <p>The PidFile directive sets the file to which the server records the
   process id of the daemon. If the filename does not begin with a slash
  @@ -210,7 +210,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, perchild, prefork, mpm_winnt</p>
  +><STRONG>Module:</STRONG></A> threaded, perchild, prefork, mpm_winnt</p>
   
   
   <P>The Listen directive instructs Apache to listen to only specific IP
  @@ -279,7 +279,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, perchild, prefork, mpm_winnt</p>
  +><STRONG>Module:</STRONG></A> threaded, perchild, prefork, mpm_winnt</p>
   
   <P>The maximum length of the queue of pending connections.  Generally no
   tuning is needed or desired, however on some systems it is desirable
  @@ -312,7 +312,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, perchild, prefork</p>
  +><STRONG>Module:</STRONG></A> threaded, perchild, prefork</p>
   
   <p>The LockFile directive sets the path to the lockfile used when
   Apache is compiled with either USE_FCNTL_SERIALIZED_ACCEPT or
  @@ -352,7 +352,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, prefork</p>
  +><STRONG>Module:</STRONG></A> threaded, prefork</p>
   
   <P>The MaxClients directive sets the limit on the number of child
   processes that will be created to serve requests.  When the server is
  @@ -394,7 +394,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, prefork, perchild, mpm_winnt</p>
  +><STRONG>Module:</STRONG></A> threaded, prefork, perchild, mpm_winnt</p>
   
   <p>The MaxRequestsPerChild directive sets the limit on the number of requests
   that an individual child server process will handle. After MaxRequestsPerChild
  @@ -424,7 +424,7 @@
   <A
    HREF="directive-dict.html#Default"
    REL="Help"
  -><STRONG>Default:</STRONG></A> <CODE>MaxSpareThreads 10 (Perchild) or 500 (Mpmt_pthread) </CODE><BR>
  +><STRONG>Default:</STRONG></A> <CODE>MaxSpareThreads 10 (Perchild) or 500 (threaded) </CODE><BR>
   <A
    HREF="directive-dict.html#Context"
    REL="Help"
  @@ -436,13 +436,13 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, perchild</p>
  +><STRONG>Module:</STRONG></A> threaded, perchild</p>
   
   <P>Maximum number of idle threads.  Different MPMs deal with this directive
   differently.  Perchild monitor the number of idle threads on a
   per-child basis.  If there are too many idle threads in that child, the server
   will begin to kill threads within that child.</P>
  -<P>Mpmt_pthread deals with idle threads on a server-wide basis.  If there are 
  +<P>threaded deals with idle threads on a server-wide basis.  If there are 
   too many idle threads in the server then child processes are killed 
   until the number of idle threads is less than this number.</p>
   
  @@ -471,7 +471,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, perchild</p>
  +><STRONG>Module:</STRONG></A> threaded, perchild</p>
   
   <P>Maximum number of threads per child.  For MPMs with a variable
   number of threads per child, this directive sets the maximum number of
  @@ -491,7 +491,7 @@
   <A
    HREF="directive-dict.html#Default"
    REL="Help"
  -><STRONG>Default:</STRONG></A> <CODE>MaxSpareThreads 5 (Perchild) or 250 (Mpmt_pthread) </CODE><BR>
  +><STRONG>Default:</STRONG></A> <CODE>MaxSpareThreads 5 (Perchild) or 250 (threaded) </CODE><BR>
   <A
    HREF="directive-dict.html#Context"
    REL="Help"
  @@ -503,14 +503,14 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, perchild</p>
  +><STRONG>Module:</STRONG></A> threaded, perchild</p>
   
   <P>Minimum number of idle threads to handle request spikes.  Different MPMs 
   deal with this directive differently.  Perchild monitor the number 
   of idle threads on a per-child basis.  If there aren't enough idle threads in 
   that child, the server will begin to create new threads within that child.  
   </P>
  -<P>Mpmt_pthread deals with idle threads on a server-wide basis.  If there 
  +<P>threaded deals with idle threads on a server-wide basis.  If there 
   aren't enough idle threads in the server then child processes are created 
   until the number of idle threads is greater than number.</p>
   
  @@ -572,7 +572,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, perchild, prefork</p>
  +><STRONG>Module:</STRONG></A> threaded, perchild, prefork</p>
   
   <p>The ScoreBoardFile directive is required on some architectures to place
   a file that the server will use to communicate between its children and
  @@ -610,7 +610,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, perchild, prefork, mpm_winnt</p>
  +><STRONG>Module:</STRONG></A> threaded, perchild, prefork, mpm_winnt</p>
   
   The server will set the TCP buffer size to the number of bytes
   specified. Very useful to increase past standard OS defaults on high
  @@ -640,7 +640,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, prefork</p>
  +><STRONG>Module:</STRONG></A> threaded, prefork</p>
   
   <p>The StartServers directive sets the number of child server processes created
   on startup. As the number of processes is dynamically controlled depending
  @@ -698,13 +698,13 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, mpm_winnt</p>
  +><STRONG>Module:</STRONG></A> threaded, mpm_winnt</p>
   
   <P>This directive sets the number of threads created by each child
   process.  The child creates these threads at startup and never creates
   more.  if using an MPM like mpmt_winnt, where there is only one child process,
   this number should be high enough to handle the entire load of the server.
  -If using an MPM like mpmt_pthread, where there are multiple child processes,
  +If using an MPM like threaded, where there are multiple child processes,
   the total number of threads should be high enough to handle the common load
   on the server.</p>
   
  @@ -732,7 +732,7 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mpmt_pthread, perchild, prefork</p>
  +><STRONG>Module:</STRONG></A> threaded, perchild, prefork</p>
   
   The User directive sets the userid as which the server will answer requests.
   In order to use this directive, the standalone server must be run initially
  
  
  
  1.4       +1 -1      httpd-2.0/docs/manual/mod/prefork.html
  
  Index: prefork.html
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/docs/manual/mod/prefork.html,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -d -b -w -u -r1.3 -r1.4
  --- prefork.html	2000/11/22 06:15:41	1.3
  +++ prefork.html	2001/02/16 19:00:02	1.4
  @@ -1,7 +1,7 @@
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
   <HTML>
   <HEAD>
  -<TITLE>Apache MPM mpmt_pthread</TITLE>
  +<TITLE>Apache MPM prefork</TITLE>
   </HEAD>
   
   <!-- Background white, links blue (unvisited), navy (visited), red (active) -->
  
  
  
  1.1                  httpd-2.0/docs/manual/mod/threaded.html
  
  Index: threaded.html
  ===================================================================
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
  <HTML>
  <HEAD>
  <TITLE>Apache MPM threaded</TITLE>
  </HEAD>
  
  <!-- Background white, links blue (unvisited), navy (visited), red (active) -->
  <BODY
   BGCOLOR="#FFFFFF"
   TEXT="#000000"
   LINK="#0000FF"
   VLINK="#000080"
   ALINK="#FF0000"
  >
  <!--#include virtual="header.html" -->
  
  <H1 ALIGN="CENTER">Multi-Processing Module threaded</H1>
  <P>
  This Multi-Processing Module implements a hybrid multi-threaded
  multi-process web server.
  </P>
  
  <P><A
  HREF="module-dict.html#Status"
  REL="Help"
  ><STRONG>Status:</STRONG></A> MPM
  <BR>
  <A
  HREF="module-dict.html#SourceFile"
  REL="Help"
  ><STRONG>Source File:</STRONG></A> threaded.c
  <BR>
  <A
  HREF="module-dict.html#ModuleIdentifier"
  REL="Help"
  ><STRONG>Module Identifier:</STRONG></A> mpm_threaded_module
  </P>
  
  <H2>Summary</H2>
  
  <p>This Multi-Processing Module (MPM) is the default for most unix-like
  operating systems.  It implements a hybrid
  multi-process multi-threaded server.  Each process has a fixed number
  of threads.  The server adjusts to handle load by increasing or
  decreasing the number of processes.</p>
  
  <p>A single control process is responsible for launching child
  processes.  Each child process creates a fixed number of threads as
  specified in the <code>ThreadsPerChild</code> directive.
  The individual threads then listen for connections and
  serve them when they arrive.</p>
  
  <p>Apache always tries to maintain a pool of <em>spare</em> or idle
  server threads, which stand ready to serve incoming requests.  In this
  way, clients do not need to wait for a new threads or processes to be
  created before their requests can be served.  Apache assesses the
  total number of idle threads in all processes, and forks or kills
  processes to keep this number within the boundaries specified by
  <code>MinSpareThreads</code> and <code>MaxSpareThreads</code>.
  Since this process is very self-regulating, it is rarely necessary to
  modify these directives from their default values.  The maximum
  number of clients that may be served simultaneously is determined
  by multiplying the maximum number of server processes that
  will be created (<code>MaxClients</code>) by the number of threads
  created in each process (<code>ThreadsPerChild</code>).</p>
  
  <p>While the parent process is usually started as root under Unix in
  order to bind to port 80, the child processes and threads are launched
  by Apache as a less-privileged user.  The <code>User</code> and
  <code>Group</code> directives are used to set the privileges of the
  Apache child processes.  The child processes must be able to read all
  the content that will be served, but should have as few privileges
  beyond that as possible.  In addition, unless <a
  href="../suexec.html">suexec</a> is used, these directives also set
  the privileges which will be inherited by CGI scripts.</p>
  
  <p><code>MaxRequestsPerChild</code> controls how frequently the server
  recycles processes by killing old ones and launching new ones.</p>
  
  <p>See also: <a href="../bind.html">Setting which addresses and ports
  Apache uses</a>.</p>
  
  
  <H2>Directives</H2>
  <UL>
  <li><a href="mpm_common.html#coredumpdirectory">CoreDumpDirectory</a></li>
  <li><a href="mpm_common.html#group">Group</a></li>
  <li><a href="mpm_common.html#pidfile">PidFile</a></li>
  <li><a href="mpm_common.html#listen">Listen</a></li>
  <li><a href="mpm_common.html#listenbacklog">ListenBacklog</a></li>
  <li><a href="mpm_common.html#lockfile">LockFile</a></li>
  <li><a href="mpm_common.html#maxclients">MaxClients</a></li>
  <li><a href="mpm_common.html#maxrequestsperchild">MaxRequestsPerChild</a></li>
  <li><a href="mpm_common.html#maxsparethreads">MaxSpareThreads</a></li>
  <li><a href="mpm_common.html#minsparethreads">MinSpareThreads</a></li>
  <li><a href="mpm_common.html#scoreboardfile">ScoreBoardFile</a></li>
  <li><a href="mpm_common.html#sendbuffersize">SendBufferSize</a></li>
  <li><a href="mpm_common.html#startservers">StartServers</a></li>
  <li><a href="mpm_common.html#threadsperchild">ThreadsPerChild</a></li>
  <li><a href="mpm_common.html#user">User</a></li>
  </UL>
  
  <!--#include virtual="footer.html" -->
  </BODY>
  </HTML>
  
  
  
  1.3       +1 -1      httpd-2.0/modules/generators/config5.m4
  
  Index: config5.m4
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/generators/config5.m4,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -d -b -w -u -r1.2 -r1.3
  --- config5.m4	2001/01/21 17:22:18	1.2
  +++ config5.m4	2001/02/16 19:00:07	1.3
  @@ -13,7 +13,7 @@
   
   LTFLAGS="$LTFLAGS -export-dynamic"
   
  -if test "$apache_cv_mpm" = "mpmt_pthread" -o "$apache_cv_mpm" = "dexter"; then
  +if test "$apache_cv_mpm" = "threaded" -o "$apache_cv_mpm" = "perchild"; then
   # if we are using a threaded MPM, we will get better performance with
   # mod_cgid, so make it the default.
       APACHE_MODULE(cgid, CGI scripts, , , yes)
  
  
  
  1.6       +1 -1      httpd-2.0/server/mpm/MPM.NAMING
  
  Index: MPM.NAMING
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/MPM.NAMING,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -d -b -w -u -r1.5 -r1.6
  --- MPM.NAMING	2001/02/13 20:30:16	1.5
  +++ MPM.NAMING	2001/02/16 19:00:10	1.6
  @@ -27,7 +27,7 @@
     perchild ...... Multi  Process Model with Threading via Pthreads
                     Constant number of processes, variable number of threads
                     each child process can have a different uid/gid.  
  -  mpmt_pthread .. Multi  Process Model with Threading via Pthreads
  +  threaded ...... Multi  Process Model with Threading via Pthreads
                     Variable number of processes, constant number of
                     threads/child (= Apache/pthread)
     spmt_os2 ...... Single Process Model with Threading on OS/2
  
  
  
  1.31      +3 -3      httpd-2.0/server/mpm/config.m4
  
  Index: config.m4
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/config.m4,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -d -b -w -u -r1.30 -r1.31
  --- config.m4	2001/02/13 21:23:22	1.30
  +++ config.m4	2001/02/16 19:00:10	1.31
  @@ -1,18 +1,18 @@
   AC_MSG_CHECKING(which MPM to use)
   AC_ARG_WITH(mpm,
   [  --with-mpm=MPM          Choose the process model for Apache to use.
  -               MPM={beos,mpmt_pthread,prefork,spmt_os2,perchild}],[
  +               MPM={beos,threaded,prefork,spmt_os2,perchild}],[
     APACHE_MPM=$withval
   ],[
     if test "x$APACHE_MPM" = "x"; then
  -    APACHE_MPM=mpmt_pthread
  +    APACHE_MPM=threaded
     fi
   ])
   AC_MSG_RESULT($APACHE_MPM)
   
   apache_cv_mpm=$APACHE_MPM
   	
  -if test "$apache_cv_mpm" = "mpmt_pthread" -o "$apache_cv_mpm" = "perchild"; then
  +if test "$apache_cv_mpm" = "threaded" -o "$apache_cv_mpm" = "perchild"; then
     PTHREADS_CHECK
     AC_MSG_CHECKING([for which threading library to use])
     AC_MSG_RESULT($threads_result)
  
  
  
  1.1                  httpd-2.0/server/mpm/threaded/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  
  LTLIBRARY_NAME    = libthreaded.la
  LTLIBRARY_SOURCES = threaded.c
  
  include $(top_srcdir)/build/ltlib.mk
  
  
  
  1.1                  httpd-2.0/server/mpm/threaded/config.m4
  
  Index: config.m4
  ===================================================================
  dnl ## XXX - Need a more thorough check of the proper flags to use
  
  if test "$MPM_NAME" = "threaded" ; then
  
      APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile)
  
      APACHE_MPM_PTHREAD
  
  fi
  
  
  
  1.1                  httpd-2.0/server/mpm/threaded/mpm.h
  
  Index: mpm.h
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2001 The Apache Software Foundation.  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. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * Portions of this software are based upon public domain software
   * originally written at the National Center for Supercomputing Applications,
   * University of Illinois, Urbana-Champaign.
   */
  #include "scoreboard.h"
  #include "unixd.h"
  
  #ifndef APACHE_MPM_THREADED_H
  #define APACHE_MPM_THREADED_H
  
  #define THREADED_MPM
  
  #define MPM_NEEDS_RECLAIM_CHILD_PROCESSES 1
  #define MPM_SYNC_CHILD_TABLE() (ap_sync_scoreboard_image())
  #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
  #define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
  
  extern int ap_threads_per_child;
  extern int ap_max_requests_per_child;
  extern int ap_max_daemons_limit;
  extern unsigned int ap_my_pid;
  extern server_rec *ap_server_conf;
  extern char ap_coredump_dir[MAX_STRING_LEN];
  
  #endif /* APACHE_MPM_THREADED_H */
  
  
  
  1.1                  httpd-2.0/server/mpm/threaded/mpm_default.h
  
  Index: mpm_default.h
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2001 The Apache Software Foundation.  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. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * Portions of this software are based upon public domain software
   * originally written at the National Center for Supercomputing Applications,
   * University of Illinois, Urbana-Champaign.
   */
  
  #ifndef APACHE_MPM_DEFAULT_H
  #define APACHE_MPM_DEFAULT_H
  
  #define AP_ID_FROM_CHILD_THREAD(c, t)    ((c * HARD_THREAD_LIMIT) + t)
  #define AP_CHILD_THREAD_FROM_ID(i)    (i / HARD_THREAD_LIMIT), (i % HARD_THREAD_LIMIT)
  
  /* Number of servers to spawn off by default --- also, if fewer than
   * this free when the caretaker checks, it will spawn more.
   */
  #ifndef DEFAULT_START_DAEMON
  #define DEFAULT_START_DAEMON 5
  #endif
  
  /* Maximum number of *free* server processes --- more than this, and
   * they will die off.
   */
  
  #ifndef DEFAULT_MAX_FREE_DAEMON
  #define DEFAULT_MAX_FREE_DAEMON 10
  #endif
  
  /* Minimum --- fewer than this, and more will be created */
  
  #ifndef DEFAULT_MIN_FREE_DAEMON
  #define DEFAULT_MIN_FREE_DAEMON 5
  #endif
  
  /* Limit on the total --- clients will be locked out if more servers than
   * this are needed.  It is intended solely to keep the server from crashing
   * when things get out of hand.
   *
   * We keep a hard maximum number of servers, for two reasons --- first off,
   * in case something goes seriously wrong, we want to stop the fork bomb
   * short of actually crashing the machine we're running on by filling some
   * kernel table.  Secondly, it keeps the size of the scoreboard file small
   * enough that we can read the whole thing without worrying too much about
   * the overhead.
   */
  #ifdef NO_THREADS
  #define HARD_SERVER_LIMIT 256
  #endif
  #ifndef HARD_SERVER_LIMIT
  #define HARD_SERVER_LIMIT 8 
  #endif
  
  /* Limit on the threads per process.  Clients will be locked out if more than
   * this  * HARD_SERVER_LIMIT are needed.
   *
   * We keep this for one reason it keeps the size of the scoreboard file small
   * enough that we can read the whole thing without worrying too much about
   * the overhead.
   */
  #ifdef NO_THREADS
  #define HARD_THREAD_LIMIT 1
  #endif
  #ifndef HARD_THREAD_LIMIT
  #define HARD_THREAD_LIMIT 64 
  #endif
  
  #ifdef NO_THREADS
  #define DEFAULT_THREADS_PER_CHILD 1
  #endif
  #ifndef DEFAULT_THREADS_PER_CHILD
  #define DEFAULT_THREADS_PER_CHILD 50
  #endif
  
  /* File used for accept locking, when we use a file */
  #ifndef DEFAULT_LOCKFILE
  #define DEFAULT_LOCKFILE "logs/accept.lock"
  #endif
  
  /* Scoreboard file, if there is one */
  #ifndef DEFAULT_SCOREBOARD
  #define DEFAULT_SCOREBOARD "logs/apache_runtime_status"
  #endif
  
  /* Where the main/parent process's pid is logged */
  #ifndef DEFAULT_PIDLOG
  #define DEFAULT_PIDLOG "logs/httpd.pid"
  #endif
  
  /*
   * Interval, in microseconds, between scoreboard maintenance.
   */
  #ifndef SCOREBOARD_MAINTENANCE_INTERVAL
  #define SCOREBOARD_MAINTENANCE_INTERVAL 1000000
  #endif
  
  /* Number of requests to try to handle in a single process.  If <= 0,
   * the children don't die off.
   */
  #ifndef DEFAULT_MAX_REQUESTS_PER_CHILD
  #define DEFAULT_MAX_REQUESTS_PER_CHILD 10000
  #endif
  
  #endif /* AP_MPM_DEFAULT_H */
  
  
  
  1.1                  httpd-2.0/server/mpm/threaded/threaded.c
  
  Index: threaded.c
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2001 The Apache Software Foundation.  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. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * Portions of this software are based upon public domain software
   * originally written at the National Center for Supercomputing Applications,
   * University of Illinois, Urbana-Champaign.
   */
  
  #include "apr.h"
  #include "apr_portable.h"
  #include "apr_strings.h"
  #include "apr_file_io.h"
  #include "apr_thread_proc.h"
  #include "apr_signal.h"
  
  #if APR_HAVE_UNISTD_H
  #include <unistd.h>
  #endif
  #if APR_HAVE_SYS_SOCKET_H
  #include <sys/socket.h>
  #endif
  #if APR_HAVE_SYS_WAIT_H
  #include <sys/wait.h> 
  #endif
  
  #define CORE_PRIVATE 
   
  #include "ap_config.h"
  #include "httpd.h" 
  #include "http_main.h" 
  #include "http_log.h" 
  #include "http_config.h"	/* for read_config */ 
  #include "http_core.h"		/* for get_remote_host */ 
  #include "http_connection.h"
  #include "ap_mpm.h"
  #include "unixd.h"
  #include "mpm_common.h"
  #include "ap_listen.h"
  #include "scoreboard.h" 
  
  #ifdef HAVE_NETINET_TCP_H
  #include <netinet/tcp.h>
  #endif
  
  #include <pthread.h>
  #include <signal.h>
  
  /*
   * Actual definitions of config globals
   */
  
  int ap_threads_per_child=0;         /* Worker threads per child */
  int ap_max_requests_per_child=0;
  static const char *ap_pid_fname=NULL;
  static int ap_daemons_to_start=0;
  static int min_spare_threads=0;
  static int max_spare_threads=0;
  static int ap_daemons_limit=0;
  static int workers_may_exit = 0;
  static int requests_this_child;
  static int num_listensocks = 0;
  static apr_socket_t **listensocks;
  
  /* The structure used to pass unique initialization info to each thread */
  typedef struct {
      int pid;
      int tid;
      int sd;
      apr_pool_t *tpool; /* "pthread" would be confusing */
  } proc_info;
  
  /*
   * The max child slot ever assigned, preserved across restarts.  Necessary
   * to deal with MaxClients changes across SIGWINCH restarts.  We use this
   * value to optimize routines that have to scan the entire scoreboard.
   */
  int ap_max_daemons_limit = -1;
  
  char ap_coredump_dir[MAX_STRING_LEN];
  
  static apr_file_t *pipe_of_death_in = NULL;
  static apr_file_t *pipe_of_death_out = NULL;
  static pthread_mutex_t pipe_of_death_mutex;
  
  /* *Non*-shared http_main globals... */
  
  server_rec *ap_server_conf;
  
  /* one_process --- debugging mode variable; can be set from the command line
   * with the -X flag.  If set, this gets you the child_main loop running
   * in the process which originally started up (no detach, no make_child),
   * which is a pretty nice debugging environment.  (You'll get a SIGHUP
   * early in standalone_main; just continue through.  This is the server
   * trying to kill off any child processes which it might have lying
   * around --- Apache doesn't keep track of their pids, it just sends
   * SIGHUP to the process group, ignoring it in the root process.
   * Continue through and you'll be fine.).
   */
  
  static int one_process = 0;
  
  #ifdef DEBUG_SIGSTOP
  int raise_sigstop_flags;
  #endif
  
  static apr_pool_t *pconf;		/* Pool for config stuff */
  static apr_pool_t *pchild;		/* Pool for httpd child stuff */
  
  unsigned int ap_my_pid; /* Linux getpid() doesn't work except in main 
                             thread. Use this instead */
  /* Keep track of the number of worker threads currently active */
  static int worker_thread_count;
  static pthread_mutex_t worker_thread_count_mutex;
  
  /* Locks for accept serialization */
  static apr_lock_t *accept_mutex;
  static const char *lock_fname;
  
  #ifdef NO_SERIALIZED_ACCEPT
  #define SAFE_ACCEPT(stmt) APR_SUCCESS
  #else
  #define SAFE_ACCEPT(stmt) (stmt)
  #endif
  
  AP_DECLARE(int) ap_get_max_daemons(void)
  {
      return ap_max_daemons_limit;
  }
  
  /* a clean exit from a child with proper cleanup */ 
  static void clean_child_exit(int code) __attribute__ ((noreturn));
  void clean_child_exit(int code)
  {
      if (pchild) {
  	apr_pool_destroy(pchild);
      }
      exit(code);
  }
  
  /* handle all varieties of core dumping signals */
  static void sig_coredump(int sig)
  {
      chdir(ap_coredump_dir);
      apr_signal(sig, SIG_DFL);
      kill(ap_my_pid, sig);
      /* 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.
       */
  }
  
  static void just_die(int sig)
  {
      clean_child_exit(0);
  }
  
  /*****************************************************************
   * 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.
   */
  
  static 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 */
  static 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;
      if (is_graceful) {
          apr_pool_cleanup_kill(pconf, NULL, ap_cleanup_scoreboard);
      }
  }
  
  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, errno, ap_server_conf, "sigaction(SIGSEGV)");
  #ifdef SIGBUS
  	if (sigaction(SIGBUS, &sa, NULL) < 0)
  	    ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)");
  #endif
  #ifdef SIGABORT
  	if (sigaction(SIGABORT, &sa, NULL) < 0)
  	    ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)");
  #endif
  #ifdef SIGABRT
  	if (sigaction(SIGABRT, &sa, NULL) < 0)
  	    ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)");
  #endif
  #ifdef SIGILL
  	if (sigaction(SIGILL, &sa, NULL) < 0)
  	    ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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, errno, ap_server_conf, "sigaction(SIGTERM)");
  #ifdef SIGINT
      if (sigaction(SIGINT, &sa, NULL) < 0)
          ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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, errno, ap_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, errno, ap_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, errno, ap_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, errno, ap_server_conf, "sigaction(SIGHUP)");
      if (sigaction(SIGWINCH, &sa, NULL) < 0)
  	ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGWINCH)");
  #else
      if (!one_process) {
  	apr_signal(SIGSEGV, sig_coredump);
  #ifdef SIGBUS
  	apr_signal(SIGBUS, sig_coredump);
  #endif /* SIGBUS */
  #ifdef SIGABORT
  	apr_signal(SIGABORT, sig_coredump);
  #endif /* SIGABORT */
  #ifdef SIGABRT
  	apr_signal(SIGABRT, sig_coredump);
  #endif /* SIGABRT */
  #ifdef SIGILL
  	apr_signal(SIGILL, sig_coredump);
  #endif /* SIGILL */
  #ifdef SIGXCPU
  	apr_signal(SIGXCPU, SIG_DFL);
  #endif /* SIGXCPU */
  #ifdef SIGXFSZ
  	apr_signal(SIGXFSZ, SIG_DFL);
  #endif /* SIGXFSZ */
      }
  
      apr_signal(SIGTERM, sig_term);
  #ifdef SIGHUP
      apr_signal(SIGHUP, restart);
  #endif /* SIGHUP */
  #ifdef SIGWINCH
      apr_signal(SIGWINCH, restart);
  #endif /* SIGWINCH */
  #ifdef SIGPIPE
      apr_signal(SIGPIPE, SIG_IGN);
  #endif /* SIGPIPE */
  
  #endif
  }
  
  /*****************************************************************
   * Here follows a long bunch of generic server bookkeeping stuff...
   */
  
  int ap_graceful_stop_signalled(void)
  {
      /* XXX - Does this really work? - Manoj */
      return is_graceful;
  }
  
  /*****************************************************************
   * Child process main loop.
   */
  
  static void process_socket(apr_pool_t *p, apr_socket_t *sock, int my_child_num, int my_thread_num)
  {
      conn_rec *current_conn;
      long conn_id = AP_ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
      int csd;
  
      (void) apr_os_sock_get(&csd, sock);
  
      if (csd >= FD_SETSIZE) {
          ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, NULL,
                       "new file descriptor %d is too large; you probably need "
                       "to rebuild Apache with a larger FD_SETSIZE "
                       "(currently %d)", 
                       csd, FD_SETSIZE);
          apr_socket_close(sock);
          return;
      }
  
      ap_sock_disable_nagle(sock);
  
      current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id);
      if (current_conn) {
          ap_process_connection(current_conn);
          ap_lingering_close(current_conn);
      }
  }
  /* Sets workers_may_exit if we received a character on the pipe_of_death */
  static void check_pipe_of_death(void)
  {
      pthread_mutex_lock(&pipe_of_death_mutex);
      if (!workers_may_exit) {
          apr_status_t ret;
          char pipe_read_char;
  	apr_size_t n = 1;
  
          ret = apr_recv(listensocks[0], &pipe_read_char, &n);
          if (APR_STATUS_IS_EAGAIN(ret)) {
              /* It lost the lottery. It must continue to suffer
               * through a life of servitude. */
          }
          else {
              /* It won the lottery (or something else is very
               * wrong). Embrace death with open arms. */
              workers_may_exit = 1;
          }
      }
      pthread_mutex_unlock(&pipe_of_death_mutex);
  }
  
  static void * worker_thread(void * dummy)
  {
      proc_info * ti = dummy;
      int process_slot = ti->pid;
      int thread_slot = ti->tid;
      apr_pool_t *tpool = ti->tpool;
      apr_socket_t *csd = NULL;
      apr_pool_t *ptrans;		/* Pool for per-transaction stuff */
      apr_socket_t *sd = NULL;
      int n;
      int curr_pollfd, last_pollfd = 0;
      apr_pollfd_t *pollset;
      apr_status_t rv;
  
      free(ti);
  
      apr_pool_create(&ptrans, tpool);
  
      pthread_mutex_lock(&worker_thread_count_mutex);
      worker_thread_count++;
      pthread_mutex_unlock(&worker_thread_count_mutex);
  
      apr_poll_setup(&pollset, num_listensocks+1, tpool);
      for(n=0 ; n <= num_listensocks ; ++n)
  	apr_poll_socket_add(pollset, listensocks[n], APR_POLLIN);
  
      /* TODO: Switch to a system where threads reuse the results from earlier
         poll calls - manoj */
      while (1) {
          workers_may_exit |= (ap_max_requests_per_child != 0) && (requests_this_child <= 0);
          if (workers_may_exit) break;
  
          (void) ap_update_child_status(process_slot, thread_slot, SERVER_READY, 
                                        (request_rec *) NULL);
          if ((rv = SAFE_ACCEPT(apr_lock_acquire(accept_mutex)))
              != APR_SUCCESS) {
              ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
                           "apr_lock_acquire failed. Attempting to shutdown "
                           "process gracefully.");
              workers_may_exit = 1;
          }
  
          while (!workers_may_exit) {
  	    apr_status_t ret;
  	    apr_int16_t event;
  
              ret = apr_poll(pollset, &n, -1);
              if (ret != APR_SUCCESS) {
                  if (APR_STATUS_IS_EINTR(ret)) {
                      continue;
                  }
  
                  /* apr_poll() will only return errors in catastrophic
                   * circumstances. Let's try exiting gracefully, for now. */
                  ap_log_error(APLOG_MARK, APLOG_ERR, ret, (const server_rec *)
                               ap_server_conf, "apr_poll: (listen)");
                  workers_may_exit = 1;
              }
  
              if (workers_may_exit) break;
  
  	    apr_poll_revents_get(&event, listensocks[0], pollset);
              if (event & APR_POLLIN) {
                  /* A process got a signal on the shutdown pipe. Check if we're
                   * the lucky process to die. */
                  check_pipe_of_death();
                  continue;
              }
  
              if (num_listensocks == 1) {
                  sd = ap_listeners->sd;
                  goto got_fd;
              }
              else {
                  /* find a listener */
                  curr_pollfd = last_pollfd;
                  do {
                      curr_pollfd++;
                      if (curr_pollfd > num_listensocks) {
                          curr_pollfd = 1;
                      }
                      /* XXX: Should we check for POLLERR? */
  		    apr_poll_revents_get(&event, listensocks[curr_pollfd], pollset);
                      if (event & APR_POLLIN) {
                          last_pollfd = curr_pollfd;
  			sd=listensocks[curr_pollfd];
                          goto got_fd;
                      }
                  } while (curr_pollfd != last_pollfd);
              }
          }
      got_fd:
          if (!workers_may_exit) {
              if ((rv = apr_accept(&csd, sd, ptrans)) != APR_SUCCESS) {
                  csd = NULL;
                  ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, 
                               "apr_accept");
              }
              if ((rv = SAFE_ACCEPT(apr_lock_release(accept_mutex)))
                  != APR_SUCCESS) {
                  ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
                               "apr_lock_release failed. Attempting to shutdown "
                               "process gracefully.");
                  workers_may_exit = 1;
              }
              if (csd != NULL) {
                  process_socket(ptrans, csd, process_slot, thread_slot);
                  requests_this_child--;
              }
          }
          else {
              if ((rv = SAFE_ACCEPT(apr_lock_release(accept_mutex)))
                  != APR_SUCCESS) {
                  ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
                               "apr_lock_release failed. Attempting to shutdown "
                               "process gracefully.");
                  workers_may_exit = 1;
              }
              break;
          }
          apr_clear_pool(ptrans);
      }
  
      apr_pool_destroy(tpool);
      ap_update_child_status(process_slot, thread_slot, SERVER_DEAD,
          (request_rec *) NULL);
      pthread_mutex_lock(&worker_thread_count_mutex);
      worker_thread_count--;
      if (worker_thread_count == 0) {
          /* All the threads have exited, now finish the shutdown process
           * by signalling the sigwait thread */
          kill(ap_my_pid, SIGTERM);
      }
      pthread_mutex_unlock(&worker_thread_count_mutex);
  
      return NULL;
  }
  
  
  static void child_main(int child_num_arg)
  {
      sigset_t sig_mask;
      int signal_received;
      pthread_t thread;
      pthread_attr_t thread_attr;
      int i;
      int my_child_num = child_num_arg;
      proc_info *my_info = NULL;
      ap_listen_rec *lr;
      apr_status_t rv;
  
  
      ap_my_pid = getpid();
      apr_pool_create(&pchild, pconf);
  
      /*stuff to do before we switch id's, so we have permissions.*/
      reopen_scoreboard(pchild);
  
      rv = SAFE_ACCEPT(apr_lock_child_init(&accept_mutex, lock_fname,
                       pchild));
      if (rv != APR_SUCCESS) {
          ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
                       "Couldn't initialize cross-process lock in child");
          clean_child_exit(APEXIT_CHILDFATAL);
      }
  
      if (unixd_setup_child()) {
  	clean_child_exit(APEXIT_CHILDFATAL);
      }
  
      ap_child_init_hook(pchild, ap_server_conf);
  
      /*done with init critical section */
  
      /* All threads should mask signals out, accoring to sigwait(2) man page */
      sigfillset(&sig_mask);
  
  #ifdef SIGPROCMASK_SETS_THREAD_MASK
      if (sigprocmask(SIG_SETMASK, &sig_mask, NULL) != 0) {
          ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf, "sigprocmask");
      }
  #else
      if ((rv = pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) != 0) {
  #ifdef PTHREAD_SETS_ERRNO
          rv = errno;
  #endif
          ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, "pthread_sigmask");
      }
  #endif
  
      requests_this_child = ap_max_requests_per_child;
      
      /* Set up the pollfd array */
      listensocks = apr_pcalloc(pchild,
  			    sizeof(*listensocks) * (num_listensocks + 1));
  #if APR_FILES_AS_SOCKETS
      apr_socket_from_file(&listensocks[0], pipe_of_death_in);
  #endif
      for (lr = ap_listeners, i = 1; i <= num_listensocks; lr = lr->next, ++i)
  	listensocks[i]=lr->sd;
  
      /* Setup worker threads */
  
      worker_thread_count = 0;
      pthread_mutex_init(&worker_thread_count_mutex, NULL);
      pthread_mutex_init(&pipe_of_death_mutex, NULL);
      pthread_attr_init(&thread_attr);
  #ifdef PTHREAD_ATTR_SETDETACHSTATE_ARG2_ADDR
      {
          int on = 1;
  
          pthread_attr_setdetachstate(&thread_attr, &on);
      }
  #else
      pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
  #endif
      for (i=0; i < ap_threads_per_child; i++) {
  
  	my_info = (proc_info *)malloc(sizeof(proc_info));
          if (my_info == NULL) {
              ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,
  		         "malloc: out of memory");
              clean_child_exit(APEXIT_CHILDFATAL);
          }
  	my_info->pid = my_child_num;
          my_info->tid = i;
  	my_info->sd = 0;
  	apr_pool_create(&my_info->tpool, pchild);
  	
  	/* We are creating threads right now */
  	(void) ap_update_child_status(my_child_num, i, SERVER_STARTING, 
  				      (request_rec *) NULL);
  #ifndef NO_THREADS
  	if ((rv = pthread_create(&thread, &thread_attr, worker_thread, my_info))) {
  #ifdef PTHREAD_SETS_ERRNO
              rv = errno;
  #endif
  	    ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
  			 "pthread_create: unable to create worker thread");
              /* 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 if we exit. */
              sleep(10);
  	    clean_child_exit(APEXIT_CHILDFATAL);
  	}
  #else
  	worker_thread(my_info);
  	/* The SIGTERM shouldn't let us reach this point, but just in case... */
  	clean_child_exit(APEXIT_OK);
  #endif
  
  	/* We let each thread update it's own scoreboard entry.  This is done
  	 * because it let's us deal with tid better.
  	 */
      }
  
      pthread_attr_destroy(&thread_attr);
  
      /* This thread will be the one responsible for handling signals */
      sigemptyset(&sig_mask);
      sigaddset(&sig_mask, SIGTERM);
      sigaddset(&sig_mask, SIGINT);
      ap_sigwait(&sig_mask, &signal_received);
      switch (signal_received) {
          case SIGTERM:
          case SIGINT:
              just_die(signal_received);
              break;
          default:
              ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,
              "received impossible signal: %d", signal_received);
              just_die(SIGTERM);
      }
  }
  
  static int make_child(server_rec *s, int slot) 
  {
      int pid;
  
      if (slot + 1 > ap_max_daemons_limit) {
  	ap_max_daemons_limit = slot + 1;
      }
  
      if (one_process) {
  	set_signals();
          ap_scoreboard_image->parent[slot].pid = getpid();
  	child_main(slot);
      }
  
      /* Tag this slot as occupied so that perform_idle_server_maintenance
       * doesn't try to steal it */
      (void) ap_update_child_status(slot, 0, SERVER_STARTING, (request_rec *) NULL);
  
      if ((pid = fork()) == -1) {
          ap_log_error(APLOG_MARK, APLOG_ERR, errno, 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, 0, SERVER_DEAD, (request_rec *) NULL);
  
  	/* 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, errno, ap_server_conf,
  			 "processor unbind failed %d", status);
  #endif
  
          RAISE_SIGSTOP(MAKE_CHILD);
  
          apr_signal(SIGTERM, just_die);
          child_main(slot);
  
  	return 0;
      }
      /* else */
      ap_scoreboard_image->parent[slot].pid = pid;
      return 0;
  }
  
  /* start up a bunch of children */
  static void startup_children(int number_to_start)
  {
      int i;
  
      for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
  	if (ap_scoreboard_image->parent[i].pid != 0) {
  	    continue;
  	}
  	if (make_child(ap_server_conf, i) < 0) {
  	    break;
  	}
  	--number_to_start;
      }
  }
  
  
  /*
   * 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 idle_thread_count;
      short_score *ss;
      int free_length;
      int free_slots[MAX_SPAWN_RATE];
      int last_non_dead;
      int total_non_dead;
      apr_size_t one = 1;
      apr_status_t rv;
  
      /* initialize the free_list */
      free_length = 0;
  
      idle_thread_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;
  	int idle_thread_addition = 0;
  
  	if (i >= ap_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_addition;
  	    }
  	}
  	if (all_dead_threads && free_length < idle_spawn_rate) {
  	    free_slots[free_length] = i;
  	    ++free_length;
  	}
  	if (!all_dead_threads) {
              last_non_dead = i;
  	}
          if (!any_dying_threads) {
              ++total_non_dead;
  	    idle_thread_count += idle_thread_addition;
          }
      }
      ap_max_daemons_limit = last_non_dead + 1;
  
      if (idle_thread_count > max_spare_threads) {
          /* Kill off one child */
          char char_of_death = '!';
          if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) != APR_SUCCESS) {
              ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, "write pipe_of_death");
          }
          idle_spawn_rate = 1;
      }
      else if (idle_thread_count < min_spare_threads) {
          /* 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, 0, ap_server_conf,
  			     "server reached MaxClients setting, consider"
  			     " raising the MaxClients setting");
  		reported = 1;
  	    }
  	    idle_spawn_rate = 1;
  	}
  	else {
  	    
  	    if (idle_spawn_rate >= 8) {
  	        ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf,
  			     "server seems busy, (you may need "
  			     "to increase StartServers, ThreadsPerChild "
                               "or Min/MaxSpareThreads), "
  			     "spawning %d children, there are around %d idle "
                               "threads, and %d total children", idle_spawn_rate,
  			     idle_thread_count, total_non_dead);
  	    }
  	    for (i = 0; i < free_length; ++i) {
  	        make_child(ap_server_conf, free_slots[i]);
  	    }
  	    /* 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;
      }
  }
  
  static void server_main_loop(int remaining_children_to_start)
  {
      int child_slot;
      apr_wait_t status;
      apr_proc_t pid;
      int i;
  
      while (!restart_pending && !shutdown_pending) {
          ap_wait_or_timeout(&status, &pid, pconf);
          
          if (pid.pid != -1) {
              ap_process_child_status(&pid, status);
              /* non-fatal death... note that it's gone in the scoreboard. */
              child_slot = find_child_by_pid(&pid);
              if (child_slot >= 0) {
                  for (i = 0; i < ap_threads_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
                       */
  		    make_child(ap_server_conf, child_slot);
  		    --remaining_children_to_start;
  		}
  #if APR_HAS_OTHER_CHILD
  	    }
  	    else if (apr_proc_other_child_read(&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, 0,
  		             ap_server_conf,
  		             "long lost child came home! (pid %ld)",
  		             (long)pid.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();
      }
  }
  
  int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
  {
      int remaining_children_to_start;
      apr_status_t rv;
      apr_size_t one = 1;
  
      pconf = _pconf;
      ap_server_conf = s;
      rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out, pconf);
      if (rv != APR_SUCCESS) {
          ap_log_error(APLOG_MARK, APLOG_ERR, rv,
                       (const server_rec*) ap_server_conf,
                       "apr_file_pipe_create (pipe_of_death)");
          exit(1);
      }
  
      if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) {
          ap_log_error(APLOG_MARK, APLOG_ERR, rv,
                       (const server_rec*) ap_server_conf,
                       "apr_file_pipe_timeout_set (pipe_of_death)");
          exit(1);
      }
      ap_server_conf = s;
      if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
          /* XXX: hey, what's the right way for the mpm to indicate a fatal error? */
          ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s,
              "no listening sockets available, shutting down");
          return 1;
      }
      ap_log_pid(pconf, ap_pid_fname);
  
      /* Initialize cross-process accept lock */
      lock_fname = apr_psprintf(_pconf, "%s.%u",
                               ap_server_root_relative(_pconf, lock_fname),
                               ap_my_pid);
      rv = apr_lock_create(&accept_mutex, APR_MUTEX, APR_LOCKALL,
                     lock_fname, _pconf);
      if (rv != APR_SUCCESS) {
          ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
                       "Couldn't create accept lock");
          return 1;
      }
  
  
      if (!is_graceful) {
          ap_create_scoreboard(pconf, SB_SHARED);
      }
  
      set_signals();
      /* Don't thrash... */
      if (max_spare_threads < min_spare_threads + ap_threads_per_child)
  	max_spare_threads = min_spare_threads + ap_threads_per_child;
  
      /* 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, 0, ap_server_conf,
  		"%s configured -- resuming normal operations",
  		ap_get_server_version());
      ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf,
  		"Server built: %s", ap_get_server_built());
      restart_pending = shutdown_pending = 0;
  
      server_main_loop(remaining_children_to_start);
  
      if (shutdown_pending) {
          /* Time to gracefully shut down:
           * Kill child processes, tell them to call child_exit, etc...
           */
          if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
              ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM");
          }
          ap_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, 0,
              		 ap_server_conf,
              		 "removed PID file %s (pid=%ld)",
              		 pidfile, (long)getpid());
          }
      
          ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
              "caught SIGTERM, shutting down");
      
  	return 1;
      }
  
      /* we've been told to restart */
      apr_signal(SIGHUP, SIG_IGN);
  
      if (one_process) {
  	/* not worth thinking about */
  	return 1;
      }
  
      /* 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;
          char char_of_death = '!';
  
  	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
  		    "SIGWINCH received.  Doing graceful restart");
  
  	/* give the children the signal to die */
          for (i = 0; i < ap_daemons_limit;) {
              if ((rv = apr_file_write(pipe_of_death_in, &char_of_death, &one)) != APR_SUCCESS) {
                  if (APR_STATUS_IS_EINTR(rv)) continue;
                  ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, "write pipe_of_death");
              }
              i++;
          }
  
  	/* 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_per_child; 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 (unixd_killpg(getpgrp(), SIGTERM) < 0) {
  	    ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM");
  	}
          ap_reclaim_child_processes(1);		/* Start with SIGTERM */
  	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
  		    "SIGHUP received.  Attempting to restart");
      }
      return 0;
  }
  
  static void threaded_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
  {
      static int restart_num = 0;
      int no_detach = 0;
  
      one_process = !!ap_exists_config_define("ONE_PROCESS");
      no_detach = !!ap_exists_config_define("NO_DETACH");
  
      /* sigh, want this only the second time around */
      if (restart_num++ == 1) {
  	is_graceful = 0;
  
  	if (!one_process && !no_detach) {
  	    apr_proc_detach();
  	}
  	ap_my_pid = getpid();
      }
  
      unixd_pre_config(ptemp);
      ap_listen_pre_config();
      ap_daemons_to_start = DEFAULT_START_DAEMON;
      min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
      max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD;
      ap_daemons_limit = HARD_SERVER_LIMIT;
      ap_threads_per_child = DEFAULT_THREADS_PER_CHILD;
      ap_pid_fname = DEFAULT_PIDLOG;
      ap_scoreboard_fname = DEFAULT_SCOREBOARD;
      lock_fname = DEFAULT_LOCKFILE;
      ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
      ap_extended_status = 0;
  
      apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
  }
  
  static void threaded_hooks(apr_pool_t *p)
  {
      one_process = 0;
  
      ap_hook_pre_config(threaded_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
  }
  
  
  static const char *set_pidfile(cmd_parms *cmd, void *dummy, const char *arg) 
  {
      const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
      if (err != NULL) {
          return err;
      }
  
      if (cmd->server->is_virtual) {
  	return "PidFile directive not allowed in <VirtualHost>";
      }
      ap_pid_fname = arg;
      return NULL;
  }
  
  static const char *set_scoreboard(cmd_parms *cmd, void *dummy,
  				  const char *arg) 
  {
      const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
      if (err != NULL) {
          return err;
      }
  
      ap_scoreboard_fname = arg;
      return NULL;
  }
  
  static const char *set_lockfile(cmd_parms *cmd, void *dummy, const char *arg) 
  {
      const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
      if (err != NULL) {
          return err;
      }
  
      lock_fname = arg;
      return NULL;
  }
  
  static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy,
  					const char *arg) 
  {
      const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
      if (err != NULL) {
          return err;
      }
  
      ap_daemons_to_start = atoi(arg);
      return NULL;
  }
  
  static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy,
  					 const char *arg)
  {
      const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
      if (err != NULL) {
          return err;
      }
  
      min_spare_threads = atoi(arg);
      if (min_spare_threads <= 0) {
         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                      "WARNING: detected MinSpareThreads set to non-positive.");
         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                      "Resetting to 1 to avoid almost certain Apache failure.");
         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                      "Please read the documentation.");
         min_spare_threads = 1;
      }
         
      return NULL;
  }
  
  static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy,
  					 const char *arg)
  {
      const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
      if (err != NULL) {
          return err;
      }
  
      max_spare_threads = atoi(arg);
      return NULL;
  }
  
  static const char *set_server_limit (cmd_parms *cmd, void *dummy,
  				     const char *arg) 
  {
      const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
      if (err != NULL) {
          return err;
      }
  
      ap_daemons_limit = atoi(arg);
      if (ap_daemons_limit > HARD_SERVER_LIMIT) {
         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                      "WARNING: MaxClients of %d exceeds compile time limit "
                      "of %d servers,", ap_daemons_limit, HARD_SERVER_LIMIT);
         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                      " lowering MaxClients to %d.  To increase, please "
                      "see the", HARD_SERVER_LIMIT);
         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                      " HARD_SERVER_LIMIT define in %s.",
                      AP_MPM_HARD_LIMITS_FILE);
         ap_daemons_limit = HARD_SERVER_LIMIT;
      } 
      else if (ap_daemons_limit < 1) {
  	ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "WARNING: Require MaxClients > 0, setting to 1");
  	ap_daemons_limit = 1;
      }
      return NULL;
  }
  
  static const char *set_threads_per_child (cmd_parms *cmd, void *dummy,
  					  const char *arg) 
  {
      const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
      if (err != NULL) {
          return err;
      }
  
      ap_threads_per_child = atoi(arg);
      if (ap_threads_per_child > HARD_THREAD_LIMIT) {
          ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                       "WARNING: ThreadsPerChild of %d exceeds compile time"
                       "limit of %d threads,", ap_threads_per_child,
                       HARD_THREAD_LIMIT);
          ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                       " lowering ThreadsPerChild to %d. To increase, please"
                       " see the", HARD_THREAD_LIMIT);
          ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                       " HARD_THREAD_LIMIT define in %s.",
                       AP_MPM_HARD_LIMITS_FILE);
      }
      else if (ap_threads_per_child < 1) {
  	ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                       "WARNING: Require ThreadsPerChild > 0, setting to 1");
  	ap_threads_per_child = 1;
      }
      return NULL;
  }
  
  static const char *set_max_requests(cmd_parms *cmd, void *dummy,
  				    const char *arg) 
  {
      const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
      if (err != NULL) {
          return err;
      }
  
      ap_max_requests_per_child = atoi(arg);
  
      return NULL;
  }
  
  static const char *set_coredumpdir (cmd_parms *cmd, void *dummy,
  				    const char *arg) 
  {
      apr_finfo_t finfo;
      const char *fname;
      const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
      if (err != NULL) {
          return err;
      }
  
      fname = ap_server_root_relative(cmd->pool, arg);
      if ((apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) 
          || (finfo.filetype != APR_DIR)) {
  	return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, 
  			  " does not exist or is not a directory", NULL);
      }
      apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
      return NULL;
  }
  
  static const command_rec threaded_cmds[] = {
  UNIX_DAEMON_COMMANDS
  LISTEN_COMMANDS
  AP_INIT_TAKE1("PidFile", set_pidfile, NULL, RSRC_CONF,
      "A file for logging the server process ID"),
  AP_INIT_TAKE1("ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF,
      "A file for Apache to maintain runtime process management information"),
  AP_INIT_TAKE1("LockFile", set_lockfile, NULL, RSRC_CONF,
      "The lockfile used when Apache needs to lock the accept() call"),
  AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF,
    "Number of child processes launched at server startup"),
  AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF,
    "Minimum number of idle children, to handle request spikes"),
  AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF,
    "Maximum number of idle children"),
  AP_INIT_TAKE1("MaxClients", set_server_limit, NULL, RSRC_CONF,
    "Maximum number of children alive at the same time"),
  AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF,
    "Number of threads each child creates"),
  AP_INIT_TAKE1("MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF,
    "Maximum number of requests a particular child serves before dying."),
  AP_INIT_TAKE1("CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF,
    "The location of the directory Apache changes to before dumping core"),
  { NULL }
  };
  
  module AP_MODULE_DECLARE_DATA mpm_threaded_module = {
      MPM20_MODULE_STUFF,
      NULL,                       /* hook to run before apache parses args */
      NULL,			/* create per-directory config structure */
      NULL,			/* merge per-directory config structures */
      NULL,			/* create per-server config structure */
      NULL,			/* merge per-server config structures */
      threaded_cmds,		/* command apr_table_t */
      threaded_hooks		/* register_hooks */
  };
  
  
  
  

Mime
View raw message