Skip to content

Commit fbc56bf

Browse files
committed
bounded graceful shutdown for extra connections
1 parent 4beed2d commit fbc56bf

5 files changed

Lines changed: 126 additions & 18 deletions

File tree

docs/log-message-tags/next-number

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
10619
1+
10623

server/mpm/event/event.c

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ static int num_listensocks = 0;
188188
static apr_int32_t conns_this_child; /* MaxConnectionsPerChild, only access
189189
in listener thread */
190190
static apr_uint32_t connection_count = 0; /* Number of open connections */
191+
static apr_uint32_t extra_connection_count = 0; /* Number of open connections that the MPM does not own */
191192
static apr_uint32_t lingering_count = 0; /* Number of connections in lingering close */
192193
static apr_uint32_t suspended_count = 0; /* Number of suspended connections */
193194
static apr_uint32_t clogged_count = 0; /* Number of threads processing ssl conns */
@@ -873,16 +874,39 @@ static apr_status_t decrement_connection_count(void *cs_)
873874

874875
static void ap_mpm_note_extra_connection_added(void)
875876
{
876-
apr_atomic_inc32(&connection_count);
877+
apr_atomic_inc32(&extra_connection_count);
877878
}
878879

879880
static void ap_mpm_note_extra_connection_removed(void)
880881
{
881-
int is_last_connection = !apr_atomic_dec32(&connection_count);
882+
apr_atomic_dec32(&extra_connection_count);
883+
}
882884

883-
/* Wake a listener blocked waiting for connection_count to drain. */
884-
if (listener_is_wakeable && is_last_connection && listener_may_exit) {
885-
apr_pollset_wakeup(event_pollset);
885+
static void wait_for_extra_connections(void)
886+
{
887+
apr_uint32_t count = apr_atomic_read32(&extra_connection_count);
888+
apr_time_t graceful, timeout, deadline;
889+
890+
if (count == 0) {
891+
return;
892+
}
893+
894+
graceful = apr_time_from_sec(ap_graceful_shutdown_timeout);
895+
timeout = (graceful > ap_server_conf->timeout) ? graceful : ap_server_conf->timeout;
896+
deadline = apr_time_now() + timeout;
897+
898+
do {
899+
apr_sleep(apr_time_from_msec(100));
900+
count = apr_atomic_read32(&extra_connection_count);
901+
} while (count > 0 && apr_time_now() < deadline);
902+
903+
if (count > 0) {
904+
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
905+
APLOGNO(10619)
906+
"Child: %u connection(s) noted by modules did not "
907+
"finish within %" APR_TIME_T_FMT " seconds, "
908+
"exiting anyway",
909+
count, apr_time_sec(timeout));
886910
}
887911
}
888912

@@ -3154,6 +3178,10 @@ static void child_main(int child_num_arg, int child_bucket)
31543178
rv == AP_MPM_PODX_GRACEFUL ? "graceful" : "ungraceful");
31553179
}
31563180

3181+
if (terminate_mode == ST_GRACEFUL) {
3182+
wait_for_extra_connections();
3183+
}
3184+
31573185
free(threads);
31583186

31593187
clean_child_exit(resource_shortage ? APEXIT_CHILDSICK : 0);

server/mpm/prefork/prefork.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,34 @@ static void prefork_note_child_started(int slot, pid_t pid)
219219
ap_run_child_status(ap_server_conf, pid, gen, slot, MPM_CHILD_STARTED);
220220
}
221221

222+
static void wait_for_extra_connections(void)
223+
{
224+
apr_uint32_t count = apr_atomic_read32(&connection_count);
225+
apr_time_t graceful, timeout, deadline;
226+
227+
if (count == 0) {
228+
return;
229+
}
230+
231+
graceful = apr_time_from_sec(ap_graceful_shutdown_timeout);
232+
timeout = (graceful > ap_server_conf->timeout) ? graceful : ap_server_conf->timeout;
233+
deadline = apr_time_now() + timeout;
234+
235+
do {
236+
apr_sleep(apr_time_from_msec(100));
237+
count = apr_atomic_read32(&connection_count);
238+
} while (count > 0 && apr_time_now() < deadline);
239+
240+
if (count > 0) {
241+
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
242+
APLOGNO(10620)
243+
"Child: %u connection(s) noted by modules did not "
244+
"finish within %" APR_TIME_T_FMT " seconds, "
245+
"exiting anyway",
246+
count, apr_time_sec(timeout));
247+
}
248+
}
249+
222250
/* a clean exit from a child with proper cleanup */
223251
static void clean_child_exit_ex(int code, int from_signal) __attribute__ ((noreturn));
224252
static void clean_child_exit_ex(int code, int from_signal)
@@ -232,9 +260,7 @@ static void clean_child_exit_ex(int code, int from_signal)
232260
if (!code && !from_signal) {
233261
ap_run_child_stopping(pchild, !retained->mpm->is_ungraceful);
234262
if (!retained->mpm->is_ungraceful) {
235-
while (apr_atomic_read32(&connection_count) > 0) {
236-
apr_sleep(apr_time_from_msec(100));
237-
}
263+
wait_for_extra_connections();
238264
}
239265
ap_run_child_stopped(pchild, !retained->mpm->is_ungraceful);
240266
}

