spmt_os2.c revision cc910c475085f94bd30fc1b6e16363872424f780
698N/A/* ==================================================================== 698N/A * Copyright (c) 1995-1999 The Apache Group. All rights reserved. 698N/A * Redistribution and use in source and binary forms, with or without 698N/A * modification, are permitted provided that the following conditions 698N/A * 1. Redistributions of source code must retain the above copyright 698N/A * notice, this list of conditions and the following disclaimer. 698N/A * 2. Redistributions in binary form must reproduce the above copyright 698N/A * notice, this list of conditions and the following disclaimer in 698N/A * the documentation and/or other materials provided with the 698N/A * 3. All advertising materials mentioning features or use of this 698N/A * software must display the following acknowledgment: 698N/A * "This product includes software developed by the Apache Group 698N/A * 4. The names "Apache Server" and "Apache Group" must not be used to 698N/A * endorse or promote products derived from this software without 698N/A * prior written permission. For written permission, please contact 698N/A * 5. Products derived from this software may not be called "Apache" 698N/A * nor may "Apache" appear in their names without prior written 698N/A * permission of the Apache Group. * 6. Redistributions of any form whatsoever must retain the following * "This product includes software developed by the Apache Group * 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 * The max child slot ever assigned, preserved across restarts. Necessary * to deal with MaxClients changes across SIGUSR1 restarts. We use this * value to optimize routines that have to scan the entire scoreboard. /* *Non*-shared http_main globals... */ /* 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.). /* used to maintain list of children which aren't part of the scoreboard */ static pool *
pconf;
/* Pool for config stuff */ /* a clean exit from a child with proper cleanup */ * Done by each child at it's birth "Child cannot open lock semaphore, rc=%d",
rc);
* Must be safe to call this on a restart. "Parent cannot create lock semaphore, rc=%d",
rc);
"OS2SEM: Error %d getting accept lock. Exiting!",
rc);
"OS2SEM: Error %d freeing accept lock. Exiting!",
rc);
/* On some architectures it's safe to do unserialized accept()s in the single * Listen case. But it's never safe to do it in the case where there's * multiple Listen statements. Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT * when it's safe in the single Listen case. /***************************************************************** * dealing with other children /* 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. /* XXX: um, well we've just wasted some space in pconf ? */ /* test to ensure that the write_fds are all still writable, otherwise * invoke the maintenance functions as appropriate */ /* XXX: uhh this could be really bad, we could have a bad file * descriptor due to a bug in one of the maintenance routines */ /* possibly reap an other_child, return 0 if yes, -1 if not */ * Reset individual counters /* Don't reveal the password in the server-status view */ /* clean up the slot's vhostrec pointer (maybe re-used) * and mark the slot as belonging to a new generation. /* TODO: call me some time */ /* Finally, this routine is used by the caretaker thread to wait for /* number of calls to wait_or_timeout between writable probes */ #
define NumSIG 32 /* for 1998's unixes, this is still a good assumption */#
else /* platform has no sys_siglist[], define our own */#
endif /* platform has sys_siglist[] *//* handle all varieties of core dumping signals */ /* 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... /* volatile just in case */ /* 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. /* Probably not an error - don't bother reporting it */ /* we want to ignore HUPs and USR1 while we're busy processing one */ /* 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. "setsockopt: (TCP_NODELAY)");
/***************************************************************** * Child process main loop. /* Disable the restart signal handlers and enable the just_die stuff. * Note that since restart() just notes that a restart has been * requested there's no race condition here. set_signals();
/* signals aren't inherrited by child threads */ /* Get a sub pool for global allocations in this child, so that * we can have cleanups occur when the child exits. /* needs to be done before we switch UIDs so we have permissions */ /* Prepare to receive a SIGUSR1 due to graceful restart so that * (Re)initialize this child to a pre-connection state. * Wait for an acceptable connection to arrive. /* Lock around "accept", if necessary */ /* more than one socket */ /* Single Unix documents select as returning errnos * EBADF, EINTR, and EINVAL... and in none of those * cases does it make sense to continue. In fact * on Linux 2.0.x we seem to end up with EFAULT * occasionally, and we'd loop forever due to it. /* we remember the last_lr we searched last time around so that we don't end up starving any particular listening socket */ /* only one socket, just pretend we did the other stuff */ /* if we accept() something we don't want to die, so we have to /* we didn't get a socket, and we were told to die */ break;
/* We have a socket ready for reading */ /* 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. /* EPROTO on certain older kernels really means * ECONNABORTED, so we need to ignore it for them. * See discussion in new-httpd archives nh.9701 * 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. /* 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 "accept: (client socket)");
/* We've got a socket, let's at least process one request off the * socket before we accept a graceful restart request. We set * the signal to ignore because we don't want to disturb any * We now have a connection, so set it up with the appropriate * socket options, file descriptors, and read/write buffers. "filedescriptor (%u) larger than FD_SETSIZE (%u) " "found, you probably need to rebuild Apache with a " "error attaching to socket");
/* _beginthread didn't succeed. Fix the scoreboard or else * it will say SERVER_STARTING forever and ever /* In case system resources are maxxed out, we don't want Apache running away with the CPU trying to _beginthread over and /* start up a bunch of children */ * 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. /* initialize the free_list */ /* try to keep children numbers as low as possible */ /* 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. /* 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). /* kill off one child... we use SIGUSR1 because that'll cause it to * shut down gracefully, in case it happened to pick up a request /* terminate the free list */ /* only report this condition once */ "server reached MaxClients setting, consider" " raising the MaxClients setting");
"server seems busy, (you may need " "spawning %d children, there are %d idle, and " /* 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 /* Child died... if it died due to a fatal error, * we should simply bail out. "Child %d returned a Fatal error... \n" "child tid %d exit signal %s (%d), " "possible coredump in %s",
"child tid %d exit signal %s (%d)",
tid,
"child tid %d exit signal %d",
"no listening sockets available, shutting down");
/***************************************************************** /* XXX: hey, what's the right way for the mpm to indicate a fatal error? */ "Error allocating thread local storage" /* 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 SIGUSR1). 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. /* give the system some time to recover before kicking into "%s configured -- resuming normal operations",
/* XXX: if it takes longer than 1 second for all our children * to start up and get into IDLE state then we may spawn an /* non-fatal death... note that it's gone in the scoreboard. */ /* we're still doing a 1-for-1 replacement of dead * children with new children /* TODO: this won't work, we waited on a thread not a process else if (reap_other_child(pid, status) == 0) { /* Great, we've probably just lost a slot in the * scoreboard. Somehow we don't know about this "long lost child came home! (tid %d)",
tid);
/* 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. /* 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. /* 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. /* Time to gracefully shut down: * Don't worry about killing child threads for now, the all die when the parent exits /* cleanup pid file on normal shutdown */ "removed PID file %s (pid=%ld)",
"caught SIGTERM, shutting down");
/* we've been told to restart */ /* not worth thinking about */ /* 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. "SIGUSR1 received. Doing graceful restart");
/* kill off the idle ones */ /* This is mostly for debugging... so that we know what is still * gracefully dealing with existing request. But we can't really * do it if we're in a SCOREBOARD_FILE because it'll cause "SIGHUP received. Attempting to restart");
return "PidFile directive not allowed in <VirtualHost>";
fprintf(
stderr,
"WARNING: detected MinSpareServers set to non-positive.\n");
fprintf(
stderr,
"Resetting to 1 to avoid almost certain Apache failure.\n");
fprintf(
stderr,
"WARNING: MaxClients of %d exceeds compile time limit " fprintf(
stderr,
" lowering MaxClients to %d. To increase, please " fprintf(
stderr,
"WARNING: Require MaxClients > 0, setting to 1\n");
/* ZZZ change this to the AP func FileInfo*/ " does not exist or is not a directory",
NULL);
"A file for logging the server process ID"},
"Number of child processes launched at server startup" },
"Minimum number of idle children, to handle request spikes" },
"Maximum number of idle children" },
"Maximum number of children alive at the same time" },
"Maximum number of requests a particular child serves before dying." },
"The location of the directory Apache changes to before dumping core" },
NULL,
/* create per-directory config structure */ NULL,
/* merge per-directory config structures */ NULL,
/* create per-server config structure */ NULL,
/* merge per-server config structures */ NULL,
/* pre-run fixups */