martin 99/07/21 04:44:02
Modified: src/main http_main.c Log: When the network layer has been shut down, there is not much use in just exiting: the parent would simply re-create us (and we'd fail again). Use the CHILDFATAL code to tear the server down. This fixed a nasty fork-loop bug which appeared in these network-shutdown situations (children would exit and be recreated immediately). Reviewed by: Dean Gaudet Revision Changes Path 1.456 +22 -678 apache-1.3/src/main/http_main.c Index: http_main.c =================================================================== RCS file: /export/home/cvs/apache-1.3/src/main/http_main.c,v retrieving revision 1.455 retrieving revision 1.456 diff -u -r1.455 -r1.456 --- http_main.c 1999/07/20 17:44:16 1.455 +++ http_main.c 1999/07/21 11:44:00 1.456 @@ -3855,6 +3855,27 @@ case ENETUNREACH: #endif break; +#ifdef ENETDOWN + case ENETDOWN: + /* + * When the network layer has been shut down, there + * is not much use in simply exiting: the parent + * would simply re-create us (and we'd fail again). + * Use the CHILDFATAL code to tear the server down. + * @@@ Martin's idea for possible improvement: + * A different approach would be to define + * a new APEXIT_NETDOWN exit code, the reception + * of which would make the parent shutdown all + * children, then idle-loop until it detected that + * the network is up again, and restart the children. + * Ben Hyde noted that temporary ENETDOWN situations + * occur in mobile IP. + */ + ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, + "accept: giving up."); + clean_child_exit(APEXIT_CHILDFATAL); +#endif /*ENETDOWN*/ + #ifdef TPF case EINACT: ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, @@ -5820,681 +5841,4 @@ * Apache process ID. Shutdown is signaled by 'apache -k shutdown'. */ signal_shutdown_event = CreateEvent(sa, TRUE, FALSE, signal_shutdown_name); - if (!signal_shutdown_event) { - ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf, - "master_main: Cannot create shutdown event %s", signal_shutdown_name); - CleanNullACL((void *)sa); - exit(1); - } - - /* Create restart event, apPID_restart, where PID is the parent - * Apache process ID. Restart is signaled by 'apache -k restart'. - */ - signal_restart_event = CreateEvent(sa, TRUE, FALSE, signal_restart_name); - if (!signal_restart_event) { - CloseHandle(signal_shutdown_event); - ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf, - "master_main: Cannot create restart event %s", signal_restart_name); - CleanNullACL((void *)sa); - exit(1); - } - CleanNullACL((void *)sa); - - /* Create the start mutex, apPID, where PID is the parent Apache process ID. - * Ths start mutex is used during a restart to prevent more than one - * child process from entering the accept loop at once. - */ - start_mutex = ap_create_mutex(signal_prefix_string); - restart_pending = shutdown_pending = 0; - - do { /* restart-pending */ - if (!is_graceful) { - ap_restart_time = time(NULL); - } - ap_clear_pool(pconf); - pparent = ap_make_sub_pool(pconf); - - server_conf = ap_read_config(pconf, pparent, ap_server_confname); - ap_clear_pool(plog); - ap_open_logs(server_conf, plog); - ap_set_version(); - ap_init_modules(pconf, server_conf); - version_locked++; - service_set_status(SERVICE_START_PENDING); - /* Create child processes */ - while (processes_to_create--) { - if (create_process(process_handles, process_kill_events, - ¤t_live_processes, &child_num, signal_prefix_string, argc, argv) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "master_main: create child process failed. Exiting."); - goto die_now; - } - } - service_set_status(SERVICE_RUNNING); - restart_pending = shutdown_pending = 0; - - /* Wait for either the shutdown or restart events to be signaled */ - process_handles[current_live_processes] = signal_shutdown_event; - process_handles[current_live_processes+1] = signal_restart_event; - rv = WaitForMultipleObjects(current_live_processes+2, (HANDLE *)process_handles, - FALSE, INFINITE); - if (rv == WAIT_FAILED) { - /* Something serious is wrong */ - ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_WIN32ERROR, server_conf, - "WaitForMultipeObjects on process handles and apache-signal -- doing shutdown"); - shutdown_pending = 1; - break; - } - if (rv == WAIT_TIMEOUT) { - /* Hey, this cannot happen */ - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "WaitForMultipeObjects with INFINITE wait exited with WAIT_TIMEOUT"); - shutdown_pending = 1; - } - - cld = rv - WAIT_OBJECT_0; - APD4("main process: wait finished, cld=%d handle %d (max=%d)", cld, process_handles[cld], current_live_processes); - if (cld == current_live_processes) { - /* apPID_shutdown event signalled, we should exit now */ - shutdown_pending = 1; - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf, - "master_main: Shutdown event signaled. Shutting the server down."); - if (ResetEvent(signal_shutdown_event) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf, - "ResetEvent(signal_shutdown_event)"); - } - /* Signal each child processes to die */ - for (i = 0; i < current_live_processes; i++) { - APD3("master_main: signalling child %d, handle %d to die", i, process_handles[i]); - if (SetEvent(process_kill_events[i]) == 0) - ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_WIN32ERROR, server_conf, - "master_main: SetEvent for child process in slot #%d failed", i); - } - break; - } else if (cld == current_live_processes+1) { - /* apPID_restart event signalled, restart the child process */ - int children_to_kill = current_live_processes; - restart_pending = 1; - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf, - "master_main: Restart event signaled. Doing a graceful restart."); - if (ResetEvent(signal_restart_event) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf, - "ResetEvent(signal_restart_event) failed."); - } - /* Signal each child process to die */ - for (i = 0; i < children_to_kill; i++) { - APD3("master_main: signalling child #%d handle %d to die", i, process_handles[i]); - if (SetEvent(process_kill_events[i]) == 0) - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf, - "master_main: SetEvent for child process in slot #%d failed", i); - /* Remove the process (and event) from the process table */ - cleanup_process(process_handles, process_kill_events, i, ¤t_live_processes); - } - processes_to_create = nchild; - ++ap_my_generation; - continue; - } else { - /* A child process must have exited because of MaxRequestPerChild being hit - * or a fatal error condition (seg fault, etc.). Remove the dead process - * from the process_handles and process_kill_events table and create a new - * child process. - */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf, - "master_main: Child processed exited (due to MaxRequestsPerChild?). Restarting the child process."); - ap_assert(cld < current_live_processes); - cleanup_process(process_handles, process_kill_events, cld, ¤t_live_processes); - APD2("main_process: child in slot %d died", rv); - processes_to_create = 1; - continue; - } - - } while (1); - - /* If we dropped out of the loop we definitly want to die completely. We need to - * make sure we wait for all the child process to exit first. - */ - - APD2("*** main process shutdown, processes=%d ***", current_live_processes); - -die_now: - - tmstart = time(NULL); - while (current_live_processes && ((tmstart+60) > time(NULL))) { - service_set_status(SERVICE_STOP_PENDING); - rv = WaitForMultipleObjects(current_live_processes, (HANDLE *)process_handles, FALSE, 2000); - if (rv == WAIT_TIMEOUT) - continue; - ap_assert(rv != WAIT_FAILED); - cld = rv - WAIT_OBJECT_0; - ap_assert(rv < current_live_processes); - APD4("main_process: child in #%d handle %d died, left=%d", - rv, process_handles[rv], current_live_processes); - cleanup_process(process_handles, process_kill_events, cld, ¤t_live_processes); - } - for (i = 0; i < current_live_processes; i++) { - ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO, server_conf, - "forcing termination of child #%d (handle %d)", i, process_handles[i]); - TerminateProcess((HANDLE) process_handles[i], 1); - } - - CloseHandle(signal_restart_event); - CloseHandle(signal_shutdown_event); - - /* cleanup pid file on normal shutdown */ - { - const char *pidfile = NULL; - pidfile = ap_server_root_relative (pparent, ap_pid_fname); - if ( pidfile != NULL && unlink(pidfile) == 0) - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, - server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - } - - if (pparent) { - ap_destroy_pool(pparent); - } - - ap_destroy_mutex(start_mutex); - - service_set_status(SERVICE_STOPPED); - return (0); -} - -/* - * Send signal to a running Apache. On entry signal should contain - * either "shutdown" or "restart" - */ - -int send_signal(pool *p, char *signal) -{ - char prefix[20]; - FILE *fp; - int nread; - char *fname; - int end; - - fname = ap_server_root_relative (p, ap_pid_fname); - - fp = fopen(fname, "r"); - if (!fp) { - printf("Cannot read apache PID file %s\n", fname); - return FALSE; - } - prefix[0] = 'a'; - prefix[1] = 'p'; - - nread = fread(prefix+2, 1, sizeof(prefix)-3, fp); - if (nread == 0) { - fclose(fp); - printf("PID file %s was empty\n", fname); - return FALSE; - } - fclose(fp); - - /* Terminate the prefix string */ - end = 2 + nread - 1; - while (end > 0 && (prefix[end] == '\r' || prefix[end] == '\n')) - end--; - prefix[end + 1] = '\0'; - - setup_signal_names(prefix); - - if (!strcasecmp(signal, "shutdown")) - ap_start_shutdown(); - else if (!strcasecmp(signal, "restart")) - ap_start_restart(1); - else { - printf("Unknown signal name \"%s\". Use either shutdown or restart.\n", - signal); - return FALSE; - } - return TRUE; -} - -void post_parse_init() -{ - ap_set_version(); - ap_init_modules(pconf, server_conf); - ap_suexec_enabled = init_suexec(); - version_locked++; - ap_open_logs(server_conf, plog); - set_group_privs(); -} - -int service_init() -{ - common_init(); - - ap_cpystrn(ap_server_root, HTTPD_ROOT, sizeof(ap_server_root)); - if (ap_registry_get_service_conf(pconf, ap_server_confname, sizeof(ap_server_confname), - ap_server_argv0)) - return FALSE; - - ap_setup_prelinked_modules(); - server_conf = ap_read_config(pconf, ptrans, ap_server_confname); - ap_log_pid(pconf, ap_pid_fname); - post_parse_init(); - return TRUE; -} - -#ifdef WIN32 -__declspec(dllexport) - int apache_main(int argc, char *argv[]) -#else -int REALMAIN(int argc, char *argv[]) -#endif -{ - int c; - int child = 0; - char *cp; - char *s; - char *service_name = NULL; - int install = 0; - int conf_specified = 0; - char *signal_to_send = NULL; - char cwd[MAX_STRING_LEN]; - - /* Service application - * Configuration file in registry at: - * HKLM\System\CurrentControlSet\Services\[Svc name]\Parameters\ConfPath - */ - if (isProcessService()) { - service_main(master_main, argc, argv); - clean_parent_exit(0); - } - - /* Console application or a child process. */ - - if ((s = strrchr(argv[0], PATHSEPARATOR)) != NULL) { - ap_server_argv0 = ++s; - } - else { - ap_server_argv0 = argv[0]; - } - - common_init(); - ap_setup_prelinked_modules(); - - if(!GetCurrentDirectory(sizeof(cwd),cwd)) { - ap_log_error(APLOG_MARK,APLOG_WIN32ERROR, NULL, - "GetCurrentDirectory() failure"); - return -1; - } - - ap_cpystrn(cwd, ap_os_canonical_filename(pcommands, cwd), sizeof(cwd)); - ap_cpystrn(ap_server_root, cwd, sizeof(ap_server_root)); - - while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVlLZ:iusStThk:n:")) != -1) { - char **new; - switch (c) { - case 'c': - new = (char **)ap_push_array(ap_server_post_read_config); - *new = ap_pstrdup(pcommands, optarg); - break; - case 'C': - new = (char **)ap_push_array(ap_server_pre_read_config); - *new = ap_pstrdup(pcommands, optarg); - break; - case 'D': - new = (char **)ap_push_array(ap_server_config_defines); - *new = ap_pstrdup(pcommands, optarg); - break; -#ifdef WIN32 - case 'Z': - exit_event = open_event(optarg); - APD2("child: opened process event %s", optarg); - cp = strchr(optarg, '_'); - ap_assert(cp); - *cp = 0; - setup_signal_names(optarg); - start_mutex = ap_open_mutex(signal_name_prefix); - ap_assert(start_mutex); - child = 1; - break; - case 'n': - service_name = ap_pstrdup(pcommands, optarg); - if (isValidService(optarg)) { - ap_registry_get_service_conf(pconf, ap_server_confname, sizeof(ap_server_confname), - optarg); - conf_specified = 1; - } - break; - case 'i': - install = 1; - break; - case 'u': - install = -1; - break; - case 'S': - ap_dump_settings = 1; - break; - case 'k': - signal_to_send = optarg; - break; -#endif /* WIN32 */ - case 'd': - optarg = ap_os_canonical_filename(pcommands, optarg); - if (!ap_os_is_path_absolute(optarg)) { - optarg = ap_pstrcat(pcommands, cwd, optarg, NULL); - ap_getparents(optarg); - } - if (optarg[strlen(optarg)-1] != '/') - optarg = ap_pstrcat(pcommands, optarg, "/", NULL); - ap_cpystrn(ap_server_root, - optarg, - sizeof(ap_server_root)); - break; - case 'f': - ap_cpystrn(ap_server_confname, - ap_os_canonical_filename(pcommands, optarg), - sizeof(ap_server_confname)); - conf_specified = 1; - break; - case 'v': - ap_set_version(); - printf("Server version: %s\n", ap_get_server_version()); - printf("Server built: %s\n", ap_get_server_built()); - exit(0); - case 'V': - ap_set_version(); - show_compile_settings(); - exit(0); - case 'l': - ap_show_modules(); - exit(0); - case 'L': - ap_show_directives(); - exit(0); - case 'X': - ++one_process; /* Weird debugging mode. */ - break; - case 't': - ap_configtestonly = 1; - ap_docrootcheck = 1; - break; - case 'T': - ap_configtestonly = 1; - ap_docrootcheck = 0; - break; - case 'h': - usage(ap_server_argv0); - case '?': - usage(ap_server_argv0); - } /* switch */ - } /* while */ - - /* ServerConfFile is found in this order: - * (1) -f or -n - * (2) [-d]/SERVER_CONFIG_FILE - * (3) ./SERVER_CONFIG_FILE - * (4) [Registry: HKLM\Software\[product]\ServerRoot]/SERVER_CONFIG_FILE - * (5) /HTTPD_ROOT/SERVER_CONFIG_FILE - */ - - if (!conf_specified) { - ap_cpystrn(ap_server_confname, SERVER_CONFIG_FILE, sizeof(ap_server_confname)); - if (access(ap_server_root_relative(pcommands, ap_server_confname), 0)) { - ap_registry_get_server_root(pconf, ap_server_root, sizeof(ap_server_root)); - if (!*ap_server_root) - ap_cpystrn(ap_server_root, HTTPD_ROOT, sizeof(ap_server_root)); - ap_cpystrn(ap_server_root, ap_os_canonical_filename(pcommands, ap_server_root), - sizeof(ap_server_root)); - } - } - - if (!ap_os_is_path_absolute(ap_server_confname)) { - char *full_conf_path; - - full_conf_path = ap_pstrcat(pcommands, ap_server_root, "/", ap_server_confname, NULL); - full_conf_path = ap_os_canonical_filename(pcommands, full_conf_path); - ap_cpystrn(ap_server_confname, full_conf_path, sizeof(ap_server_confname)); - } - ap_getparents(ap_server_confname); - ap_no2slash(ap_server_confname); - -#ifdef WIN32 - if (install) { - if (!service_name) - service_name = ap_pstrdup(pconf, DEFAULTSERVICENAME); - if (install > 0) - InstallService(service_name, ap_server_root_relative(pcommands, ap_server_confname)); - else - RemoveService(service_name); - clean_parent_exit(0); - } - - if (service_name && signal_to_send) { - send_signal_to_service(service_name, signal_to_send); - clean_parent_exit(0); - } - - if (service_name && !conf_specified) { - printf("Unknown service: %s\n", service_name); - clean_parent_exit(0); - } -#endif - server_conf = ap_read_config(pconf, ptrans, ap_server_confname); - - if (ap_configtestonly) { - fprintf(stderr, "%s: Syntax OK\n", ap_server_root_relative(pcommands, ap_server_confname)); - clean_parent_exit(0); - } - - if (ap_dump_settings) { - clean_parent_exit(0); - } - - /* Treat -k start confpath as just -f confpath */ - if (signal_to_send && strcasecmp(signal_to_send, "start")) { - send_signal(pconf, signal_to_send); - clean_parent_exit(0); - } - - if (!child && !ap_dump_settings) { - ap_log_pid(pconf, ap_pid_fname); - } - - post_parse_init(); - -#ifdef OS2 - printf("%s running...\n", ap_get_server_version()); -#endif -#ifdef WIN32 - if (!child) { - printf("%s running...\n", ap_get_server_version()); - } -#endif - if (one_process && !exit_event) - exit_event = create_event(0, 0, NULL); - if (one_process && !start_mutex) - start_mutex = ap_create_mutex(NULL); - /* - * In the future, the main will spawn off a couple - * of children and monitor them. As soon as a child - * exits, it spawns off a new one - */ - if (child || one_process) { - if (!exit_event || !start_mutex) - exit(-1); - worker_main(); - ap_destroy_mutex(start_mutex); - destroy_event(exit_event); - } - else - master_main(argc, argv); - - clean_parent_exit(0); - return 0; /* purely to avoid a warning */ -} - -#endif /* ndef MULTITHREAD */ - -#else /* ndef SHARED_CORE_TIESTATIC */ - -/* -** Standalone Tie Program for Shared Core support -** -** It's purpose is to tie the static libraries and -** the shared core library under link-time and -** passing execution control to the real main function -** in the shared core library under run-time. -*/ - -extern int ap_main(int argc, char *argv[]); - -int main(int argc, char *argv[]) -{ - return ap_main(argc, argv); -} - -#endif /* ndef SHARED_CORE_TIESTATIC */ -#else /* ndef SHARED_CORE_BOOTSTRAP */ - -#ifdef OS2 -/* Shared core loader for OS/2 */ - -int ap_main(int argc, char *argv[]); /* Load time linked from libhttpd.dll */ - -int main(int argc, char *argv[]) -{ - return ap_main(argc, argv); -} - -#else - -/* -** Standalone Bootstrap Program for Shared Core support -** -** It's purpose is to initialise the LD_LIBRARY_PATH -** environment variable therewith the Unix loader is able -** to start the Standalone Tie Program (see above) -** and then replacing itself with this program by -** immediately passing execution to it. -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "ap_config.h" -#include "httpd.h" - -#if defined(HPUX) || defined(HPUX10) || defined(HPUX11) -#define VARNAME "SHLIB_PATH" -#else -#define VARNAME "LD_LIBRARY_PATH" -#endif - -#ifndef SHARED_CORE_DIR -#define SHARED_CORE_DIR HTTPD_ROOT "/libexec" -#endif - -#ifndef SHARED_CORE_EXECUTABLE_PROGRAM -#define SHARED_CORE_EXECUTABLE_PROGRAM "lib" TARGET ".ep" -#endif - -extern char *optarg; -extern int optind; - -int main(int argc, char *argv[], char *envp[]) -{ - char prog[MAX_STRING_LEN]; - char llp_buf[MAX_STRING_LEN]; - char **llp_slot; - char *llp_existing; - char *llp_dir; - char **envpnew; - int c, i, l; - - /* - * parse argument line, - * but only handle the -L option - */ - llp_dir = SHARED_CORE_DIR; - while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVlLR:SZ:tTh")) != -1) { - switch (c) { - case 'D': - case 'C': - case 'c': - case 'X': - case 'd': - case 'f': - case 'v': - case 'V': - case 'l': - case 'L': - case 'S': - case 'Z': - case 't': - case 'T': - case 'h': - case '?': - break; - case 'R': - llp_dir = strdup(optarg); - break; - } - } - - /* - * create path to SHARED_CORE_EXECUTABLE_PROGRAM - */ - ap_snprintf(prog, sizeof(prog), "%s/%s", llp_dir, SHARED_CORE_EXECUTABLE_PROGRAM); - - /* - * adjust process environment therewith the Unix loader - * is able to start the SHARED_CORE_EXECUTABLE_PROGRAM. - */ - llp_slot = NULL; - llp_existing = NULL; - l = strlen(VARNAME); - for (i = 0; envp[i] != NULL; i++) { - if (strncmp(envp[i], VARNAME "=", l+1) == 0) { - llp_slot = &envp[i]; - llp_existing = strchr(envp[i], '=') + 1; - } - } - if (llp_slot == NULL) { - envpnew = (char **)malloc(sizeof(char *)*(i + 2)); - if (envpnew == NULL) { - fprintf(stderr, "Ouch! Out of memory generating envpnew!\n"); - } - memcpy(envpnew, envp, sizeof(char *)*i); - envp = envpnew; - llp_slot = &envp[i++]; - envp[i] = NULL; - } - if (llp_existing != NULL) - ap_snprintf(llp_buf, sizeof(llp_buf), "%s=%s:%s", VARNAME, llp_dir, llp_existing); - else - ap_snprintf(llp_buf, sizeof(llp_buf), "%s=%s", VARNAME, llp_dir); - *llp_slot = strdup(llp_buf); - - /* - * finally replace our process with - * the SHARED_CORE_EXECUTABLE_PROGRAM - */ - if (execve(prog, argv, envp) == -1) { - fprintf(stderr, - "%s: Unable to exec Shared Core Executable Program `%s'\n", - argv[0], prog); - return 1; - } - else - return 0; -} - -#endif /* def OS2 */ -#endif /* ndef SHARED_CORE_BOOTSTRAP */ - -/* force Expat to be linked into the server executable */ -#if defined(USE_EXPAT) && !defined(SHARED_CORE_BOOTSTRAP) -#include "xmlparse.h" -const XML_LChar *suck_in_expat(void); -const XML_LChar *suck_in_expat(void) -{ - return XML_ErrorString(XML_ERROR_NONE); -} -#endif /* USE_EXPAT */ - + if (!signal_shutd \ No newline at end of file