Commit 527a3bb9 authored by David McCreedy's avatar David McCreedy
Browse files

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
parent 80f3b24e
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -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 
+4 −1
Original line number Diff line number Diff line
@@ -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;
        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);
    }
+32 −7
Original line number Diff line number Diff line
@@ -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.
	 */
+57 −27
Original line number Diff line number Diff line
@@ -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);
    /* 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);
    sleep(1);
       /* 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) {
+23 −6
Original line number Diff line number Diff line
@@ -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 {