From: Paul J. Reder Date: Fri, 6 Apr 2001 20:12:09 +0000 (+0000) Subject: Changes required to make prefork clean up idle children properly. There was a window... X-Git-Tag: 2.0.17~107 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a3d7fb947da15eeee87b41017f10cb9ab9c7d123;p=thirdparty%2Fapache%2Fhttpd.git Changes required to make prefork clean up idle children properly. There was a window during which a starting worker deadlocks when an idle cleanup arrives before it completes init. Apache then keeps trying to cleanup the same deadlocked worker forever (until higher pids come along, but it still will never reduce below the deadlocked pid). Thus the number of children would not reduce to the correct idle level. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88741 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/include/ap_mpm.h b/include/ap_mpm.h index 26a4d44aa5c..549faf71ccb 100644 --- a/include/ap_mpm.h +++ b/include/ap_mpm.h @@ -121,7 +121,7 @@ AP_DECLARE(int) ap_mpm_run(apr_pool_t *pconf, apr_pool_t *plog, server_rec *serv * predicate indicating if a graceful stop has been requested ... * used by the connection loop * @return 1 if a graceful stop has been requested, 0 otherwise - * @deffunc int ap_graceful_stop_signalled*void) + * @deffunc int ap_graceful_stop_signalled(*void) */ AP_DECLARE(int) ap_graceful_stop_signalled(void); diff --git a/include/scoreboard.h b/include/scoreboard.h index 91cbcf20b10..81238495f24 100644 --- a/include/scoreboard.h +++ b/include/scoreboard.h @@ -100,7 +100,8 @@ extern "C" { #define SERVER_GRACEFUL 8 /* server is gracefully finishing request */ #define SERVER_ACCEPTING 9 /* thread is accepting connections */ #define SERVER_QUEUEING 10 /* thread is putting connection on the queue */ -#define SERVER_NUM_STATUS 11 /* number of status settings */ +#define SERVER_IDLE_KILL 11 /* Server is cleaning up idle children. */ +#define SERVER_NUM_STATUS 12 /* number of status settings */ /* A "virtual time" is simply a counter that indicates that a child is * making progress. The parent checks up on each child, and when they have @@ -148,6 +149,10 @@ typedef enum { SB_NOT_SHARED = 2 } ap_scoreboard_e; +#define SB_WORKING 0 /* The server is busy and the child is useful. */ +#define SB_IDLE_DIE 1 /* The server is idle and the child is superfluous. */ + /* The child should check for this and exit gracefully. */ + /* stuff which is thread/process specific */ typedef struct { #ifdef OPTIMIZE_TIMEOUTS @@ -165,6 +170,7 @@ typedef struct { unsigned long my_bytes_served; unsigned long conn_bytes; unsigned short conn_count; + unsigned short life_status; /* Either SB_WORKING or SB_IDLE_DIE */ apr_time_t start_time; apr_time_t stop_time; #ifdef HAVE_TIMES diff --git a/modules/generators/mod_status.c b/modules/generators/mod_status.c index 3cd30fe54b4..17f07e888fe 100644 --- a/modules/generators/mod_status.c +++ b/modules/generators/mod_status.c @@ -466,6 +466,7 @@ static int status_handler(request_rec *r) ap_rputs("\"D\" DNS Lookup,
\n", r); ap_rputs("\"L\" Logging, \n", r); ap_rputs("\"G\" Gracefully finishing, \n", r); + ap_rputs("\"I\" Idle cleanup of worker, \n", r); ap_rputs("\".\" Open slot with no current process

\n", r); ap_rputs("

\n", r); if (!ap_extended_status) { @@ -764,6 +765,7 @@ static void status_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, serv status_flags[SERVER_BUSY_LOG] = 'L'; status_flags[SERVER_BUSY_DNS] = 'D'; status_flags[SERVER_GRACEFUL] = 'G'; + status_flags[SERVER_IDLE_KILL] = 'I'; } static void register_hooks(apr_pool_t *p) diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index 4e40eaa16ef..2546570d3b6 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -232,6 +232,7 @@ static void clean_child_exit(int code) if (pchild) { apr_pool_destroy(pchild); } + ap_scoreboard_image->servers[my_child_num][0].life_status = SB_WORKING; chdir_for_gprof(); exit(code); } @@ -360,20 +361,18 @@ static void sig_coredump(int sig) * Connection structures and accounting... */ -static void just_die(int sig) +static void please_die_gracefully(int sig) { - clean_child_exit(0); -} - -static int volatile deferred_die; -static int volatile usr1_just_die; - -static void usr1_handler(int sig) -{ - if (usr1_just_die) { - just_die(sig); + /* clean_child_exit(0); */ + ap_scoreboard_image->servers[my_child_num][0].life_status = SB_IDLE_DIE; + if (sig == SIGHUP) { + (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), + SERVER_GRACEFUL, (request_rec *) NULL); + } + else { + (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), + SERVER_IDLE_KILL, (request_rec *) NULL); } - deferred_die = 1; } /* volatile just in case */ @@ -520,16 +519,16 @@ static apr_socket_t *csd; static int requests_this_child; static fd_set main_fds; +#define I_AM_TO_SHUTDOWN() \ +(ap_scoreboard_image->servers[my_child_num][0].life_status != SB_WORKING) + int ap_graceful_stop_signalled(void) { - ap_sync_scoreboard_image(); - if (deferred_die || - ap_scoreboard_image->global.running_generation != ap_my_generation) { - return 1; - } + /* not ever called anymore... */ return 0; } + static void child_main(int child_num_arg) { ap_listen_rec *lr; @@ -540,9 +539,9 @@ static void child_main(int child_num_arg) apr_status_t stat = APR_EINIT; int sockdes; + my_child_num = child_num_arg; ap_my_pid = getpid(); csd = NULL; - my_child_num = child_num_arg; requests_this_child = 0; last_lr = NULL; @@ -565,16 +564,16 @@ static void child_main(int child_num_arg) (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), SERVER_READY, (request_rec *) NULL); - apr_signal(SIGHUP, just_die); - apr_signal(SIGTERM, just_die); + apr_signal(SIGHUP, please_die_gracefully); + apr_signal(SIGTERM, please_die_gracefully); - while (!ap_graceful_stop_signalled()) { + ap_sync_scoreboard_image(); + while (!I_AM_TO_SHUTDOWN()) { /* Prepare to receive a SIGWINCH due to graceful restart so that * we can exit cleanly. */ - usr1_just_die = 1; - apr_signal(SIGWINCH, usr1_handler); + apr_signal(SIGWINCH, please_die_gracefully); /* * (Re)initialize this child to a pre-connection state. @@ -654,9 +653,9 @@ static void child_main(int child_num_arg) /* if we accept() something we don't want to die, so we have to * defer the exit */ - usr1_just_die = 0; for (;;) { - if (deferred_die) { + ap_sync_scoreboard_image(); + if (I_AM_TO_SHUTDOWN()) { /* we didn't get a socket, and we were told to die */ clean_child_exit(0); } @@ -763,10 +762,10 @@ static void child_main(int child_num_arg) } } - if (ap_graceful_stop_signalled()) { + ap_sync_scoreboard_image(); + if (I_AM_TO_SHUTDOWN()) { clean_child_exit(0); } - usr1_just_die = 1; } SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ @@ -791,12 +790,15 @@ static void child_main(int child_num_arg) "(currently %d)", sockdes, FD_SETSIZE); apr_socket_close(csd); + ap_sync_scoreboard_image(); continue; } #ifdef TPF - if (sockdes == 0) /* 0 is invalid socket for TPF */ - continue; + if (sockdes == 0) { /* 0 is invalid socket for TPF */ + ap_sync_scoreboard_image(); + continue; + } #endif ap_sock_disable_nagle(csd); @@ -807,6 +809,8 @@ static void child_main(int child_num_arg) ap_process_connection(current_conn); ap_lingering_close(current_conn); } + + ap_sync_scoreboard_image(); } clean_child_exit(0); } @@ -821,12 +825,13 @@ static int make_child(server_rec *s, int slot) } if (one_process) { - apr_signal(SIGHUP, just_die); - apr_signal(SIGINT, just_die); + apr_signal(SIGHUP, please_die_gracefully); + apr_signal(SIGINT, please_die_gracefully); #ifdef SIGQUIT apr_signal(SIGQUIT, SIG_DFL); #endif - apr_signal(SIGTERM, just_die); + apr_signal(SIGTERM, please_die_gracefully); + ap_scoreboard_image->servers[slot][0].life_status = SB_WORKING; child_main(slot); } @@ -870,13 +875,14 @@ static int make_child(server_rec *s, int slot) } #endif RAISE_SIGSTOP(MAKE_CHILD); - /* Disable the restart signal handlers and enable the just_die stuff. + /* Disable the restart signal handlers and enable the please_die_gracefully stuff. * Note that since restart() just notes that a restart has been * requested there's no race condition here. */ - apr_signal(SIGHUP, just_die); - apr_signal(SIGWINCH, just_die); - apr_signal(SIGTERM, just_die); + apr_signal(SIGHUP, please_die_gracefully); + apr_signal(SIGWINCH, please_die_gracefully); + apr_signal(SIGTERM, please_die_gracefully); + ap_scoreboard_image->servers[slot][0].life_status = SB_WORKING; child_main(slot); } @@ -1066,6 +1072,7 @@ static int setup_listeners(server_rec *s) int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) { + int index; int remaining_children_to_start; pconf = _pconf; @@ -1236,11 +1243,12 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) ++ap_my_generation; ap_scoreboard_image->global.running_generation = ap_my_generation; update_scoreboard_global(); + + for (index = 0; index < ap_daemons_limit; ++index) { + ap_scoreboard_image->servers[index][0].life_status = SB_IDLE_DIE; + } if (is_graceful) { -#ifndef SCOREBOARD_FILE - int i; -#endif ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, "SIGWINCH received. Doing graceful restart"); @@ -1255,9 +1263,9 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) * corruption too easily. */ ap_sync_scoreboard_image(); - for (i = 0; i < ap_daemons_limit; ++i) { - if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) { - ap_scoreboard_image->servers[i][0].status = SERVER_GRACEFUL; + for (index = 0; index < ap_daemons_limit; ++index) { + if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) { + ap_scoreboard_image->servers[index][0].status = SERVER_GRACEFUL; } } #endif diff --git a/server/mpm_common.c b/server/mpm_common.c index d9ecdb00d8a..784aee3eba7 100644 --- a/server/mpm_common.c +++ b/server/mpm_common.c @@ -126,9 +126,9 @@ void ap_reclaim_child_processes(int terminate) switch (tries) { case 1: /* 16ms */ case 2: /* 82ms */ - break; case 3: /* 344ms */ case 4: /* 16ms */ + break; case 5: /* 82ms */ case 6: /* 344ms */ case 7: /* 1.4sec */