Lines 352-400
static void scan_errorlist(server_rec * main_server)
Link Here
|
352 |
proctable_pm_unlock(main_server); |
352 |
proctable_pm_unlock(main_server); |
353 |
} |
353 |
} |
354 |
|
354 |
|
355 |
static void kill_all_subprocess(server_rec * main_server) |
355 |
static void kill_all_subprocess(server_rec * main_server, int graceful) |
356 |
{ |
356 |
{ |
357 |
size_t i; |
357 |
int wait_attempts = 0; |
358 |
int exitcode; |
|
|
359 |
apr_exit_why_e exitwhy; |
360 |
fcgid_procnode *proc_table = proctable_get_table_array(); |
358 |
fcgid_procnode *proc_table = proctable_get_table_array(); |
|
|
359 |
fcgid_procnode *free_list_header = proctable_get_free_list(); |
360 |
fcgid_procnode *busy_list_header = proctable_get_busy_list(); |
361 |
fcgid_procnode *idle_list_header = proctable_get_idle_list(); |
362 |
fcgid_procnode *error_list_header = proctable_get_error_list(); |
363 |
fcgid_procnode *previous_node, *current_node, *next_node; |
364 |
|
361 |
|
365 |
|
362 |
/* Kill gracefully */ |
366 |
/* We'll scan the idle and busy lists signaling each process to shut down |
363 |
for (i = 0; i < proctable_get_table_size(); i++) { |
367 |
The processes in the idle list will be moved to the error list |
364 |
if (proc_table[i].proc_pool) |
368 |
Processes in the busy list will be moved to the error list only during a hard shutdown/restart. |
365 |
proc_kill_gracefully(&proc_table[i], main_server); |
369 |
After we've moved everything to the error list that needs to die, we walk it until everything is cleaned up */ |
366 |
} |
370 |
|
367 |
apr_sleep(apr_time_from_sec(1)); |
371 |
proctable_pm_lock(main_server); |
368 |
|
372 |
|
369 |
/* Kill with SIGKILL if it doesn't work */ |
373 |
/* signal all processes in the error list once */ |
370 |
for (i = 0; i < proctable_get_table_size(); i++) { |
374 |
previous_node = error_list_header; |
371 |
if (proc_table[i].proc_pool) { |
375 |
current_node = &proc_table[previous_node->next_index]; |
372 |
if (apr_proc_wait(&(proc_table[i].proc_id), &exitcode, &exitwhy, |
376 |
while (current_node != proc_table) { |
373 |
APR_NOWAIT) != APR_CHILD_NOTDONE) { |
377 |
proc_kill_gracefully(current_node, main_server); |
374 |
proc_table[i].diewhy = FCGID_DIE_SHUTDOWN; |
378 |
previous_node = current_node; |
375 |
proc_print_exit_info(&proc_table[i], exitcode, exitwhy, |
379 |
current_node = &proc_table[current_node->next_index]; |
376 |
main_server); |
380 |
} |
377 |
apr_pool_destroy(proc_table[i].proc_pool); |
381 |
|
378 |
proc_table[i].proc_pool = NULL; |
382 |
/* Previous node is going to be the tail end of the error list. Attach all the idle list to it and signal those processes to exit */ |
379 |
} |
383 |
current_node = &proc_table[idle_list_header->next_index]; |
380 |
else |
384 |
if (current_node != proc_table) { |
381 |
proc_kill_force(&proc_table[i], main_server); |
385 |
previous_node->next_index = (current_node - proc_table); |
|
|
386 |
idle_list_header->next_index = 0; |
387 |
while ( current_node != proc_table ) { |
388 |
proc_kill_gracefully( current_node, main_server ); |
389 |
current_node->diewhy = FCGID_DIE_SHUTDOWN; |
390 |
previous_node = current_node; |
391 |
current_node = &proc_table[ current_node->next_index ]; |
382 |
} |
392 |
} |
383 |
} |
393 |
} |
384 |
|
394 |
|
385 |
/* Wait again */ |
395 |
/* If this is a forced shutdown, link the busy list to the error list */ |
386 |
for (i = 0; i < proctable_get_table_size(); i++) { |
396 |
current_node = &proc_table[busy_list_header->next_index]; |
387 |
if (proc_table[i].proc_pool) { |
397 |
if (!graceful && current_node != proc_table) { |
388 |
if (apr_proc_wait(&(proc_table[i].proc_id), &exitcode, &exitwhy, |
398 |
previous_node->next_index = (current_node - proc_table); |
389 |
APR_WAIT) != APR_CHILD_NOTDONE) { |
399 |
busy_list_header->next_index = 0; |
390 |
proc_table[i].diewhy = FCGID_DIE_SHUTDOWN; |
400 |
} |
391 |
proc_print_exit_info(&proc_table[i], exitcode, exitwhy, |
401 |
|
392 |
main_server); |
402 |
/* Signal processes in the busy list */ |
393 |
apr_pool_destroy(proc_table[i].proc_pool); |
403 |
while (current_node != proc_table) { |
394 |
proc_table[i].proc_pool = NULL; |
404 |
proc_kill_gracefully( current_node, main_server ); |
|
|
405 |
current_node->diewhy = FCGID_DIE_SHUTDOWN; |
406 |
current_node = &proc_table[ current_node->next_index ]; |
407 |
} |
408 |
|
409 |
/* Now clear the error list into the free list... |
410 |
We are blocking all the bridged processes from completing during this timeframe |
411 |
since they can't aquire the mutex to check the process tables. This should be |
412 |
acceptable for both graceful and hard restarts. This loop should end rapidly |
413 |
with graceful restarts and connection interruptions are going to happen regardless |
414 |
with hard restarts. */ |
415 |
while (error_list_header->next_index != 0) { |
416 |
apr_sleep(apr_time_from_sec(1)); |
417 |
wait_attempts++; |
418 |
previous_node = error_list_header; |
419 |
current_node = &proc_table[previous_node->next_index]; |
420 |
while (current_node != proc_table) { |
421 |
next_node = &proc_table[current_node->next_index]; |
422 |
if (proc_wait_process(main_server, current_node) == APR_CHILD_NOTDONE |
423 |
&& wait_attempts < FCGID_PM_MAX_SHUTDOWN_WAIT_ATTEMPTS ) { |
424 |
/* kill it hard and check again in 1 second */ |
425 |
proc_kill_force( current_node, main_server ); |
426 |
previous_node = current_node; |
395 |
} |
427 |
} |
|
|
428 |
else { |
429 |
/* Unlink from error list */ |
430 |
previous_node->next_index = current_node->next_index; |
431 |
|
432 |
/* Link to free list */ |
433 |
current_node->next_index = free_list_header->next_index; |
434 |
free_list_header->next_index = current_node - proc_table; |
435 |
} |
436 |
current_node = next_node; |
396 |
} |
437 |
} |
397 |
} |
438 |
} |
|
|
439 |
|
440 |
/* At this point in a graceful restart, the busy and free lists have all the process nodes */ |
441 |
/* In a forced restart, all nodes are in the free list */ |
442 |
|
443 |
proctable_pm_unlock(main_server); |
398 |
} |
444 |
} |
399 |
|
445 |
|
400 |
/* This should be proposed as a stand-alone improvement to the httpd module, |
446 |
/* This should be proposed as a stand-alone improvement to the httpd module, |
Lines 482-488
fastcgi_spawn(fcgid_command * command, server_rec * main_server,
Link Here
|
482 |
if (free_list_header->next_index == 0) { |
528 |
if (free_list_header->next_index == 0) { |
483 |
proctable_pm_unlock(main_server); |
529 |
proctable_pm_unlock(main_server); |
484 |
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, main_server, |
530 |
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, main_server, |
485 |
"mod_fcgid: too much processes, please increase FCGID_MAX_APPLICATION"); |
531 |
"mod_fcgid: too many processes, please increase FCGID_MAX_APPLICATION"); |
486 |
return; |
532 |
return; |
487 |
} |
533 |
} |
488 |
procnode = &proctable_array[free_list_header->next_index]; |
534 |
procnode = &proctable_array[free_list_header->next_index]; |
Lines 494-500
fastcgi_spawn(fcgid_command * command, server_rec * main_server,
Link Here
|
494 |
procnode->deviceid = command->deviceid; |
540 |
procnode->deviceid = command->deviceid; |
495 |
procnode->inode = command->inode; |
541 |
procnode->inode = command->inode; |
496 |
apr_cpystrn(procnode->cmdline, command->cmdline, _POSIX_PATH_MAX); |
542 |
apr_cpystrn(procnode->cmdline, command->cmdline, _POSIX_PATH_MAX); |
497 |
procnode->virtualhost = command->virtualhost; |
543 |
apr_cpystrn(procnode->virtualhost, command->virtualhost, _POSIX_PATH_MAX); |
498 |
procnode->uid = command->uid; |
544 |
procnode->uid = command->uid; |
499 |
procnode->gid = command->gid; |
545 |
procnode->gid = command->gid; |
500 |
procnode->start_time = procnode->last_active_time = apr_time_now(); |
546 |
procnode->start_time = procnode->last_active_time = apr_time_now(); |
Lines 510-516
fastcgi_spawn(fcgid_command * command, server_rec * main_server,
Link Here
|
510 |
procinfo.gid = command->gid; |
556 |
procinfo.gid = command->gid; |
511 |
procinfo.userdir = command->userdir; |
557 |
procinfo.userdir = command->userdir; |
512 |
if ((rv = |
558 |
if ((rv = |
513 |
apr_pool_create(&procnode->proc_pool, configpool)) != APR_SUCCESS |
559 |
apr_pool_create(&procnode->proc_pool, main_server->process->pool)) != APR_SUCCESS |
514 |
|| (procinfo.proc_environ = |
560 |
|| (procinfo.proc_environ = |
515 |
apr_table_make(procnode->proc_pool, INITENV_CNT)) == NULL) { |
561 |
apr_table_make(procnode->proc_pool, INITENV_CNT)) == NULL) { |
516 |
/* Link the node back to free list in this case */ |
562 |
/* Link the node back to free list in this case */ |
Lines 523-528
fastcgi_spawn(fcgid_command * command, server_rec * main_server,
Link Here
|
523 |
"mod_fcgid: can't create pool for process"); |
569 |
"mod_fcgid: can't create pool for process"); |
524 |
return; |
570 |
return; |
525 |
} |
571 |
} |
|
|
572 |
|
526 |
/* Set up longer, system defaults before falling into parsing fixed-limit |
573 |
/* Set up longer, system defaults before falling into parsing fixed-limit |
527 |
* request-by-request variables, so if any are overriden, they preempt |
574 |
* request-by-request variables, so if any are overriden, they preempt |
528 |
* any system default assumptions |
575 |
* any system default assumptions |
Lines 563-568
fastcgi_spawn(fcgid_command * command, server_rec * main_server,
Link Here
|
563 |
apr_status_t pm_main(server_rec * main_server, apr_pool_t * configpool) |
610 |
apr_status_t pm_main(server_rec * main_server, apr_pool_t * configpool) |
564 |
{ |
611 |
{ |
565 |
fcgid_command command; |
612 |
fcgid_command command; |
|
|
613 |
apr_status_t rv; |
566 |
|
614 |
|
567 |
while (1) { |
615 |
while (1) { |
568 |
if (procmgr_must_exit()) |
616 |
if (procmgr_must_exit()) |
Lines 586-592
apr_status_t pm_main(server_rec * main_server, apr_pool_t * configpool)
Link Here
|
586 |
} |
634 |
} |
587 |
|
635 |
|
588 |
/* Stop all processes */ |
636 |
/* Stop all processes */ |
589 |
kill_all_subprocess(main_server); |
637 |
kill_all_subprocess(main_server, procmgr_graceful_restart()); |
590 |
|
638 |
|
591 |
return APR_SUCCESS; |
639 |
return APR_SUCCESS; |
592 |
} |
640 |
} |