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...