server/mpm/winnt/child.c

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,36 @@ void ap_mpm_note_extra_connection_removed(void)
146146
apr_atomic_dec32(&extra_connection_count);
147147
}
148148

149+
static void wait_for_extra_connections(void)
150+
{
151+
apr_uint32_t count = apr_atomic_read32(&extra_connection_count);
152+
apr_time_t graceful, timeout;
153+
int time_remains;
154+
155+
if (count == 0) {
156+
return;
157+
}
158+
159+
graceful = apr_time_from_sec(ap_graceful_shutdown_timeout);
160+
timeout = (graceful > ap_server_conf->timeout) ? graceful : ap_server_conf->timeout;
161+
time_remains = (int)(timeout / APR_TIME_C(1000));
162+
163+
do {
164+
Sleep(100);
165+
time_remains -= 100;
166+
count = apr_atomic_read32(&extra_connection_count);
167+
} while (count > 0 && time_remains > 0);
168+
169+
if (count > 0) {
170+
ap_log_error(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, ap_server_conf,
171+
APLOGNO(10622)
172+
"Child: %u connection(s) noted by modules did not "
173+
"finish within %" APR_TIME_T_FMT " seconds, "
174+
"exiting anyway",
175+
count, apr_time_sec(timeout));
176+
}
177+
}
178+
149179
static void mpm_recycle_completion_context(winnt_conn_ctx_t *context)
150180
{
151181
/* Recycle the completion context.
@@ -1249,12 +1279,6 @@ void child_main(apr_pool_t *pconf, DWORD parent_pid)
12491279
}
12501280
}
12511281

1252-
/* Drain externally accepted connections within what is left of the deadline. */
1253-
while (apr_atomic_read32(&extra_connection_count) > 0 && time_remains >= 0) {
1254-
Sleep(100);
1255-
time_remains -= 100;
1256-
}
1257-
12581282
if (threads_created) {
12591283
ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, APLOGNO(00363)
12601284
"Child: Waiting for %d threads timed out, terminating process.",
@@ -1280,6 +1304,10 @@ void child_main(apr_pool_t *pconf, DWORD parent_pid)
12801304
ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, APLOGNO(00364)
12811305
"Child: All worker threads have exited.");
12821306

1307+
if (graceful_shutdown) {
1308+
wait_for_extra_connections();
1309+
}
1310+
12831311
ap_run_child_stopped(pchild, graceful_shutdown);
12841312

12851313
apr_thread_mutex_destroy(child_lock);

server/mpm/worker/worker.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,34 @@ static void ap_mpm_note_extra_connection_removed(void)
523523
apr_atomic_dec32(&connection_count);
524524
}
525525

526+
static void wait_for_extra_connections(void)
527+
{
528+
apr_uint32_t count = apr_atomic_read32(&connection_count);
529+
apr_time_t graceful, timeout, deadline;
530+
531+
if (count == 0) {
532+
return;
533+
}
534+
535+
graceful = apr_time_from_sec(ap_graceful_shutdown_timeout);
536+
timeout = (graceful > ap_server_conf->timeout) ? graceful : ap_server_conf->timeout;
537+
deadline = apr_time_now() + timeout;
538+
539+
do {
540+
apr_sleep(apr_time_from_msec(100));
541+
count = apr_atomic_read32(&connection_count);
542+
} while (count > 0 && apr_time_now() < deadline);
543+
544+
if (count > 0) {
545+
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
546+
APLOGNO(10621)
547+
"Child: %u connection(s) noted by modules did not "
548+
"finish within %" APR_TIME_T_FMT " seconds, "
549+
"exiting anyway",
550+
count, apr_time_sec(timeout));
551+
}
552+
}
553+
526554
static void unblock_signal(int sig)
527555
{
528556
sigset_t sig_mask;
@@ -1341,9 +1369,7 @@ static void child_main(int child_num_arg, int child_bucket)
13411369
}
13421370

13431371
if (terminate_mode == ST_GRACEFUL) {
1344-
while (apr_atomic_read32(&connection_count) > 0) {
1345-
apr_sleep(apr_time_from_msec(100));
1346-
}
1372+
wait_for_extra_connections();
13471373
}
13481374

13491375
free(threads);

0 commit comments

Comments
 (0)