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 */