dgaudet     98/12/04 11:12:18

  Modified:    src/include ap_mmn.h scoreboard.h
               src/main http_main.c
               src/modules/standard mod_status.c
  Log:
  - Jim's fix to the vhostrec problem wasn't sufficient for all cases...
  implement the full generation-based solution I proposed.
  - Deal with generation rollover a little more robustly.  Still not perfect.
  
  Revision  Changes    Path
  1.12      +5 -2      apache-1.3/src/include/ap_mmn.h
  
  Index: ap_mmn.h
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/include/ap_mmn.h,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- ap_mmn.h  1998/11/20 21:17:25     1.11
  +++ ap_mmn.h  1998/12/04 19:12:15     1.12
  @@ -184,11 +184,14 @@
    * 19981108 (1.3.4-dev) - added ap_method_number_of()
    *                      - changed value of M_INVALID and added WebDAV methods
    * 19981108.1           - ap_exists_config_define() is now public (minor 
bump)
  - *
  + * 19981204             - scoreboard changes -- added generation, changed
  + *                        exit_generation to running_generation.  Somewhere
  + *                        earlier vhostrec was added, but it's only safe to 
use
  + *                        as of this rev.  See scoreboard.h for 
documentation.
    */
   
   #ifndef MODULE_MAGIC_NUMBER_MAJOR
  -#define MODULE_MAGIC_NUMBER_MAJOR 19981108
  +#define MODULE_MAGIC_NUMBER_MAJOR 19981204
   #endif
   #define MODULE_MAGIC_NUMBER_MINOR 1                     /* 0...n */
   #define MODULE_MAGIC_NUMBER MODULE_MAGIC_NUMBER_MAJOR        /* backward 
