rbb 99/02/11 14:15:56
Modified: pthreads/src/main fdqueue.c http_main.c
Log:
Another pass at logic for signal handling. SIGTERM works properly. SIGHUP
causes a zombie, and makes the socket unusable. Graceful restarts are not
close to working, because of signals issues with user based pthreads. They
are on the plate for tomorrow.
Manoj and I worked on this together, both design and implementation.
Revision Changes Path
1.3 +2 -3 apache-apr/pthreads/src/main/fdqueue.c
Index: fdqueue.c
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/main/fdqueue.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- fdqueue.c 1999/02/09 22:04:14 1.2
+++ fdqueue.c 1999/02/11 22:15:55 1.3
@@ -49,9 +49,8 @@
if (pthread_mutex_lock(&queue->one_big_mutex) != 0) {
return FD_QUEUE_FAILURE;
}
- while (queue->head == queue->tail) {
- pthread_cond_wait(&queue->not_empty, &queue->one_big_mutex);
- }
+ pthread_cond_wait(&queue->not_empty, &queue->one_big_mutex);
+
fd = queue->data[queue->head].fd;
*addr = queue->data[queue->head].addr;
/* If the queue was full, signal that it no longer is */
1.17 +100 -61 apache-apr/pthreads/src/main/http_main.c
Index: http_main.c
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/main/http_main.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- http_main.c 1999/02/11 16:33:04 1.16
+++ http_main.c 1999/02/11 22:15:55 1.17
@@ -175,7 +175,9 @@
int ap_listenbacklog;
int ap_dump_settings = 0;
API_VAR_EXPORT int ap_extended_status = 0;
+pthread_once_t firstcall = PTHREAD_ONCE_INIT;
+
/*
* The max child slot ever assigned, preserved across restarts. Necessary
* to deal with MaxClients changes across SIGUSR1 restarts. We use this
@@ -480,15 +482,58 @@
}
}
+void graceful_killer(void)
+{
+ listen_rec *lr;
+ int i;
+
+ for (i = 0; i < ap_threads_per_child; i++) {
+ pthread_cond_signal(&(csd_queue.not_empty));
+ }
+ /* Setup acceptor threads */
+
+ lr = ap_listeners;
+ while (lr->next != NULL) {
+ close(lr->fd);
+ lr= lr->next;
+ }
+ fprintf(stderr, "gonna exit doit");
+ pthread_exit(NULL);
+}
+
+static int find_child_by_pid(pid_t pid) /* ZZZ */
+{
+ int i;
+
+ for (i = 0; i < max_daemons_limit; ++i)
+ if (ap_scoreboard_image->parent[i].pid == pid)
+ return i;
+
+ return -1;
+}
+
/* a clean exit from a child with proper cleanup
static void clean_child_exit(int code) __attribute__ ((noreturn)); */
static void clean_child_exit(int code)
{
+ int child_num = find_child_by_pid(getpid());
+ int i;
+ listen_rec *lr;
+
+ /* lr = ap_listeners;
+ while (lr->next != NULL) {
+ close(lr->fd);
+ lr= lr->next;
+ }*/
+
+ for (i = 0; i < max_threads_limit; i++)
+ ap_update_child_status(child_num, i, SERVER_DEAD, (request_rec *)
NULL);
+
if (pchild) {
ap_child_exit_modules(pchild, server_conf);
ap_destroy_pool(pchild);
}
- /* longjump(tls()->thread_exit, 1); */
+
exit(code);
}
@@ -834,8 +879,6 @@
if (child_num < 0)
return -1;
- fprintf(stderr, "Updating status for %d %d to %d\n", child_num,
thread_num, status);
-
ss = &ap_scoreboard_image->servers[child_num][thread_num];
old_status = ss->status;
ss->status = status;
@@ -932,17 +975,6 @@
}
-static int find_child_by_pid(pid_t pid) /* ZZZ */
-{
- int i;
-
- for (i = 0; i < max_daemons_limit; ++i)
- if (ap_scoreboard_image->parent[i].pid == pid)
- return i;
-
- return -1;
-}
-
static void reclaim_child_processes(int terminate)
{
int i, status;
@@ -985,18 +1017,9 @@
case 2: /* 82ms */
break;
case 3: /* 344ms */
- /* perhaps it missed the SIGHUP, lets try again */
- ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
- server_conf,
- "child process %d did not exit, sending another SIGHUP",
- pid);
- kill(pid, SIGHUP);
- waittime = 1024 * 16;
- break;
case 4: /* 16ms */
case 5: /* 82ms */
case 6: /* 344ms */
- break;
case 7: /* 1.4sec */
/* ok, now it's being annoying */
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
@@ -1266,15 +1289,12 @@
static int volatile usr1_just_die = 1;
static int volatile deferred_die;
-static void usr1_handler(int sig)
+static void graceful_sig_handler(int sig)
{
- if (usr1_just_die) {
- just_die(sig);
- }
- deferred_die = 1;
+ fprintf(stderr, "Got a HUP from parent");
+ requests_this_child = 0;
}
-
/*****************************************************************
* Connection structures and accounting...
*/
@@ -1319,6 +1339,8 @@
/* do a graceful restart if graceful == 1 */
void ap_start_restart(int graceful)
{
+
+ fprintf(stderr, " SENDING A RESTART MESSAGE!!");
if (restart_pending == 1) {
/* Probably not an error - don't bother reporting it */
return;
@@ -1398,14 +1420,14 @@
sigaddset(&sa.sa_mask, SIGHUP);
#ifndef LINUX
sigaddset(&sa.sa_mask, SIGUSR1);
-#endif /* LINUX */
+#endif
sa.sa_handler = restart;
if (sigaction(SIGHUP, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
"sigaction(SIGHUP)");
-#ifndef LINUX
+#ifndef LINUX
if (sigaction(SIGUSR1, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
"sigaction(SIGUSR1)");
-#endif /* LINUX */
+#endif
#else
if (!one_process) {
signal(SIGSEGV, sig_coredump);
@@ -1431,14 +1453,14 @@
signal(SIGTERM, sig_term);
#ifdef SIGHUP
- signal(SIGHUP, restart);
+ signal(SIGHUP, sig_hup);
#endif /* SIGHUP */
#ifndef LINUX
#ifdef SIGUSR1
signal(SIGUSR1, restart);
#endif /* SIGUSR1 */
-#endif /* LINUX */
#endif
+#endif
}
/*****************************************************************
@@ -1572,7 +1594,7 @@
"make_sock: for %s, setsockopt: (SO_REUSEADDR)", addr);
printf("make_sock: failed to setsockopt for %s\n", addr);
close(s);
- return NULL;
+ return 0;
}
#endif /*_OSD_POSIX*/
one = 1;
@@ -1582,7 +1604,7 @@
ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
"make_sock: for %s, setsockopt: (SO_KEEPALIVE)", addr);
close(s);
- return NULL;
+ return 0;
}
#endif
#endif
@@ -1663,7 +1685,7 @@
"found, you probably need to rebuild Apache with a "
"larger FD_SETSIZE", addr, s, FD_SETSIZE);
close(s);
- return NULL;
+ return 0;
}
#endif
@@ -1718,7 +1740,7 @@
return or->fd;
}
}
- return NULL;
+ return 0;
}
@@ -1747,7 +1769,7 @@
num_listenfds = 0;
for (;;) {
fd = find_listener(lr);
- if (fd == NULL) {
+ if (fd == 0) {
fd = make_sock(p, &lr->local_addr);
}
else {
@@ -2038,23 +2060,27 @@
* Let's setup the socket options on the master socket. These
* will be inherited by any dup'ed sockets for us. No reason to do
* this oce for each request.
- */
- sock_disable_nagle(sd);
+ sock_disable_nagle(sd);
+ */
(void) ap_update_child_status(my_pid, my_tid, SERVER_READY,
(request_rec *) NULL);
- for (;;) {
+ while (0 < requests_this_child) {
csd = accept(sd, &sa_client, &len);
if (csd >= 0) {
if (queue_push(&csd_queue, csd, &sa_client) != 0) {
/* ap_log_error*/
- }
+ }
} else{
- /* ap_log_error()*/
- }
- /* thread_exit */
+ /* ap_log_error()*/
+ }
}
+ ap_update_child_status(my_pid, my_tid, SERVER_DEAD, (request_rec *)
NULL);
+ pthread_once(&firstcall, graceful_killer);
+ fprintf(stderr, "gonna exit accept thread");
+
+ pthread_exit(NULL);
}
void * worker_thread(void * dummy)
@@ -2068,12 +2094,18 @@
(void) ap_update_child_status(my_pid, my_tid, SERVER_READY,
(request_rec *) NULL);
-
- for (;;) {
+
+ while (0 < requests_this_child) {
int csd = queue_pop(&csd_queue, &sa_client);
- pthread_t tid = pthread_self();
- process_socket(pchild, &sa_client, csd, my_pid, my_tid);
+ if (csd >= 0) {
+ process_socket(pchild, &sa_client, csd, my_pid, my_tid);
+ }
}
+ ap_update_child_status(my_pid, my_tid, SERVER_DEAD, (request_rec *)
NULL);
+ pthread_once(&firstcall, graceful_killer);
+ fprintf(stderr, "gonna exit worker thread");
+
+ pthread_exit(NULL);
}
/*****************************************************************
@@ -2211,10 +2243,12 @@
pthread_attr_t thread_attr;
my_pid = getpid();
- requests_this_child = 0;
+ requests_this_child = ap_max_requests_per_child;
pchild = ap_make_sub_pool(pconf);
+ pthread_detach(pthread_self());
+
/*stuff to do before we switch id's, so we have permissions.*/
reopen_scoreboard(pchild);
/* SAFE_ACCEPT(accept_mutex_child_init(pchild));*/
@@ -2237,6 +2271,7 @@
/* We don't want to have to pthread_wait on these threads */
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+#if 0
/* Set signal masks for threads to basically nothing */
sigemptyset(&sig_mask);
#ifdef LINUX
@@ -2246,6 +2281,8 @@
if ((ret = pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) != 0) {
ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, "pthread_sigmask
failed");
}
+#endif
+
/* Setup worker threads */
for (i=0; i < ap_threads_per_child; i++) {
my_info = NULL;
@@ -2379,7 +2416,7 @@
RAISE_SIGSTOP(MAKE_CHILD);
MONCONTROL(1);
- signal(SIGHUP, just_die);
+ signal(SIGHUP, graceful_sig_handler);
signal(SIGTERM, just_die);
child_main(slot);
@@ -2445,7 +2482,7 @@
if (i >= max_daemons_limit && free_length == idle_spawn_rate)
break;
- for (j = 0; j < max_threads_limit; j++) {
+ for (j = 0; j < ap_threads_per_child; j++) {
ss = &ap_scoreboard_image->servers[i][j];
status = ss->status;
if (status == SERVER_DEAD) {
@@ -2488,7 +2525,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, SIGUSR1); */
+ kill(ap_scoreboard_image->parent[to_kill].pid, SIGHUP);
idle_spawn_rate = 1;
}
else if (idle_count < ap_daemons_min_free) {
@@ -2724,11 +2761,10 @@
"SIGUSR1 received. Doing graceful restart");
/* kill off the idle ones */
-#if 0
- if (ap_killpg(pgrp, SIGUSR1) < 0) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg
SIGUSR1");
+ if (ap_killpg(pgrp, SIGHUP) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg
SIGHUP");
}
-#endif
+
/* This is mostly for debugging... so that we know what is still
* gracefully dealing with existing request.
*/
@@ -2742,9 +2778,12 @@
}
}
else {
- /* Kill 'em all */
- if (ap_killpg(pgrp, SIGHUP) < 0) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg
SIGHUP");
+ /* Kill 'em all. Since the child acts the same on the parents SIGTERM
+ * and a SIGHUP, we may as well use the same signal, because some user
+ * pthreads are stealing signals from us left and right.
+ */
+ if (ap_killpg(pgrp, SIGTERM) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg
SIGTERM");
}
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
"SIGHUP received. Attempting to restart");