dgaudet 99/06/20 14:46:14
Modified: mpm/src CHANGES
mpm/src/include alloc.h
mpm/src/main alloc.c mpm_prefork.c
Log:
remove 1.3 timeout code; SIGUSR1/SIGHUP/SIGTERM working again
Revision Changes Path
1.7 +3 -0 apache-2.0/mpm/src/CHANGES
Index: CHANGES
===================================================================
RCS file: /home/cvs/apache-2.0/mpm/src/CHANGES,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- CHANGES 1999/06/20 21:12:47 1.6
+++ CHANGES 1999/06/20 21:46:11 1.7
@@ -1,5 +1,8 @@
Changes with MPM
+ * mpm_prefork: throw away all the alarm/timeout crud; and clean up the
+ signal handling for the new world order. [Dean Gaudet]
+
* Crude ap_thread_mutex abstraction so that we get the pthread stuff out
of alloc.c for now. [Dean Gaudet]
1.2 +0 -22 apache-2.0/mpm/src/include/alloc.h
Index: alloc.h
===================================================================
RCS file: /home/cvs/apache-2.0/mpm/src/include/alloc.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- alloc.h 1999/06/18 18:39:27 1.1
+++ alloc.h 1999/06/20 21:46:12 1.2
@@ -287,10 +287,6 @@
*
* Cleanups are identified for purposes of finding & running them off by the
* plain_cleanup and data, which should presumably be unique.
- *
- * NB any code which invokes register_cleanup or kill_cleanup directly
- * is a critical section which should be guarded by block_alarms() and
- * unblock_alarms() below...
*/
API_EXPORT(void) ap_register_cleanup(pool *p, void *data,
@@ -303,24 +299,6 @@
/* A "do-nothing" cleanup, for register_cleanup; it's faster to do
* things this way than to test for NULL. */
API_EXPORT_NONSTD(void) ap_null_cleanup(void *data);
-
-/* The time between when a resource is actually allocated, and when it
- * its cleanup is registered is a critical section, during which the
- * resource could leak if we got interrupted or timed out. So, anything
- * which registers cleanups should bracket resource allocation and the
- * cleanup registry with these. (This is done internally by run_cleanup).
- *
- * NB they are actually implemented in http_main.c, since they are bound
- * up with timeout handling in general...
- */
-
-#ifdef TPF
-#define ap_block_alarms() (0)
-#define ap_unblock_alarms() (0)
-#else
-API_EXPORT(void) ap_block_alarms(void);
-API_EXPORT(void) ap_unblock_alarms(void);
-#endif /* TPF */
/* Common cases which want utility support..
* the note_cleanups_for_foo routines are for
1.3 +4 -4 apache-2.0/mpm/src/main/alloc.c
Index: alloc.c
===================================================================
RCS file: /home/cvs/apache-2.0/mpm/src/main/alloc.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- alloc.c 1999/06/20 21:12:49 1.2
+++ alloc.c 1999/06/20 21:46:12 1.3
@@ -303,7 +303,7 @@
#define test_is_free(_x)
#endif
-/* Free a chain of blocks --- must be called with alarms blocked. */
+/* Free a chain of blocks --- must be called with mutex held. */
#ifdef POOL_DEBUG
#define reset_block(b) do { \
test_is_free(b); \
@@ -383,7 +383,7 @@
/* Get a new block, from our own free list if possible, from the system
- * if necessary. Must be called with alarms blocked.
+ * if necessary. Must be called with mutex held.
*/
static union block_hdr *new_block(int min_size)
@@ -873,8 +873,8 @@
* until all the output is done.
*
* Note that this is completely safe because nothing else can
- * allocate in this pool while ap_psprintf is running. alarms are
- * blocked, and the only thing outside of alloc.c that's invoked
+ * allocate in this pool while ap_psprintf is running.
+ * The only thing outside of alloc.c that's invoked
* is ap_vformatter -- which was purposefully written to be
* self-contained with no callouts.
*/
1.5 +21 -348 apache-2.0/mpm/src/main/mpm_prefork.c
Index: mpm_prefork.c
===================================================================
RCS file: /home/cvs/apache-2.0/mpm/src/main/mpm_prefork.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- mpm_prefork.c 1999/06/20 21:12:50 1.4
+++ mpm_prefork.c 1999/06/20 21:46:13 1.5
@@ -82,7 +82,6 @@
* TODO: behave like apache-1.3... here's a short list of things I think
* TODO: need cleaning up still:
* TODO: - use ralf's mm stuff for the shared mem and mutexes
- * TODO: - eliminate the timeout stuff... 2.0 timeouts are part of the BUFF
* TODO: - abstract the Listen stuff, it's going to be common with other MPM
* TODO: - clean up scoreboard stuff when we figure out how to do it in 2.0
*/
@@ -161,7 +160,6 @@
/* *Non*-shared http_main globals... */
static server_rec *server_conf;
-static JMP_BUF jmpbuffer;
static int sd;
static fd_set listenfds;
static int listenmaxfd;
@@ -180,11 +178,6 @@
static int one_process = 0;
-/* set if timeouts are to be handled by the children and not by the parent.
- * i.e. child_timeouts = !standalone || one_process.
- */
-static int child_timeouts;
-
#ifdef HAS_OTHER_CHILD
/* used to maintain list of children which aren't part of the scoreboard */
typedef struct other_child_rec other_child_rec;
@@ -804,220 +797,7 @@
#define SAFE_ACCEPT(stmt) do {stmt;} while(0)
#endif
-/*****************************************************************
- *
- * Timeout handling. DISTINCTLY not thread-safe, but all this stuff
- * has to change for threads anyway. Note that this code allows only
- * one timeout in progress at a time...
- */
-
-static conn_rec *volatile current_conn;
-static request_rec *volatile timeout_req;
-static const char *volatile timeout_name = NULL;
-static int volatile alarms_blocked = 0;
-static int volatile alarm_pending = 0;
-
-static void timeout(int sig)
-{
- void *dirconf;
-
- if (alarms_blocked) {
- alarm_pending = 1;
- return;
- }
- if (exit_after_unblock) {
- clean_child_exit(0);
- }
-
- if (!current_conn) {
- ap_longjmp(jmpbuffer, 1);
- }
-
- if (timeout_req != NULL)
- dirconf = timeout_req->per_dir_config;
- else
- dirconf = current_conn->base_server->lookup_defaults;
- if (!current_conn->keptalive) {
- ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,
- current_conn->base_server, "[client %s] %s timed out",
- current_conn->remote_ip,
- timeout_name ? timeout_name : "request");
- }
-
- if (timeout_req) {
- /* Someone has asked for this transaction to just be aborted
- * if it times out...
- */
-
- request_rec *log_req = timeout_req;
- request_rec *save_req = timeout_req;
-
- /* avoid looping... if ap_log_transaction started another
- * timer (say via rfc1413.c) we could loop...
- */
- timeout_req = NULL;
-
- while (log_req->main || log_req->prev) {
- /* Get back to original request... */
- if (log_req->main)
- log_req = log_req->main;
- else
- log_req = log_req->prev;
- }
-
- if (!current_conn->keptalive) {
- /* in some cases we come here before setting the time */
- if (log_req->request_time == 0) {
- log_req->request_time = time(0);
- }
- ap_log_transaction(log_req);
- }
-
- ap_bsetflag(save_req->connection->client, B_EOUT, 1);
- ap_bclose(save_req->connection->client);
-
- ap_longjmp(jmpbuffer, 1);
- }
- else { /* abort the connection */
- ap_bsetflag(current_conn->client, B_EOUT, 1);
- ap_bclose(current_conn->client);
- current_conn->aborted = 1;
- }
-}
-
-#ifndef TPF
-/*
- * These two called from alloc.c to protect its critical sections...
- * Note that they can nest (as when destroying the sub_pools of a pool
- * which is itself being cleared); we have to support that here.
- */
-
-API_EXPORT(void) ap_block_alarms(void)
-{
- ++alarms_blocked;
-}
-
-API_EXPORT(void) ap_unblock_alarms(void)
-{
- --alarms_blocked;
- if (alarms_blocked == 0) {
- if (exit_after_unblock) {
- /* We have a couple race conditions to deal with here, we can't
- * allow a timeout that comes in this small interval to allow
- * the child to jump back to the main loop. Instead we block
- * alarms again, and then note that exit_after_unblock is
- * being dealt with. We choose this way to solve this so that
- * the common path through unblock_alarms() is really short.
- */
- ++alarms_blocked;
- exit_after_unblock = 0;
- clean_child_exit(0);
- }
- if (alarm_pending) {
- alarm_pending = 0;
- timeout(0);
- }
- }
-}
-#endif /* TPF */
-
-static void (*volatile alarm_fn) (int) = NULL;
-
-static void alrm_handler(int sig)
-{
- if (alarm_fn) {
- (*alarm_fn) (sig);
- }
-}
-
-unsigned int ap_set_callback_and_alarm(void (*fn) (int), int x)
-{
- unsigned int old;
-
- if (alarm_fn && x && fn != alarm_fn) {
- ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, NULL,
- "ap_set_callback_and_alarm: possible nested timer!");
- }
- alarm_fn = fn;
-#ifndef OPTIMIZE_TIMEOUTS
- old = alarm(x);
-#else
- if (child_timeouts) {
- old = alarm(x);
- }
- else {
- /* Just note the timeout in our scoreboard, no need to call the system.
- * We also note that the virtual time has gone forward.
- */
- ap_check_signals();
- old = ap_scoreboard_image->servers[my_child_num].timeout_len;
- ap_scoreboard_image->servers[my_child_num].timeout_len = x;
- ++ap_scoreboard_image->servers[my_child_num].cur_vtime;
- }
-#endif
- return (old);
-}
-
-
-/* reset_timeout (request_rec *) resets the timeout in effect,
- * as long as it hasn't expired already.
- */
-
-API_EXPORT(void) ap_reset_timeout(request_rec *r)
-{
- int i;
-
- if (timeout_name) { /* timeout has been set */
- i = ap_set_callback_and_alarm(alarm_fn, r->server->timeout);
- if (i == 0) /* timeout already expired, so set it back to 0
*/
- ap_set_callback_and_alarm(alarm_fn, 0);
- }
-}
-
-
-
-
-void ap_keepalive_timeout(char *name, request_rec *r)
-{
- unsigned int to;
- timeout_req = r;
- timeout_name = name;
-
- if (r->connection->keptalive)
- to = r->server->keep_alive_timeout;
- else
- to = r->server->timeout;
- ap_set_callback_and_alarm(timeout, to);
-
-}
-
-API_EXPORT(void) ap_hard_timeout(char *name, request_rec *r)
-{
- timeout_req = r;
- timeout_name = name;
-
- ap_set_callback_and_alarm(timeout, r->server->timeout);
-
-}
-
-API_EXPORT(void) ap_soft_timeout(char *name, request_rec *r)
-{
- timeout_name = name;
-
- ap_set_callback_and_alarm(timeout, r->server->timeout);
-
-}
-
-API_EXPORT(void) ap_kill_timeout(request_rec *dummy)
-{
- ap_check_signals();
- ap_set_callback_and_alarm(NULL, 0);
- timeout_req = NULL;
- timeout_name = NULL;
-}
-
-
/*****************************************************************
* dealing with other children
*/
@@ -1635,14 +1415,8 @@
ss = &ap_scoreboard_image->servers[child_num];
old_status = ss->status;
ss->status = status;
-#ifdef OPTIMIZE_TIMEOUTS
- ++ss->cur_vtime;
-#endif
if (ap_extended_status) {
-#ifndef OPTIMIZE_TIMEOUTS
- ss->last_used = time(NULL);
-#endif
if (status == SERVER_READY || status == SERVER_DEAD) {
/*
* Reset individual counters
@@ -2107,19 +1881,12 @@
*/
static void just_die(int sig)
-{ /* SIGHUP to child process??? */
- /* if alarms are blocked we have to wait to die otherwise we might
- * end up with corruption in alloc.c's internal structures */
- if (alarms_blocked) {
- exit_after_unblock = 1;
- }
- else {
- clean_child_exit(0);
- }
+{
+ clean_child_exit(0);
}
-static int volatile usr1_just_die = 1;
static int volatile deferred_die;
+static int volatile usr1_just_die;
static void usr1_handler(int sig)
{
@@ -2134,20 +1901,8 @@
static int volatile restart_pending;
static int volatile is_graceful;
ap_generation_t volatile ap_my_generation=0;
-
-/*
- * 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.
- */
-
-void ap_start_shutdown(void)
+static void sig_term(int sig)
{
if (shutdown_pending == 1) {
/* Um, is this _probably_ not an error, if the user has
@@ -2159,25 +1914,14 @@
shutdown_pending = 1;
}
-/* do a graceful restart if graceful == 1 */
-void ap_start_restart(int graceful)
+static void restart(int sig)
{
if (restart_pending == 1) {
/* Probably not an error - don't bother reporting it */
return;
}
restart_pending = 1;
- is_graceful = graceful;
-}
-
-static void sig_term(int sig)
-{
- ap_start_shutdown();
-}
-
-static void restart(int sig)
-{
- ap_start_restart(sig == SIGUSR1);
+ is_graceful = sig == SIGUSR1;
}
static void set_signals(void)
@@ -2484,11 +2228,9 @@
ap_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
/* note that because we're about to slack we don't use psocket */
- ap_block_alarms();
if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
"make_sock: failed to get a socket for %s", addr);
- ap_unblock_alarms();
exit(1);
}
@@ -2527,7 +2269,6 @@
ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
"make_sock: for %s, setsockopt: (SO_REUSEADDR)", addr);
close(s);
- ap_unblock_alarms();
return -1;
}
#endif /*_OSD_POSIX*/
@@ -2537,7 +2278,6 @@
ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
"make_sock: for %s, setsockopt: (SO_KEEPALIVE)", addr);
close(s);
- ap_unblock_alarms();
return -1;
}
#endif
@@ -2589,7 +2329,6 @@
GETUSERMODE();
#endif
close(s);
- ap_unblock_alarms();
exit(1);
}
#ifdef MPE
@@ -2601,7 +2340,6 @@
ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
"make_sock: unable to listen for connections on %s", addr);
close(s);
- ap_unblock_alarms();
exit(1);
}
@@ -2610,7 +2348,6 @@
ap_note_cleanups_for_socket(p, s); /* arrange to close on exec or
restart */
#endif
- ap_unblock_alarms();
#ifdef CHECK_FD_SETSIZE
/* protect various fd_sets */
@@ -2781,7 +2518,8 @@
int ap_mpm_graceful_stop(void)
{
ap_sync_scoreboard_image();
- if (ap_scoreboard_image->global.running_generation != ap_my_generation) {
+ if (deferred_die ||
+ ap_scoreboard_image->global.running_generation != ap_my_generation) {
return 1;
}
return 0;
@@ -2794,18 +2532,7 @@
struct sockaddr sa_client;
listen_rec *lr;
pool *ptrans;
-
- /* All of initialization is a critical section, we don't care if we're
- * told to HUP or USR1 before we're done initializing. For example,
- * we could be half way through ap_child_init_hook() when a restart
- * signal arrives, and we'd have no real way to recover gracefully
- * and exit properly.
- *
- * I suppose a module could take forever to initialize, but that would
- * be either a broken module, or a broken configuration (i.e. network
- * problems, file locking problems, whatever). -djg
- */
- ap_block_alarms();
+ conn_rec *current_conn;
my_pid = getpid();
csd = -1;
@@ -2851,26 +2578,10 @@
ap_child_init_hook(pchild, server_conf);
- /* done with the initialization critical section */
- ap_unblock_alarms();
-
(void) ap_update_child_status(my_child_num, SERVER_READY, (request_rec
*) NULL);
- /*
- * Setup the jump buffers so that we can return here after a timeout
- */
- ap_setjmp(jmpbuffer);
-#ifndef OS2
-#ifdef SIGURG
- signal(SIGURG, timeout);
-#endif
-#endif
- signal(SIGALRM, alrm_handler);
-#ifdef TPF
signal(SIGHUP, just_die);
signal(SIGTERM, just_die);
- signal(SIGUSR1, just_die);
-#endif /* TPF */
#ifdef OS2
/* Stop Ctrl-C/Ctrl-Break signals going to child processes */
@@ -2884,9 +2595,8 @@
BUFF *conn_io;
/* Prepare to receive a SIGUSR1 due to graceful restart so that
- * we can exit cleanly. Since we're between connections right
- * now it's the right time to exit, but we might be blocked in a
- * system call when the graceful restart request is made. */
+ * we can exit cleanly.
+ */
usr1_just_die = 1;
signal(SIGUSR1, usr1_handler);
@@ -2894,16 +2604,10 @@
* (Re)initialize this child to a pre-connection state.
*/
- ap_kill_timeout(0); /* Cancel any outstanding alarms. */
current_conn = NULL;
ap_clear_pool(ptrans);
- ap_sync_scoreboard_image();
- if (ap_scoreboard_image->global.running_generation != ap_my_generation)
{
- clean_child_exit(0);
- }
-
if ((ap_max_requests_per_child > 0
&& requests_this_child++ >= ap_max_requests_per_child)) {
clean_child_exit(0);
@@ -2951,17 +2655,16 @@
/* if we accept() something we don't want to die, so we have to
* defer the exit
*/
- deferred_die = 0;
usr1_just_die = 0;
for (;;) {
- clen = sizeof(sa_client);
- csd = ap_accept(sd, &sa_client, &clen);
- if (csd >= 0 || errno != EINTR)
- break;
if (deferred_die) {
/* we didn't get a socket, and we were told to die */
clean_child_exit(0);
}
+ clen = sizeof(sa_client);
+ csd = ap_accept(sd, &sa_client, &clen);
+ if (csd >= 0 || errno != EINTR)
+ break;
}
if (csd >= 0)
@@ -3038,19 +2741,10 @@
}
}
- /* go around again, safe to die */
- usr1_just_die = 1;
- if (deferred_die) {
- /* ok maybe not, see ya later */
+ if (ap_mpm_graceful_stop()) {
clean_child_exit(0);
}
- /* or maybe we missed a signal, you never know on systems
- * without reliable signals
- */
- ap_sync_scoreboard_image();
- if (ap_scoreboard_image->global.running_generation !=
ap_my_generation) {
- clean_child_exit(0);
- }
+ usr1_just_die = 1;
}
SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
@@ -3061,7 +2755,9 @@
#endif
/* We've got a socket, let's at least process one request off the
- * socket before we accept a graceful restart request.
+ * socket before we accept a graceful restart request. We set
+ * the signal to ignore because we don't want to disturb any
+ * third party code.
*/
signal(SIGUSR1, SIG_IGN);
@@ -3218,9 +2914,6 @@
child_main(slot);
}
-#ifdef OPTIMIZE_TIMEOUTS
- ap_scoreboard_image->parent[slot].last_rtime = now;
-#endif
ap_scoreboard_image->parent[slot].pid = pid;
#ifdef SCOREBOARD_FILE
lseek(scoreboard_fd, XtOffsetOf(scoreboard, parent[slot]), 0);
@@ -3317,24 +3010,6 @@
++total_non_dead;
last_non_dead = i;
-#ifdef OPTIMIZE_TIMEOUTS
- if (ss->timeout_len) {
- /* if it's a live server, with a live timeout then
- * start checking its timeout */
- parent_score *ps = &ap_scoreboard_image->parent[i];
- if (ss->cur_vtime != ps->last_vtime) {
- /* it has made progress, so update its last_rtime,
- * last_vtime */
- ps->last_rtime = now;
- ps->last_vtime = ss->cur_vtime;
- }
- else if (ps->last_rtime + ss->timeout_len < now) {
- /* no progress, and the timeout length has been exceeded */
- ss->timeout_len = 0;
- kill(ps->pid, SIGALRM);
- }
- }
-#endif
}
}
max_daemons_limit = last_non_dead + 1;
@@ -3463,8 +3138,6 @@
server_conf = s;
- child_timeouts = one_process;
-
ap_log_pid(pconf, ap_pid_fname);
setup_listeners(pconf);
@@ -3687,7 +3360,7 @@
is_graceful = 0;
if (!one_process) {
- /* TODO: detach(); ... it should work fine, this is just easier for
debugging */
+ detach();
}
my_pid = getpid();