compat */
  
  
  
  1.44      +29 -2     apache-1.3/src/include/scoreboard.h
  
  Index: scoreboard.h
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/include/scoreboard.h,v
  retrieving revision 1.43
  retrieving revision 1.44
  diff -u -r1.43 -r1.44
  --- scoreboard.h      1998/11/06 22:42:41     1.43
  +++ scoreboard.h      1998/12/04 19:12:15     1.44
  @@ -106,6 +106,29 @@
    */
   typedef unsigned vtime_t;
   
  +/* Type used for generation indicies.  Startup and every restart cause a
  + * new generation of children to be spawned.  Children within the same
  + * generation share the same configuration information -- pointers to stuff
  + * created at config time in the parent are valid across children.  For
  + * example, the vhostrec pointer in the scoreboard below is valid in all
  + * children of the same generation.
  + *
  + * The safe way to access the vhost pointer is like this:
  + *
  + * short_score *ss = pointer to whichver slot is interesting;
  + * parent_score *ps = pointer to whichver slot is interesting;
  + * server_rec *vh = ss->vhostrec;
  + *
  + * if (ps->generation != ap_my_generation) {
  + *     vh = NULL;
  + * }
  + *
  + * then if vh is not NULL it's valid in this child.
  + *
  + * This avoids various race conditions around restarts.
  + */
  +typedef int ap_generation_t;
  +
   /* stuff which the children generally write, and the parent mainly reads */
   typedef struct {
   #ifdef OPTIMIZE_TIMEOUTS
  @@ -135,11 +158,12 @@
       char client[32];         /* Keep 'em small... */
       char request[64];                /* We just want an idea... */
       server_rec *vhostrec;    /* What virtual host is being accessed? */
  +                                /* SEE ABOVE FOR SAFE USAGE! */
   } short_score;
   
   typedef struct {
  -    int exit_generation;     /* Set by the main process if a graceful
  -                                restart is required */
  +    ap_generation_t running_generation;      /* the generation of children 
which
  +                                         * should still be serving requests. 
*/
   } global_score;
   
   /* stuff which the parent generally writes and the children rarely read */
  @@ -149,6 +173,7 @@
       time_t last_rtime;               /* time(0) of the last change */
       vtime_t last_vtime;              /* the last vtime the parent has seen */
   #endif
  +    ap_generation_t generation;      /* generation of this child */
   } parent_score;
   
   typedef struct {
  @@ -163,6 +188,8 @@
   API_EXPORT(int) ap_exists_scoreboard_image(void);
   
   API_VAR_EXPORT extern scoreboard *ap_scoreboard_image;
  +
  +API_VAR_EXPORT extern ap_generation_t ap_my_generation;
   
   /* for time_process_request() in http_main.c */
   #define START_PREQUEST 1
  
  
  
  1.408     +56 -60    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.407
  retrieving revision 1.408
  diff -u -r1.407 -r1.408
  --- http_main.c       1998/12/03 01:07:54     1.407
  +++ http_main.c       1998/12/04 19:12:16     1.408
  @@ -1531,12 +1531,6 @@
    * We begin with routines which deal with the file itself... 
    */
   
  -/* volatile just in case */
  -static int volatile shutdown_pending;
  -static int volatile restart_pending;
  -static int volatile is_graceful;
  -static int volatile generation;
  -
   #ifdef MULTITHREAD
   /*
    * In the multithreaded mode, have multiple threads - not multiple
  @@ -1548,14 +1542,8 @@
   static void reinit_scoreboard(pool *p)
   {
       ap_assert(!ap_scoreboard_image);
  -    if (is_graceful) {
  -        int i;
  -        for (i = 0; i < HARD_SERVER_LIMIT; i++)
  -            ap_scoreboard_image->servers[i].vhostrec = NULL;
  -    } else {
  -        ap_scoreboard_image = (scoreboard *) malloc(SCOREBOARD_SIZE);
  -        memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
  -    }
  +    ap_scoreboard_image = (scoreboard *) malloc(SCOREBOARD_SIZE);
  +    memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
   }
   
   void cleanup_scoreboard(void)
  @@ -1636,7 +1624,7 @@
                ap_server_argv0);
       }
       ap_scoreboard_image = (scoreboard *) m;
  -    ap_scoreboard_image->global.exit_generation = 0;
  +    ap_scoreboard_image->global.running_generation = 0;
   }
   
   static void reopen_scoreboard(pool *p)
  @@ -1723,7 +1711,7 @@
       close(fd);
       ap_register_cleanup(p, NULL, cleanup_shared_mem, ap_null_cleanup);
       ap_scoreboard_image = (scoreboard *) m;
  -    ap_scoreboard_image->global.exit_generation = 0;
  +    ap_scoreboard_image->global.running_generation = 0;
   }
   
   static void reopen_scoreboard(pool *p)
  @@ -1803,7 +1791,7 @@
       close(fd);
   #endif
       ap_scoreboard_image = (scoreboard *) m;
  -    ap_scoreboard_image->global.exit_generation = 0;
  +    ap_scoreboard_image->global.running_generation = 0;
   }
   
   static void reopen_scoreboard(pool *p)
  @@ -1895,7 +1883,7 @@
            "sbrk() could not move break back");
       }
   #endif
  -    ap_scoreboard_image->global.exit_generation = 0;
  +    ap_scoreboard_image->global.running_generation = 0;
   }
   
   static void reopen_scoreboard(pool *p)
  @@ -1962,41 +1950,32 @@
   /* Called by parent process */
   static void reinit_scoreboard(pool *p)
   {
  -    if (is_graceful && ap_scoreboard_image) {
  -        int i;
  -        for (i = 0; i < HARD_SERVER_LIMIT; i++)
  -            ap_scoreboard_image->servers[i].vhostrec = NULL;
  -#ifdef SCOREBOARD_FILE
  -            force_write(scoreboard_fd, ap_scoreboard_image, 
sizeof(*ap_scoreboard_image));
  -#endif
  -    } else {
  -        int exit_gen = 0;
  -        if (ap_scoreboard_image)
  -            exit_gen = ap_scoreboard_image->global.exit_generation;
  +    int running_gen = 0;
  +    if (ap_scoreboard_image)
  +     running_gen = ap_scoreboard_image->global.running_generation;
   
   #ifndef SCOREBOARD_FILE
  -        if (ap_scoreboard_image == NULL) {
  -            setup_shared_mem(p);
  -        }
  -        memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
  -        ap_scoreboard_image->global.exit_generation = exit_gen;
  +    if (ap_scoreboard_image == NULL) {
  +     setup_shared_mem(p);
  +    }
  +    memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
  +    ap_scoreboard_image->global.running_generation = running_gen;
   #else
  -        ap_scoreboard_image = &_scoreboard_image;
  -        ap_scoreboard_fname = ap_server_root_relative(p, 
ap_scoreboard_fname);
  +    ap_scoreboard_image = &_scoreboard_image;
  +    ap_scoreboard_fname = ap_server_root_relative(p, ap_scoreboard_fname);
   
  -        scoreboard_fd = ap_popenf(p, ap_scoreboard_fname, O_CREAT | O_BINARY 
| O_RDWR, 0644);
  -        if (scoreboard_fd == -1) {
  -            perror(ap_scoreboard_fname);
  -            fprintf(stderr, "Cannot open scoreboard file:\n");
  -            exit(APEXIT_INIT);
  -        }
  -        ap_register_cleanup(p, NULL, cleanup_scoreboard_file, 
ap_null_cleanup);
  +    scoreboard_fd = ap_popenf(p, ap_scoreboard_fname, O_CREAT | O_BINARY | 
O_RDWR, 0644);
  +    if (scoreboard_fd == -1) {
  +     perror(ap_scoreboard_fname);
  +     fprintf(stderr, "Cannot open scoreboard file:\n");
  +     exit(APEXIT_INIT);
  +    }
  +    ap_register_cleanup(p, NULL, cleanup_scoreboard_file, ap_null_cleanup);
   
  -        memset((char *) ap_scoreboard_image, 0, 
sizeof(*ap_scoreboard_image));
  -        ap_scoreboard_image->global.exit_generation = exit_gen;
  -        force_write(scoreboard_fd, ap_scoreboard_image, 
sizeof(*ap_scoreboard_image));
  +    memset((char *) ap_scoreboard_image, 0, sizeof(*ap_scoreboard_image));
  +    ap_scoreboard_image->global.running_generation = running_gen;
  +    force_write(scoreboard_fd, ap_scoreboard_image, 
sizeof(*ap_scoreboard_image));
   #endif
  -    }
   }
   
   /* Routines called to deal with the scoreboard image
  @@ -2572,6 +2551,12 @@
       deferred_die = 1;
   }
   
  +/* volatile just in case */
  +static int volatile shutdown_pending;
  +static int volatile restart_pending;
  +static int volatile is_graceful;
  +int volatile ap_my_generation;
  +
   #ifdef WIN32
   /*
    * Signalling Apache on NT.
  @@ -3618,7 +3603,7 @@
        ap_clear_pool(ptrans);
   
        ap_sync_scoreboard_image();
  -     if (ap_scoreboard_image->global.exit_generation >= generation) {
  +     if (ap_scoreboard_image->global.running_generation != ap_my_generation) 
{
            clean_child_exit(0);
        }
   
  @@ -3759,7 +3744,7 @@
             * without reliable signals
             */
            ap_sync_scoreboard_image();
  -         if (ap_scoreboard_image->global.exit_generation >= generation) {
  +         if (ap_scoreboard_image->global.running_generation != 
ap_my_generation) {
                clean_child_exit(0);
            }
        }
  @@ -3864,7 +3849,7 @@
                                       (request_rec *) NULL);
   
            ap_sync_scoreboard_image();
  -         if (ap_scoreboard_image->global.exit_generation >= generation) {
  +         if (ap_scoreboard_image->global.running_generation != 
ap_my_generation) {
                ap_bclose(conn_io);
                clean_child_exit(0);
            }
  @@ -3932,6 +3917,16 @@
       Explain1("Starting new child in slot %d", slot);
       (void) ap_update_child_status(slot, SERVER_STARTING, (request_rec *) 
NULL);
   
  +    /* clean up the slot's vhostrec pointer now that it is being re-used,
  +     * and mark the slot as beloging to a new generation.
  +     */
  +    /* XXX: there's still a race condition here for file-based scoreboards...
  +     * but... like, do we really care to spend yet another write() operation
  +     * here? -djg
  +     */
  +    ap_scoreboard_image->servers[slot].vhostrec = NULL;
  +    ap_scoreboard_image->parent[slot].generation = ap_my_generation;
  +
   #ifndef _OSD_POSIX
       if ((pid = fork()) == -1) {
   #else /*_OSD_POSIX*/
  @@ -4229,7 +4224,6 @@
       ap_standalone = 1;
   
       is_graceful = 0;
  -    ++generation;
   
       if (!one_process) {
        detach();
  @@ -4262,7 +4256,9 @@
        ap_init_modules(pconf, server_conf);
        version_locked++;       /* no more changes to server_version */
        SAFE_ACCEPT(accept_mutex_init(pconf));
  -     reinit_scoreboard(pconf);
  +     if (!is_graceful) {
  +         reinit_scoreboard(pconf);
  +     }
   #ifdef SCOREBOARD_FILE
        else {
            ap_scoreboard_fname = ap_server_root_relative(pconf, 
ap_scoreboard_fname);
  @@ -4406,14 +4402,16 @@
            clean_parent_exit(0);
        }
   
  +     /* advance to the next generation */
  +     /* XXX: we really need to make sure this new generation number isn't in
  +      * use by any of the children.
  +      */
  +     ++ap_my_generation;
        if (is_graceful) {
   #ifndef SCOREBOARD_FILE
            int i;
   #endif
  -
  -         /* USE WITH CAUTION:  Graceful restarts are not known to work
  -          * in various configurations on the architectures we support. */
  -         ap_scoreboard_image->global.exit_generation = generation;
  +         ap_scoreboard_image->global.running_generation = ap_my_generation;
            update_scoreboard_global();
   
            ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
  @@ -4446,7 +4444,6 @@
            ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
                        "SIGHUP received.  Attempting to restart");
        }
  -     ++generation;
       } while (restart_pending);
   
       /*add_common_vars(NULL);*/
  @@ -5168,7 +5165,7 @@
   
       my_pid = getpid();
   
  -    ++generation;
  +    ++ap_my_generation;
   
       copy_listeners(pconf);
       ap_restart_time = time(NULL);
  @@ -5548,7 +5545,6 @@
       processes_to_create = nchild;
   
       is_graceful = 0;
  -    ++generation;
   
       ap_snprintf(signal_prefix_string, sizeof(signal_prefix_string),
                "ap%d", getpid());
  @@ -5709,7 +5705,7 @@
                        "SetEvent for child process in slot #%d", i);
            }
        }
  -     ++generation;
  +     ++ap_my_generation;
       } while (restart_pending);
   
       /* If we dropped out of the loop we definitly want to die completely. We 
need to
  
  
  
  1.103     +6 -6      apache-1.3/src/modules/standard/mod_status.c
  
  Index: mod_status.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/modules/standard/mod_status.c,v
  retrieving revision 1.102
  retrieving revision 1.103
  diff -u -r1.102 -r1.103
  --- mod_status.c      1998/12/03 14:38:05     1.102
  +++ mod_status.c      1998/12/04 19:12:18     1.103
  @@ -254,7 +254,7 @@
       char stat_buffer[HARD_SERVER_LIMIT];
       int pid_buffer[HARD_SERVER_LIMIT];
       clock_t tu, ts, tcu, tcs;
  -    char *vhost;
  +    server_rec *vhost;
   
       tu = ts = tcu = tcs = 0;
   
  @@ -309,10 +309,6 @@
       for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
        score_record = ap_scoreboard_image->servers[i];
        ps_record = ap_scoreboard_image->parent[i];
  -     if (score_record.vhostrec)
  -         vhost = score_record.vhostrec->server_hostname;
  -     else
  -         vhost = "NULL";
        res = score_record.status;
        stat_buffer[i] = status_flags[res];
        pid_buffer[i] = (int) ps_record.pid;
  @@ -492,6 +488,10 @@
        for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
            score_record = ap_scoreboard_image->servers[i];
            ps_record = ap_scoreboard_image->parent[i];
  +         vhost = score_record.vhostrec;
  +         if (ps_record.generation != ap_my_generation) {
  +             vhost = NULL;
  +         }
   
   #if defined(NO_GETTIMEOFDAY)
   #ifndef NO_TIMES
  @@ -658,7 +658,7 @@
                            ap_rprintf(r,
                             "<td>%s<td nowrap>%s<td nowrap>%s</tr>\n\n",
                             score_record.client,
  -                          (score_record.vhostrec ? vhost : "NULL"),
  +                          vhost ? vhost->server_hostname : "(unavailable)",
                             ap_escape_html(r->pool, score_record.request));
                    }           /* no_table_report */
                }                       /* !short_report */
  
  
  

Reply via email to