From: David McCreedy Date: Tue, 28 Feb 2006 16:38:08 +0000 (+0000) Subject: TPF platform-specific changes: X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=16e4329503cd1206788e6de2046b3c244bcf1d3e;p=thirdparty%2Fapache%2Fhttpd.git TPF platform-specific changes: Ensure children close their sockets upon shutdown. Fix KeepAliveTimeOut and TimeOut processing. Implement SIGUSR1 (graceful restart) and SIGHUP (restart now). git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x@381696 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/include/ap_alloc.h b/src/include/ap_alloc.h index 48866127bb5..25e348742e5 100644 --- a/src/include/ap_alloc.h +++ b/src/include/ap_alloc.h @@ -279,13 +279,8 @@ API_EXPORT_NONSTD(void) ap_null_cleanup(void *data); * 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 diff --git a/src/main/buff.c b/src/main/buff.c index aacf6d62225..3fc1645861c 100644 --- a/src/main/buff.c +++ b/src/main/buff.c @@ -282,7 +282,10 @@ static ap_inline int buff_read(BUFF *fb, void *buf, int nbyte) FD_SET(fb->fd_in, &fds); tv.tv_sec = 1; tv.tv_usec = 0; - rv = ap_select(fb->fd_in + 1, &fds, NULL, NULL, &tv); + do { + rv = ap_select(fb->fd_in + 1, &fds, NULL, NULL, &tv); + ap_check_signals(); + } while((rv == 0) && ap_check_alarm()); if (rv > 0) rv = ap_read(fb, buf, nbyte); } diff --git a/src/main/http_main.c b/src/main/http_main.c index 44a2bd776da..cddc943d3f7 100644 --- a/src/main/http_main.c +++ b/src/main/http_main.c @@ -479,6 +479,13 @@ static void chdir_for_gprof(void) static void clean_child_exit(int code) __attribute__ ((noreturn)); static void clean_child_exit(int code) { +#ifdef TPF + /* run ptrans cleanups since TPF's sockets don't close upon exit */ + if (ptrans) { + ap_clear_pool(ptrans); + } +#endif /* TPF */ + if (pchild) { /* make sure the accept mutex is released before calling child * exit hooks and cleanups... otherwise, modules can segfault @@ -1557,7 +1564,6 @@ static void timeout(int sig) } -#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 @@ -1597,7 +1603,6 @@ API_EXPORT(void) ap_unblock_alarms(void) } } } -#endif /* TPF */ #ifndef NETWARE static APACHE_TLS void (*volatile alarm_fn) (int) = NULL; @@ -1609,6 +1614,9 @@ static APACHE_TLS unsigned int alarm_expiry_time = 0; #if !defined(WIN32) && !defined(NETWARE) static void alrm_handler(int sig) { +#ifdef TPF41 + signal(sig, exit); +#endif if (alarm_fn) { (*alarm_fn) (sig); } @@ -1687,7 +1695,26 @@ API_EXPORT(int) ap_check_alarm(void) } #endif /* WIN32 */ +#ifdef TPF +API_EXPORT(int) ap_check_alarm(void) +{ + int i; +#ifdef OPTIMIZE_TIMEOUTS + /* just pull the timeout from the scoreboard */ + ap_sync_scoreboard_image(); + i = ap_scoreboard_image->servers[my_child_num].timeout_len; +#else + i = ap_set_callback_and_alarm(alarm_fn, 3); /* determine time left */ + /* the 3 seconds is just an arbitrary amount of time to keep the alarm + from expiring before it is reset on this next line: */ + ap_set_callback_and_alarm(alarm_fn, i); /* restore time left */ +#endif + + return i; /* return the time left */ +} + +#endif /* TPF */ /* reset_timeout (request_rec *) resets the timeout in effect, * as long as it hasn't expired already. @@ -2814,6 +2841,9 @@ static void reclaim_child_processes(int terminate) break; } } +#ifdef TPF + AP_OS_RECLAIM_LOOP_ADJUSTMENTS +#endif #ifndef NO_OTHER_CHILD for (ocr = other_children; ocr; ocr = nocr) { nocr = ocr->next; @@ -4672,11 +4702,6 @@ static void child_main(int child_num_arg) SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ -#ifdef TPF - if (csd == 0) /* 0 is invalid socket for TPF */ - continue; -#endif - /* We've got a socket, let's at least process one request off the * socket before we accept a graceful restart request. */ diff --git a/src/os/tpf/os.c b/src/os/tpf/os.c index a5d639b8546..8c69013884e 100644 --- a/src/os/tpf/os.c +++ b/src/os/tpf/os.c @@ -110,18 +110,38 @@ int tpf_select(int maxfds, fd_set *reads, fd_set *writes, fd_set *excepts, int tpf_accept(int sockfd, struct sockaddr *peer, int *paddrlen) { + extern pid_t tpf_parent_pid; int socks[1]; int rv; - ap_check_signals(); socks[0] = sockfd; - rv = select(socks, 1, 0, 0, TPF_ACCEPT_SECS_TO_BLOCK * 1000); - errno = sock_errno(); + rv = select(socks, 1, 0, 0, 1 * 1000); + ap_check_signals(); + if ((rv == 0) && (errno == 0)) { + /* select timed out */ + errno = EINTR; /* make errno look like accept was interruped */ + /* now's a good time to make sure our parent didn't abnormally exit */ + if (getppid() == 1) { + /* our parent is gone... close the socket so Apache can restart + (it shouldn't still be open but we're taking no chances) */ + closesocket(sockfd); + ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, NULL, + "child %d closing the socket because getppid()" + " returned 1 instead of parent pid %d", + getpid(), tpf_parent_pid); + errno = 0; + } + return -1; + } + /* paranoid check for rv == 0 and errno != 0, should never happen */ + if (rv == 0) { + rv = -1; + } + if(rv>0) { rv = accept(sockfd, peer, paddrlen); errno = sock_errno(); } - ap_check_signals(); return rv; } @@ -339,14 +359,6 @@ pid_t os_fork(server_rec *s, int slot) int count; listen_rec *lr; - fflush(stdin); - if (dup2(fileno(sock_fp), STDIN_FILENO) == -1) - ap_log_error(APLOG_MARK, APLOG_CRIT, s, - "unable to replace stdin with sock device driver"); - fflush(stdout); - if (dup2(fileno(sock_fp), STDOUT_FILENO) == -1) - ap_log_error(APLOG_MARK, APLOG_CRIT, s, - "unable to replace stdout with sock device driver"); input_parms.generation = ap_my_generation; #ifdef USE_SHMGET_SCOREBOARD input_parms.scoreboard_heap = ap_scoreboard_image; @@ -424,22 +436,23 @@ int os_check_server(char *server) { ap_check_signals(); - /* check that the program activation number hasn't changed */ - current_acn = (int *)cinfc_fast(CINFC_CMMACNUM); - if (ecbp2()->ce2acn != *current_acn) { - return 1; /* shutdown */ - } - /* check our InetD status */ if (inetd_getServerStatus(server) != INETD_SERVER_STATUS_ACTIVE) { return 1; /* shutdown */ } - /* if DAEMON model, make sure parent is still around */ + /* if DAEMON model, make sure CLTZ parent is still around */ if (zinet_model == INETD_IDCF_MODEL_DAEMON) { if (getppid() == 1) { return 1; /* shutdown */ } + } else { + /* this is the NOLISTEN model (INETD_IDCF_MODEL_NOLISTEN) */ + /* check that the program activation number hasn't changed */ + current_acn = (int *)cinfc_fast(CINFC_CMMACNUM); + if (ecbp2()->ce2acn != *current_acn) { + return 1; /* shutdown */ + } } return 0; /* keep on running... */ @@ -451,8 +464,8 @@ void os_note_additional_cleanups(pool *p, int sd) { will close socket in case we happen to abend. */ sprintf(sockfilename, "/dev/tpf.socket.file/%.8X", sd); sock_fp = fopen(sockfilename, "r+"); - /* arrange to close on exec or restart */ - ap_note_cleanups_for_file_ex(p, sock_fp, 1); + /* we don't want the children to inherit this fd */ + fcntl(fileno(sock_fp), F_SETFD, FD_CLOEXEC); sock_sd = sd; } @@ -744,6 +757,8 @@ int ap_check_shm_space(struct pool *a, int size) */ int killpg(pid_t pgrp, int sig) { + struct ev0bk evnblock; + struct timeval tv; int i; ap_sync_scoreboard_image(); @@ -755,11 +770,27 @@ int killpg(pid_t pgrp, int sig) kill(pid, sig); } } - /* allow time for the signals to get to the children */ - sleep(1); - /* get idle children's attention by closing the socket */ - closesocket(sock_sd); - sleep(1); + /* Allow time for the signals to get to the children. + Note that ap_select is signal interruptable, + so we use evnwc instead. */ + i = TPF_SHUTDOWN_SIGNAL_DELAY; + evnblock.evnpstinf.evnbkc1 = 1; /* nbr of posts needed */ + evntc(&evnblock, EVENT_CNT, 'N', i, EVNTC_1052); + evnwc(&evnblock, EVENT_CNT); + + if (sig == SIGTERM) { + /* get idle children's attention by closing the socket */ + closesocket(sock_sd); + /* and close the /dev/tpf.socket.file special file */ + fclose(sock_fp); + /* Allow the children some more time. + Note that ap_select is signal interruptable, + so we use evnwc instead. */ + i = TPF_SHUTDOWN_CLOSING_DELAY; + evnblock.evnpstinf.evnbkc1 = 1; /* nbr of posts needed */ + evntc(&evnblock, EVENT_CNT, 'N', i, EVNTC_1052); + evnwc(&evnblock, EVENT_CNT); + } return(0); } @@ -809,7 +840,6 @@ int i; printf(" -D HAVE_SYSLOG\n"); #endif - printf(" -D TPF_ACCEPT_SECS_TO_BLOCK=%i\n", TPF_ACCEPT_SECS_TO_BLOCK); /* round SCOREBOARD_MAINTENANCE_INTERVAL up to seconds */ i = (SCOREBOARD_MAINTENANCE_INTERVAL + 999999) / 1000000; if (i == 1) { diff --git a/src/os/tpf/os.h b/src/os/tpf/os.h index 34fdfcf0cfb..86739b08b30 100644 --- a/src/os/tpf/os.h +++ b/src/os/tpf/os.h @@ -179,12 +179,6 @@ #include "ap_config.h" -/* TPF_ACCEPT_SECS_TO_BLOCK is the number of seconds to block while - waiting to accept a new request in the ap_accept/tpf_accept function */ -#ifndef TPF_ACCEPT_SECS_TO_BLOCK -#define TPF_ACCEPT_SECS_TO_BLOCK 1 -#endif - #if !defined(INLINE) && defined(USE_GNU_INLINE) /* Compiler supports inline, so include the inlineable functions as * part of the header @@ -245,6 +239,29 @@ typedef struct fd_set { /* definitions for the file descriptor inheritance table */ #define TPF_FD_LIST_SIZE 4000 +/* seconds to delay after shutdown/restart signals have been sent */ +#ifndef TPF_SHUTDOWN_SIGNAL_DELAY +#define TPF_SHUTDOWN_SIGNAL_DELAY 2 +#endif + +/* seconds to delay after closing the port as part of shutdown */ +#ifndef TPF_SHUTDOWN_CLOSING_DELAY +#define TPF_SHUTDOWN_CLOSING_DELAY 3 +#endif + +#ifndef AP_OS_RECLAIM_LOOP_ADJUSTMENTS +/* expedite shutdown/restart in http_main.c's reclaim_child_processes + function by skipping some of the loop iterations */ +#define AP_OS_RECLAIM_LOOP_ADJUSTMENTS \ + if (tries == 4) { \ + tries += 1; /* skip try #5 */ \ + } else { \ + if (tries == 8) { \ + tries += 3; /* skip try #9, #10, & #11 */ \ + } \ + } +#endif /* AP_OS_RECLAIM_LOOP_ADJUSTMENTS */ + enum FILE_TYPE { PIPE_OUT = 1, PIPE_IN, PIPE_ERR }; typedef struct tpf_fd_item {