You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by rb...@apache.org on 2001/06/07 02:09:17 UTC

cvs commit: httpd-2.0/server/mpm/prefork mpm.h prefork.c

rbb         01/06/06 17:09:17

  Modified:    include  httpd.h mpm_common.h
               server   mpm_common.c
               server/mpm/prefork mpm.h prefork.c
  Log:
  First pass at the pipe_of_death logic for the prefork MPM.  This does
  pass some initial testing, but it needs to be banged on more.  It looks
  like if the server gets a lot of requests to restart all at once, there
  are potential problems, but other than that this does seem to solve our
  current restart issues.
  
  Revision  Changes    Path
  1.153     +2 -0      httpd-2.0/include/httpd.h
  
  Index: httpd.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/include/httpd.h,v
  retrieving revision 1.152
  retrieving revision 1.153
  diff -u -d -b -w -u -r1.152 -r1.153
  --- httpd.h	2001/06/03 11:59:18	1.152
  +++ httpd.h	2001/06/07 00:09:14	1.153
  @@ -1542,6 +1542,8 @@
   
   #endif
   
  +#define AP_NORESTART		APR_OS_START_USEERR + 1
  +
   #ifdef __cplusplus
   }
   #endif
  
  
  
  1.21      +43 -0     httpd-2.0/include/mpm_common.h
  
  Index: mpm_common.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/include/mpm_common.h,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -d -b -w -u -r1.20 -r1.21
  --- mpm_common.h	2001/03/22 12:32:21	1.20
  +++ mpm_common.h	2001/06/07 00:09:15	1.21
  @@ -164,6 +164,49 @@
   
   #define AP_MPM_HARD_LIMITS_FILE APACHE_MPM_DIR "/mpm_default.h"
   
  +#ifdef AP_MPM_USES_POD
  +
  +typedef struct ap_pod_t ap_pod_t;
  +
  +struct ap_pod_t {
  +    apr_file_t *pod_in;
  +    apr_file_t *pod_out;
  +    apr_pool_t *p;
  +};
  +
  +/**
  + * Open the pipe-of-death.  The pipe of death is used to tell all child
  + * processes that it is time to die gracefully.
  + * @param p The pool to use for allocating the pipe
  + */
  +AP_DECLARE(apr_status_t) ap_mpm_pod_open(apr_pool_t *p, ap_pod_t **pod);
  +
  +/**
  + * Check the pipe to determine if the process has been signalled to die.
  + */
  +AP_DECLARE(apr_status_t) ap_mpm_pod_check(ap_pod_t *pod);
  +
  +/**
  + * Close the pipe-of-death
  + */
  +AP_DECLARE(apr_status_t) ap_mpm_pod_close(ap_pod_t *pod);
  +
  +/**
  + * Write data to the pipe-of-death, signalling that one child process
  + * should die.
  + * @param p The pool to use when allocating any required structures.
  + */
  +AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod);
  +
  +/**
  + * Write data to the pipe-of-death, signalling that all child process
  + * should die.
  + * @param p The pool to use when allocating any required structures.
  + * @param num The number of child processes to kill
  + */
  +AP_DECLARE(void) ap_mpm_pod_killpg(ap_pod_t *pod, int num);
  +#endif
  +
   #ifdef __cplusplus
   }
   #endif
  
  
  
  1.48      +84 -0     httpd-2.0/server/mpm_common.c
  
  Index: mpm_common.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm_common.c,v
  retrieving revision 1.47
  retrieving revision 1.48
  diff -u -d -b -w -u -r1.47 -r1.48
  --- mpm_common.c	2001/05/16 20:51:28	1.47
  +++ mpm_common.c	2001/06/07 00:09:15	1.48
  @@ -78,6 +78,7 @@
   #include "mpm.h"
   #include "mpm_common.h"
   #include "ap_mpm.h"
  +#include "ap_listen.h"
   
   #ifdef HAVE_PWD_H
   #include <pwd.h>
  @@ -338,4 +339,87 @@
   }
   #endif /* def NEED_INITGROUPS */
   
  +#ifdef AP_MPM_USES_POD
  +
  +AP_DECLARE(apr_status_t) ap_mpm_pod_open(apr_pool_t *p, ap_pod_t **pod)
  +{
  +    apr_status_t rv;
  +
  +    *pod = apr_palloc(p, sizeof(**pod));
  +    rv = apr_file_pipe_create(&((*pod)->pod_in), &((*pod)->pod_out), p);
  +    apr_file_pipe_timeout_set((*pod)->pod_out, 0);
  +    (*pod)->p = p;
  +    return rv;
  +}
  +
  +AP_DECLARE(apr_status_t) ap_mpm_pod_check(ap_pod_t *pod)
  +{
  +    char c;
  +    apr_size_t len = 1;
  +    apr_status_t rv;
  +
  +    rv = apr_file_read(pod->pod_in, &c, &len);
  +
  +    if ((rv == APR_SUCCESS) && (len == 1)) {
  +        return APR_SUCCESS;
  +    }
  +    if (rv != APR_SUCCESS) {
  +        return rv;
  +    }
  +    return AP_NORESTART;
  +}
  +
  +AP_DECLARE(apr_status_t) ap_mpm_pod_close(ap_pod_t *pod)
  +{
  +    apr_status_t rv;
  +
  +    rv = apr_file_close(pod->pod_out);
  +    if (rv != APR_SUCCESS) {
  +        return rv;
  +    }
  +
  +    rv = apr_file_close(pod->pod_in);
  +    if (rv != APR_SUCCESS) {
  +        return rv;
  +    }
  +    return rv;
  +}
  +
  +AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod)
  +{
  +    apr_socket_t *sock;
  +    apr_sockaddr_t *sa;
  +    apr_status_t rv;
  +    char char_of_death = '!';
  +    apr_size_t one = 1;
  +
  +    do {
  +        if ((rv = apr_file_write(pod->pod_out, &char_of_death, &one))
  +                                 != APR_SUCCESS) {
  +            if (APR_STATUS_IS_EINTR(rv)) {
  +                continue;
  +            }
  +            else {
  +                ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
  +                             "write pipe_of_death");
  +                return rv;
  +            }
  +        }
  +    } while (1);
  +    
  +    apr_sockaddr_info_get(&sa, "127.0.0.1", APR_UNSPEC, ap_listeners->bind_addr->port, 0, pod->p);
  +    apr_socket_create(&sock, sa->family, SOCK_STREAM, pod->p);
  +    apr_connect(sock, sa);    
  +    apr_socket_close(sock);
   
  +    return APR_SUCCESS;
  +}
  +
  +AP_DECLARE(void) ap_mpm_pod_killpg(ap_pod_t *pod, int num)
  +{
  +    int i;
  +    for (i = 0; i < num; i++) {
  +        ap_mpm_pod_signal(pod);
  +    }
  +}
  +#endif
  
  
  
  1.12      +1 -0      httpd-2.0/server/mpm/prefork/mpm.h
  
  Index: mpm.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/prefork/mpm.h,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -d -b -w -u -r1.11 -r1.12
  --- mpm.h	2001/04/13 19:00:38	1.11
  +++ mpm.h	2001/06/07 00:09:16	1.12
  @@ -68,6 +68,7 @@
   
   #define MPM_NAME "Prefork"
   
  +#define AP_MPM_USES_POD 1
   #define AP_MPM_NEEDS_RECLAIM_CHILD_PROCESSES 1
   #define MPM_SYNC_CHILD_TABLE() (ap_sync_scoreboard_image())
   #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
  
  
  
  1.177     +31 -36    httpd-2.0/server/mpm/prefork/prefork.c
  
  Index: prefork.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/prefork/prefork.c,v
  retrieving revision 1.176
  retrieving revision 1.177
  diff -u -d -b -w -u -r1.176 -r1.177
  --- prefork.c	2001/06/04 04:00:03	1.176
  +++ prefork.c	2001/06/07 00:09:16	1.177
  @@ -140,6 +140,8 @@
   static int ap_daemons_max_free=0;
   static int ap_daemons_limit=0;
   
  +static ap_pod_t *pod;
  +
   /*
    * The max child slot ever assigned, preserved across restarts.  Necessary
    * to deal with MaxClients changes across SIGWINCH restarts.  We use this
  @@ -182,6 +184,8 @@
   char tpf_server_name[INETD_SERVNAME_LENGTH+1];
   #endif /* TPF */
   
  +int die_now = 0;
  +
   #ifdef GPROF
   /* 
    * change directory for gprof to plop the gmon.out file
  @@ -232,7 +236,7 @@
       if (pchild) {
   	apr_pool_destroy(pchild);
       }
  -    ap_scoreboard_image->parent[my_child_num].process_status = SB_WORKING;
  +    ap_mpm_pod_close(pod);
       chdir_for_gprof();
       exit(code);
   }
  @@ -378,15 +382,7 @@
   static void please_die_gracefully(int sig)
   {
       /* clean_child_exit(0); */
  -    ap_scoreboard_image->parent[my_child_num].process_status = SB_IDLE_DIE;
  -    if (sig == SIGHUP) {
  -        (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num),
  -                                      SERVER_GRACEFUL, (request_rec *) NULL);
  -    }
  -    else {
  -        (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num),
  -                                      SERVER_IDLE_KILL, (request_rec *) NULL);
  -    }
  +    die_now = 1;
   }
   
   /* volatile just in case */
  @@ -414,9 +410,11 @@
   	return;
       }
       restart_pending = 1;
  +#if 0
       if ((is_graceful = (sig == SIGWINCH))) {
           apr_pool_cleanup_kill(pconf, NULL, ap_cleanup_scoreboard);
       }
  +#endif
   }
   
   static void set_signals(void)
  @@ -479,12 +477,9 @@
   
       /* we want to ignore HUPs and WINCH while we're busy processing one */
       sigaddset(&sa.sa_mask, SIGHUP);
  -    sigaddset(&sa.sa_mask, SIGWINCH);
       sa.sa_handler = restart;
       if (sigaction(SIGHUP, &sa, NULL) < 0)
   	ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
  -    if (sigaction(SIGWINCH, &sa, NULL) < 0)
  -	ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGWINCH)");
   #else
       if (!one_process) {
   	apr_signal(SIGSEGV, sig_coredump);
  @@ -513,7 +508,7 @@
       apr_signal(SIGHUP, restart);
   #endif /* SIGHUP */
   #ifdef SIGWINCH
  -    apr_signal(SIGWINCH, restart);
  +    apr_signal(SIGWINCH, SIG_IGN);
   #endif /* SIGWINCH */
   #ifdef SIGPIPE
       apr_signal(SIGPIPE, SIG_IGN);
  @@ -533,9 +528,6 @@
   static int requests_this_child;
   static fd_set main_fds;
   
  -#define I_AM_TO_SHUTDOWN()                                                   \
  -(ap_scoreboard_image->parent[my_child_num].process_status != SB_WORKING)
  -   
   int ap_graceful_stop_signalled(void)
   {
       /* not ever called anymore... */
  @@ -581,12 +573,11 @@
       apr_signal(SIGHUP, please_die_gracefully);
   
       ap_sync_scoreboard_image();
  -    while (!I_AM_TO_SHUTDOWN()) {
  +    while (!die_now) {
   
   	/* Prepare to receive a SIGWINCH due to graceful restart so that
   	 * we can exit cleanly.
   	 */
  -	apr_signal(SIGWINCH, please_die_gracefully);
           apr_signal(SIGTERM, just_die);
   
   	/*
  @@ -669,14 +660,21 @@
   	     */
   	    for (;;) {
                   ap_sync_scoreboard_image();
  -		if (I_AM_TO_SHUTDOWN()) {
  +		if (die_now) {
   		    /* we didn't get a socket, and we were told to die */
   		    clean_child_exit(0);
   		}
   		stat = apr_accept(&csd, sd, ptrans);
   		if (stat == APR_SUCCESS || !APR_STATUS_IS_EINTR(stat))
   		    break;
  +                /* In reality, this could be done later, but to keep it
  +                 * consistent with MPMs that have a thread race-condition,
  +                 * we will do it here.
  +                 */
  +                if (!ap_mpm_pod_check(pod)) {
  +                    die_now = 1;
   	    }
  +	    }
   
   	    if (stat == APR_SUCCESS)
   		break;		/* We have a socket ready for reading */
  @@ -777,19 +775,13 @@
   	    }
   
               ap_sync_scoreboard_image();
  -	    if (I_AM_TO_SHUTDOWN()) {
  +	    if (die_now) {
   		clean_child_exit(0);
   	    }
   	}
   
   	SAFE_ACCEPT(accept_mutex_off());	/* unlock after "accept" */
   
  -	/* We've got a socket, let's at least process one request off the
  -	 * socket before we accept a graceful restart request.  We set
  -	 * the signal to ignore because we don't want to disturb any
  -	 * third party code.
  -	 */
  -	apr_signal(SIGWINCH, SIG_IGN);
   	/*
   	 * We now have a connection, so set it up with the appropriate
   	 * socket options, file descriptors, and read/write buffers.
  @@ -894,7 +886,6 @@
   	 * requested there's no race condition here.
   	 */
   	apr_signal(SIGHUP, please_die_gracefully);
  -	apr_signal(SIGWINCH, please_die_gracefully);
   	apr_signal(SIGTERM, just_die);
           ap_scoreboard_image->parent[slot].process_status = SB_WORKING;
   	child_main(slot);
  @@ -940,7 +931,7 @@
   #endif
   static int hold_off_on_exponential_spawning;
   
  -static void perform_idle_server_maintenance(void)
  +static void perform_idle_server_maintenance(apr_pool_t *p)
   {
       int i;
       int to_kill;
  @@ -1002,7 +993,7 @@
   	 * shut down gracefully, in case it happened to pick up a request
   	 * while we were counting
   	 */
  -	kill(ap_scoreboard_image->parent[to_kill].pid, SIGWINCH);
  +	ap_mpm_pod_signal(pod);
   	idle_spawn_rate = 1;
       }
       else if (idle_count < ap_daemons_min_free) {
  @@ -1088,6 +1079,7 @@
   {
       int index;
       int remaining_children_to_start;
  +    apr_status_t rv;
   
       pconf = _pconf;
   
  @@ -1099,6 +1091,11 @@
   	/* XXX: hey, what's the right way for the mpm to indicate a fatal error? */
   	return 1;
       }
  +    if ((rv = ap_mpm_pod_open(pconf, &pod))) {
  +        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
  +		"Could not open pipe-of-death.");
  +        return 1;
  +    }
   
       SAFE_ACCEPT(accept_mutex_init(pconf));
       if (!is_graceful) {
  @@ -1209,7 +1206,7 @@
   	    continue;
   	}
   
  -	perform_idle_server_maintenance();
  +	perform_idle_server_maintenance(pconf);
   #ifdef TPF
       shutdown_pending = os_check_server(tpf_server_name);
       ap_check_signals();
  @@ -1244,7 +1241,6 @@
   
       /* we've been told to restart */
       apr_signal(SIGHUP, SIG_IGN);
  -    apr_signal(SIGWINCH, SIG_IGN);
       if (one_process) {
   	/* not worth thinking about */
   	return 1;
  @@ -1264,12 +1260,11 @@
   
       if (is_graceful) {
   	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
  -		    "SIGWINCH received.  Doing graceful restart");
  +		    "Graceful restart requested, doing restart");
   
   	/* kill off the idle ones */
  -	if (unixd_killpg(getpgrp(), SIGWINCH) < 0) {
  -	    ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGWINCH");
  -	}
  +        ap_mpm_pod_killpg(pod, ap_daemons_limit);
  +
   #ifndef SCOREBOARD_FILE
   	/* This is mostly for debugging... so that we know what is still
   	    * gracefully dealing with existing request.  But we can't really
  
  
  

Re: cvs commit: httpd-2.0/server/mpm/prefork mpm.h prefork.c

Posted by rb...@covalent.net.
On Thu, 7 Jun 2001, Greg Stein wrote:

> On Thu, Jun 07, 2001 at 01:04:35PM -0400, Jeff Trawick wrote:
> >...
> > >   @@ -479,12 +477,9 @@
> > >
> > >        /* we want to ignore HUPs and WINCH while we're busy processing one */
> > >        sigaddset(&sa.sa_mask, SIGHUP);
> > >   -    sigaddset(&sa.sa_mask, SIGWINCH);
> > >        sa.sa_handler = restart;
> > >    	ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
> > >   -    if (sigaction(SIGWINCH, &sa, NULL) < 0)
> > >   -	ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
> > "sigaction(SIGWINCH)");
> > ditto
> > >    #else
> > >        if (!one_process) {
> > >    	apr_signal(SIGSEGV, sig_coredump);
> > >   @@ -513,7 +508,7 @@
> > >        apr_signal(SIGHUP, restart);
> > >    #endif /* SIGHUP */
> > >    #ifdef SIGWINCH
> > >   -    apr_signal(SIGWINCH, restart);
> > >   +    apr_signal(SIGWINCH, SIG_IGN);
> >
> > I'm extremely confused.  Don't we still use SIGWINCH vs. SIGHUP to
> > indicate the type of restart?
> >
> > Nothing is happening now in the parent for SIGWINCH (apachectl
> > graceful).  These are the suspect changes.
>
> When I run httpd using:
>
>     ./httpd -DONE_PROCESS -DNO_DETACH
>
> I find that I can no longer use ctrl-c to stop the thing. I've got to ctrl-z
> to suspend it, then kill it from the command line.
>
> Something is chewing up/ignoring the SIGQUIT. And pretty recently.

This has been happening for a while.  For a long time, I haven't been able
to ctrl-c the server while it is busy serving a request.

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------


Re: cvs commit: httpd-2.0/server/mpm/prefork mpm.h prefork.c

Posted by Greg Stein <gs...@lyra.org>.
On Thu, Jun 07, 2001 at 01:04:35PM -0400, Jeff Trawick wrote:
>...
> >   @@ -479,12 +477,9 @@
> >    
> >        /* we want to ignore HUPs and WINCH while we're busy processing one */
> >        sigaddset(&sa.sa_mask, SIGHUP);
> >   -    sigaddset(&sa.sa_mask, SIGWINCH);
> >        sa.sa_handler = restart;
> >    	ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
> >   -    if (sigaction(SIGWINCH, &sa, NULL) < 0)
> >   -	ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
> "sigaction(SIGWINCH)");
> ditto
> >    #else
> >        if (!one_process) {
> >    	apr_signal(SIGSEGV, sig_coredump);
> >   @@ -513,7 +508,7 @@
> >        apr_signal(SIGHUP, restart);
> >    #endif /* SIGHUP */
> >    #ifdef SIGWINCH
> >   -    apr_signal(SIGWINCH, restart);
> >   +    apr_signal(SIGWINCH, SIG_IGN);
> 
> I'm extremely confused.  Don't we still use SIGWINCH vs. SIGHUP to
> indicate the type of restart?
> 
> Nothing is happening now in the parent for SIGWINCH (apachectl
> graceful).  These are the suspect changes.

When I run httpd using:

    ./httpd -DONE_PROCESS -DNO_DETACH

I find that I can no longer use ctrl-c to stop the thing. I've got to ctrl-z
to suspend it, then kill it from the command line.

Something is chewing up/ignoring the SIGQUIT. And pretty recently.

Cheers,
-g

-- 
Greg Stein, http://www.lyra.org/

Re: cvs commit: httpd-2.0/server/mpm/prefork mpm.h prefork.c

Posted by Jeff Trawick <tr...@bellsouth.net>.
rbb@apache.org writes:

>   First pass at the pipe_of_death logic for the prefork MPM.  This does
>   pass some initial testing, but it needs to be banged on more.  It looks
>   like if the server gets a lot of requests to restart all at once, there
>   are potential problems, but other than that this does seem to solve our
>   current restart issues.
...
>   1.177     +31 -36    httpd-2.0/server/mpm/prefork/prefork.c
>   
>   Index: prefork.c
>   ===================================================================
>   RCS file: /home/cvs/httpd-2.0/server/mpm/prefork/prefork.c,v
>   retrieving revision 1.176
>   retrieving revision 1.177
>   diff -u -d -b -w -u -r1.176 -r1.177
>   --- prefork.c	2001/06/04 04:00:03	1.176
>   +++ prefork.c	2001/06/07 00:09:16	1.177
...
>   @@ -414,9 +410,11 @@
>    	return;
>        }
>        restart_pending = 1;
>   +#if 0
>        if ((is_graceful = (sig == SIGWINCH))) {
>            apr_pool_cleanup_kill(pconf, NULL, ap_cleanup_scoreboard);
>        }
>   +#endif

I think setting is_graceful is still important... no opinion on the
apr_pool_cleanup_kill() call

>   @@ -479,12 +477,9 @@
>    
>        /* we want to ignore HUPs and WINCH while we're busy processing one */
>        sigaddset(&sa.sa_mask, SIGHUP);
>   -    sigaddset(&sa.sa_mask, SIGWINCH);
>        sa.sa_handler = restart;
>    	ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
>   -    if (sigaction(SIGWINCH, &sa, NULL) < 0)
>   -	ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
"sigaction(SIGWINCH)");
ditto
>    #else
>        if (!one_process) {
>    	apr_signal(SIGSEGV, sig_coredump);
>   @@ -513,7 +508,7 @@
>        apr_signal(SIGHUP, restart);
>    #endif /* SIGHUP */
>    #ifdef SIGWINCH
>   -    apr_signal(SIGWINCH, restart);
>   +    apr_signal(SIGWINCH, SIG_IGN);

I'm extremely confused.  Don't we still use SIGWINCH vs. SIGHUP to
indicate the type of restart?

Nothing is happening now in the parent for SIGWINCH (apachectl
graceful).  These are the suspect changes.

-- 
Jeff Trawick | trawickj@bellsouth.net | PGP public key at web site:
       http://www.geocities.com/SiliconValley/Park/9289/
             Born in Roswell... married an alien...