stoddard 99/04/07 15:52:19
Modified: pthreads/src/include fdqueue.h
pthreads/src/main Makefile.tmpl fdqueue.c http_main.c
Added: pthreads/src/include http_accept.h
pthreads/src/main http_accept.c
Log:
Add accept loop abstraction. 4 new functions defined for http_accept.c:
accept_init()
begin_accepting_requests()
get_request()
stop_accepting_requests()
Revision Changes Path
1.7 +2 -2 apache-apr/pthreads/src/include/fdqueue.h
Index: fdqueue.h
===================================================================
RCS file: /export/home/cvs/apache-apr/pthreads/src/include/fdqueue.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- fdqueue.h 1999/02/23 19:11:18 1.6
+++ fdqueue.h 1999/04/07 22:52:16 1.7
@@ -29,10 +29,10 @@
pthread_cond_t not_full;
} FDQueue;
-int queue_init(FDQueue *queue, int regular, int overflow, pool *a);
+int queue_init(FDQueue *queue, int queue_size, pool *a);
void *queue_destroy(FDQueue *queue);
int queue_push(FDQueue *queue, int fd, struct sockaddr *addr);
-int queue_pop(FDQueue *queue, struct sockaddr *addr);
+int queue_pop(FDQueue *queue, struct sockaddr *addr, int block_if_empty);
int queue_size(FDQueue *queue);
int increase_blanks(FDQueue *queue);
int queue_full(FDQueue *queue);
1.1 apache-apr/pthreads/src/include/http_accept.h
Index: http_accept.h
===================================================================
/* ====================================================================
* Copyright (c) 1995-1999 The Apache Group. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* 4. The names "Apache Server" and "Apache Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Group and was originally based
* on public domain software written at the National Center for
* Supercomputing Applications, University of Illinois, Urbana-Champaign.
* For more information on the Apache Group and the Apache HTTP server
* project, please see <http://www.apache.org/>.
*
*/
#ifndef APACHE_HTTP_ACCEPT_H
#define APACHE_HTTP_ACCEPT_H
#ifdef __cplusplus
extern "C" {
#endif
#include "httpd.h"
#include "ap_config.h"
#define SAFE_ACCEPT(stmt) do {stmt;} while(0)
/* The info each server thread needs to start correctly.
*/
typedef struct {
int pid;
int tid;
int sd;
} proc_info;
#define USE_ACCEPT_QUEUE
#if defined (USE_ACCEPT_QUEUE)
void init_accept(pool*, int, int);
void start_accepting_requests(int);
int get_request(struct sockaddr *);
void stop_accepting_requests(pool*);
#elif defined (USE_MULTI_ACCEPT)
void init_accept(pool*);
#define start_accepting_requests(x, y)
int get_request(struct sockaddr *);
void stop_accepting_requests();
#endif
#ifdef __cplusplus
}
#endif
#endif /* APACHE_HTTP_ACCEPT_H */
1.7 +11 -1 apache-apr/pthreads/src/main/Makefile.tmpl
Index: Makefile.tmpl
===================================================================
RCS file: /export/home/cvs/apache-apr/pthreads/src/main/Makefile.tmpl,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- Makefile.tmpl 1999/03/05 16:45:55 1.6
+++ Makefile.tmpl 1999/04/07 22:52:17 1.7
@@ -11,7 +11,7 @@
http_config.o http_core.o http_log.o \
http_main.o http_protocol.o http_request.o http_vhost.o \
util.o util_date.o util_script.o util_uri.o util_md5.o \
- scoreboard.o rfc1413.o fdqueue.o acceptlock.o
+ scoreboard.o rfc1413.o fdqueue.o acceptlock.o http_accept.o
.c.o:
$(CC) -c $(INCLUDES) $(CFLAGS) $<
@@ -90,6 +90,16 @@
$(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/apr.h \
$(INCDIR)/util_uri.h
gen_uri_delims.o: gen_uri_delims.c
+http_accept.o: http_accept.c $(INCDIR)/httpd.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/apr.h \
+ $(INCDIR)/util_uri.h $(INCDIR)/http_main.h $(INCDIR)/http_log.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_protocol.h \
+ $(INCDIR)/http_request.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_core.h $(INCDIR)/http_vhost.h \
+ $(INCDIR)/util_script.h $(INCDIR)/fdqueue.h $(INCDIR)/acceptlock.h \
+ $(INCDIR)/http_accept.h
http_config.o: http_config.c $(INCDIR)/httpd.h $(INCDIR)/ap_config.h \
$(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
$(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h $(INCDIR)/hsregex.h \
1.13 +10 -5 apache-apr/pthreads/src/main/fdqueue.c
Index: fdqueue.c
===================================================================
RCS file: /export/home/cvs/apache-apr/pthreads/src/main/fdqueue.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- fdqueue.c 1999/03/03 16:02:45 1.12
+++ fdqueue.c 1999/04/07 22:52:18 1.13
@@ -3,16 +3,16 @@
/* Assumption: queue itself is allocated by the user */
/* Assumption: increment and decrement are atomic on int */
-int queue_init(FDQueue *queue, int regular, int overflow, pool *a) {
+int queue_init(FDQueue *queue, int queue_size, pool *a) {
int i;
- int bounds = regular + overflow + 1;
+ int bounds = queue_size + 1;
pthread_mutex_init(&queue->one_big_mutex, NULL);
pthread_cond_init(&queue->not_empty, NULL);
pthread_cond_init(&queue->not_full, NULL);
queue->head = queue->tail = 0;
queue->data = ap_palloc(a, bounds * sizeof(FDQueueElement));
queue->bounds = bounds;
- queue->blanks = regular;
+ queue->blanks = 0;
ap_register_cleanup(a, queue, (void (*)(void *))queue_destroy,
ap_null_cleanup);
for (i=0; i < bounds; ++i)
queue->data[i].fd = -1;
@@ -43,7 +43,7 @@
}
}
-int queue_pop(FDQueue *queue, struct sockaddr *addr) {
+int queue_pop(FDQueue *queue, struct sockaddr *addr, int block_if_empty) {
int fd;
if (pthread_mutex_lock(&queue->one_big_mutex) != 0) {
return FD_QUEUE_FAILURE;
@@ -52,7 +52,12 @@
pthread_cond_signal(&queue->not_full);
}
if (queue->head == queue->tail) {
- pthread_cond_wait(&queue->not_empty, &queue->one_big_mutex);
+ if (block_if_empty)
+ pthread_cond_wait(&queue->not_empty, &queue->one_big_mutex);
+ else {
+ pthread_mutex_unlock(&queue->one_big_mutex);
+ return -1;
+ }
}
fd = queue->data[queue->head].fd;
1.67 +24 -181 apache-apr/pthreads/src/main/http_main.c
Index: http_main.c
===================================================================
RCS file: /export/home/cvs/apache-apr/pthreads/src/main/http_main.c,v
retrieving revision 1.66
retrieving revision 1.67
diff -u -r1.66 -r1.67
--- http_main.c 1999/03/22 20:38:03 1.66
+++ http_main.c 1999/04/07 22:52:18 1.67
@@ -92,8 +92,8 @@
#include "util_script.h" /* to force util_script.c linking */
#include "util_uri.h"
#include "scoreboard.h"
-#include "fdqueue.h"
-#include "acceptlock.h"
+
+#include "http_accept.h"
#include <poll.h>
#include <netinet/tcp.h>
#include <stdio.h>
@@ -215,12 +215,6 @@
array_header *ap_server_config_defines;
pool *pchild; /* Pool for httpd child stuff */
-/* The queue of sockets we've accepted */
-static FDQueue csd_queue;
-
-/* Indicates that all acceptor threads are dead after SIGWINCH and the worker
- * threads can now exit */
-static int workers_may_exit = 0;
/* stuff that needs thread local store in main */
typedef struct {
@@ -228,14 +222,6 @@
int generation;
} tls_main_t;
-/* The info each server thread needs to start correctly.
- */
-typedef struct {
- int pid;
- int tid;
- int sd;
-} proc_info;
-
static pthread_key_t tls_main_key; /* ZZZZ */
static tls_main_t *gettls(pthread_key_t tls_main_key)
@@ -297,7 +283,7 @@
static int my_pid; /* for hybridization, we need this. Stupid to
call getpid all the time */
-static int requests_this_child;
+
/*
@@ -413,59 +399,11 @@
exit(code);
}
-/* Kill off any worker threads by kicking them out of whatever they are doing
- * and allowing them to see that requests_this_child == 0.
- * It is possible this function could be defined to be NULL in some accept
- * models.
- */
-
-void kill_workers(void)
-{
- int i;
- int index = find_child_by_pid(getpid());
- parent_score *ss = &ap_scoreboard_image->parent[index];
-
- pthread_cond_broadcast(&(csd_queue.not_empty));
- for (i = 0; i < ss->worker_threads; i++) {
- pthread_join(ap_scoreboard_image->servers[index][i].tid, NULL);
- }
-}
-
-/* Kill off any acceptor threads by kicking them out of what they are doing
- * and allowing them to see that requests_this_child == 0.
- * It is possible this function could be defined to be NULL in some accept
- * models.
- */
-void kill_acceptors(void)
-{
- listen_rec *lr;
- int i;
- int index = find_child_by_pid(getpid());
- parent_score *ss = &ap_scoreboard_image->parent[index];
-
-
- /* Kick acceptor threads out of accept */
- lr = ap_listeners;
- while (lr != NULL) {
- ap_pclosesocket(pconf, lr->fd);
- lr= lr->next;
- }
-
- /* Kick any acceptor out of blocking on a full queue */
- pthread_cond_broadcast(&(csd_queue.not_full));
-
- for (i = ss->worker_threads; i < ss->worker_threads +
ss->acceptor_threads; i++) {
- pthread_join(ap_scoreboard_image->servers[index][i].tid, NULL);
- }
-}
void graceful_killer(void)
{
- /* The two functions to get all of our other threads to die off. */
- kill_acceptors();
- workers_may_exit = 1;
- kill_workers();
+ stop_accepting_requests(pconf);
}
int ap_get_timeout(request_rec *r)
@@ -1066,7 +1004,6 @@
static void graceful_sig_handler(int sig)
{
- requests_this_child = 0;
ap_max_requests_per_child = 1;
}
@@ -1804,66 +1741,7 @@
#endif
}
-void * accept_thread(void * dummy)
-{
- proc_info * ti = dummy;
- int my_pid = ti->pid;
- int my_tid = ti->tid;
- int sd = ti->sd;
- int csd = 0;
- struct sockaddr sa_client;
- size_t len = sizeof(struct sockaddr);
-
- free(ti);
- /*
- * 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);
- */
-
- while ((ap_max_requests_per_child != 0 && requests_this_child > 0) ||
- (ap_max_requests_per_child == 0)) {
- (void) ap_update_child_status(my_pid, my_tid, SERVER_ACCEPTING,
- (request_rec *) NULL);
- /* lock around the accept if necessary */
- SAFE_ACCEPT(accept_mutex_on(my_tid - ap_threads_per_child));
- if (queue_full(&csd_queue)) {
- SAFE_ACCEPT(accept_mutex_off(my_tid - ap_threads_per_child));
- block_on_queue(&csd_queue);
- csd = -1;
- }
- else {
- requests_this_child--;
- csd = accept(sd, &sa_client, &len);
- SAFE_ACCEPT(accept_mutex_off(my_tid - ap_threads_per_child));
- }
- (void) ap_update_child_status(my_pid, my_tid, SERVER_QUEUEING,
- (request_rec *) NULL);
- if (csd >= 0) {
- if (queue_push(&csd_queue, csd, &sa_client) != 0) {
- ap_log_error(APLOG_MARK, APLOG_ERR, ap_get_server_conf(),
- "queue_push: couldn't put new connection on"
- "queue");
- }
- }
- }
-
- /* Raise SIGWINCH so that all the actions that go with a gradual,
- * graceful shutdown of the process get done.
- *
- * The reason this thread is actually going through the trouble to
- * look up its own process ID is because under Red Hat 5.2, getpid()
- * actually returns the "process ID" of the thread, since threads
- * are just processes that share everything. I hope this is fixed in
- * glibc 2.1 & Linux 2.2. - mvsk */
- kill(ap_scoreboard_image->parent[my_pid].pid, SIGWINCH);
- ap_update_child_status(my_pid, my_tid, SERVER_DEAD, (request_rec *)
NULL);
- return NULL;
-}
-
void * worker_thread(void * dummy)
{
proc_info * ti = dummy;
@@ -1876,17 +1754,18 @@
free(ti);
ptrans = ap_make_sub_pool(pchild);
- while (!(workers_may_exit && (queue_size(&csd_queue) == 0))) {
+
+ while (1) {
(void) ap_update_child_status(my_pid, my_tid, SERVER_READY,
(request_rec *) NULL);
-
- csd = queue_pop(&csd_queue, &sa_client);
- if (csd >= 0) {
- process_socket(ptrans, &sa_client, csd, my_pid, my_tid);
- increase_blanks(&csd_queue);
+ csd = get_request(&sa_client);
+ if (csd < 0) {
+ break;
}
+ process_socket(ptrans, &sa_client, csd, my_pid, my_tid);
ap_clear_pool(ptrans);
}
+
ap_destroy_pool(ptrans);
ap_update_child_status(my_pid, my_tid, SERVER_DEAD, (request_rec *)
NULL);
return NULL;
@@ -2023,8 +1902,10 @@
proc_info *my_info = NULL;
sigset_t sig_mask;
+
/* Setup worker threads */
for (i=0; i < ap_threads_per_child; i++) {
+
my_info = NULL;
my_info = (proc_info *)malloc(sizeof(proc_info));
@@ -2035,7 +1916,6 @@
/* We are creating threads right now */
(void) ap_update_child_status(my_child_num, i, SERVER_STARTING,
(request_rec *) NULL);
-
if (pthread_create(&thread, NULL, worker_thread, my_info)) {
ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
"pthread_create: unable to create worker thread");
@@ -2047,57 +1927,19 @@
(request_rec *) NULL);
exit(1); /* We won't always exit here, but for no this is okay */
}
+
/* We let each thread update it's own scoreboard entry. This is done
* because it let's us deal with tid better.
*/
- }
-
- /* Setup acceptor threads */
+ }
- lr = head_listener;
- if (lr) {
- while (lr->next != NULL) {
-
- (void) ap_update_child_status(my_child_num, i, SERVER_STARTING,
- (request_rec *) NULL);
- my_info = NULL;
-
- my_info = (proc_info *)malloc(sizeof(proc_info));
- my_info->pid = my_child_num;
- my_info->tid = i++;
- my_info->sd = lr->fd;
-
- if (pthread_create(&thread, NULL, accept_thread, my_info)) {
- ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
- "pthread_create: unable to create acceptor
thread");
- /*
- * We failed to create a thread. Update the scoreboard,
- * or it will say SERVER_STARTING forever.
- */
- exit(1);
- } else {
- /* We let each thread update it's own scoreboard entry. This is
done
- * because it let's us deal with tid better.
- */
- }
- lr = lr->next;
- }
- } else {
- /* no listening sockets???? Kill the server please. */
- exit(0);
- }
- (void) ap_update_child_status(my_child_num, i, SERVER_STARTING,
- (request_rec *) NULL);
+ /* Begin accepting requests
+ * Design:
+ *
+ */
+ start_accepting_requests(my_child_num);
- my_info = NULL;
-
- my_info = (proc_info *)malloc(sizeof(proc_info));
- my_info->pid = my_child_num;
- my_info->tid = i;
- my_info->sd = lr->fd;
-
- accept_thread(my_info);
}
static void child_main(int child_num_arg)
@@ -2108,14 +1950,15 @@
int temp = 0;
my_pid = getpid();
- requests_this_child = ap_max_requests_per_child;
+
pchild = ap_make_sub_pool(pconf);
/*stuff to do before we switch id's, so we have permissions.*/
reopen_scoreboard(pchild);
- SAFE_ACCEPT(accept_mutex_child_init(pchild));
+ init_accept(pchild, ap_threads_per_child, ap_acceptors_per_child);
+
set_group_privs();
if (!geteuid() && (setuid(ap_user_id) == -1)) {
@@ -2134,8 +1977,8 @@
if (pthread_sigmask(SIG_SETMASK, &sig_mask, NULL) != 0) {
ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
"pthread_sigmask");
}
+
- queue_init(&csd_queue, ap_threads_per_child, ap_acceptors_per_child,
pchild);
if (pthread_create(&thread, NULL, thread_starter_thread,
&child_num_arg)) {
ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
1.1 apache-apr/pthreads/src/main/http_accept.c
Index: http_accept.c
===================================================================
/* ====================================================================
* Copyright (c) 1995-1999 The Apache Group. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* 4. The names "Apache Server" and "Apache Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Group and was originally based
* on public domain software written at the National Center for
* Supercomputing Applications, University of Illinois, Urbana-Champaign.
* For more information on the Apache Group and the Apache HTTP server
* project, please see <http://www.apache.org/>.
*
*/
#include "httpd.h"
#include "http_log.h"
#include "http_conf_globals.h"
#include "acceptlock.h"
#include "fdqueue.h"
#include "scoreboard.h"
#include "http_accept.h"
#include <poll.h>
#include <netinet/tcp.h>
/* Indicates that all acceptor threads are dead after SIGWINCH and the worker
* threads can now exit */
static int workers_may_exit = 0;
/* The queue of sockets we've accepted */
static FDQueue csd_queue;
static int requests_this_child;
static void * accept_thread(void * dummy)
{
proc_info * ti = dummy;
int my_pid = ti->pid;
int my_tid = ti->tid;
int sd = ti->sd;
int csd = 0;
struct sockaddr sa_client;
size_t len = sizeof(struct sockaddr);
free(ti);
/*
* 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);
*/
while ((ap_max_requests_per_child != 0 && requests_this_child > 0) ||
(ap_max_requests_per_child == 0)) {
(void) ap_update_child_status(my_pid, my_tid, SERVER_ACCEPTING,
(request_rec *) NULL);
/* lock around the accept if necessary */
SAFE_ACCEPT(accept_mutex_on(my_tid - ap_threads_per_child));
if (queue_full(&csd_queue)) {
SAFE_ACCEPT(accept_mutex_off(my_tid - ap_threads_per_child));
block_on_queue(&csd_queue);
csd = -1;
}
else {
requests_this_child--;
csd = accept(sd, &sa_client, &len);
SAFE_ACCEPT(accept_mutex_off(my_tid - ap_threads_per_child));
}
(void) ap_update_child_status(my_pid, my_tid, SERVER_QUEUEING,
(request_rec *) NULL);
if (csd >= 0) {
if (queue_push(&csd_queue, csd, &sa_client) != 0) {
ap_log_error(APLOG_MARK, APLOG_ERR, ap_get_server_conf(),
"queue_push: couldn't put new connection on"
"queue");
}
}
}
/* Raise SIGWINCH so that all the actions that go with a gradual,
* graceful shutdown of the process get done.
*
* The reason this thread is actually going through the trouble to
* look up its own process ID is because under Red Hat 5.2, getpid()
* actually returns the "process ID" of the thread, since threads
* are just processes that share everything. I hope this is fixed in
* glibc 2.1 & Linux 2.2. - mvsk */
kill(ap_scoreboard_image->parent[my_pid].pid, SIGWINCH);
ap_update_child_status(my_pid, my_tid, SERVER_DEAD, (request_rec *) NULL);
return NULL;
}
/* Kill off any worker threads by kicking them out of whatever they are doing
* and allowing them to see that requests_this_child == 0.
* It is possible this function could be defined to be NULL in some accept
* models.
*/
static void kill_workers(void)
{
int i;
int index = find_child_by_pid(getpid());
parent_score *ss = &ap_scoreboard_image->parent[index];
pthread_cond_broadcast(&(csd_queue.not_empty));
for (i = 0; i < ss->worker_threads; i++) {
pthread_join(ap_scoreboard_image->servers[index][i].tid, NULL);
}
}
/* Kill off any acceptor threads by kicking them out of what they are doing
* and allowing them to see that requests_this_child == 0.
* It is possible this function could be defined to be NULL in some accept
* models.
*/
static void kill_acceptors(pool* pconf)
{
listen_rec *lr;
int i;
int index = find_child_by_pid(getpid());
parent_score *ss = &ap_scoreboard_image->parent[index];
/* Kick acceptor threads out of accept */
lr = ap_listeners;
while (lr != NULL) {
ap_pclosesocket(pconf, lr->fd);
lr= lr->next;
}
/* Kick any acceptor out of blocking on a full queue */
pthread_cond_broadcast(&(csd_queue.not_full));
for (i = ss->worker_threads; i < ss->worker_threads +
ss->acceptor_threads; i++) {
pthread_join(ap_scoreboard_image->servers[index][i].tid, NULL);
}
}
/*
* Description:
* Do any setup or initialization required before worker threads begin
* accepting connections
* Design questions:
* 1. what sort of arguments need to be passed on this call?
* 2. should the queue logic be simplified?
* 3. Pass in server_conf?
* 4. Simply access the globals (yech...)
*/
void init_accept(pool* pchild,
int worker_threads_per_child,
int acceptor_threads_per_child)
{
int queue_size = worker_threads_per_child + acceptor_threads_per_child;
SAFE_ACCEPT(accept_mutex_child_init(pchild));
requests_this_child = ap_max_requests_per_child;
queue_init(&csd_queue, queue_size, pchild);
}
void start_accepting_requests(int my_child_num)
{
proc_info *my_info;
pthread_t thread;
/*
* Yech, ap_listeners is a global declared in http_conf_globals.h
* and defined in http_main.c
*/
listen_rec *lr = ap_listeners;
/* Warning: Subtle code ahead
* 1. This code assumes the thing pointed to by ap_listeners is a NULL
terminated
* linked list.
*
* 2. The scoreboard size is ap_threads_per_child + ap_acceptors_per_child
* The acceptor entries are at the end of the scoreboard, so index into
the
* scoreboard beginning with ap_threads_per_child
* Perhaps a better approach is to create a new scoreboard accessor
method to
* fetch the index of the next free entry? And put in some bounds checking
* to prevent running off the end of the scoreboard? (ie, if
next_free_entry()
* returns NULL and we find ourselves needing another entry, we have a
logic
* bug that needs to be fixed...
* Perhaps we should create a scoreboard object with methods, etc.?
* ap_threads_per_child is a GLOBAL...
*/
int i = ap_threads_per_child;
if (lr) {
while (lr->next != NULL) {
(void) ap_update_child_status(my_child_num, i, SERVER_STARTING,
(request_rec *) NULL);
my_info = NULL;
my_info = (proc_info *) malloc(sizeof(proc_info));
my_info->pid = my_child_num;
my_info->tid = i++;
my_info->sd = lr->fd;
if (pthread_create(&thread, NULL, accept_thread, my_info)) {
ap_log_error(APLOG_MARK, APLOG_ALERT, (const server_rec*)
ap_get_server_conf(),
"pthread_create: unable to create acceptor
thread");
/*
* We failed to create a thread. Update the scoreboard,
* or it will say SERVER_STARTING forever.
*/
exit(1);
} else {
/* We let each thread update it's own scoreboard entry. This is
done
* because it let's us deal with tid better.
*/
}
lr = lr->next;
}
} else {
/* no listening sockets???? Kill the server please. */
exit(0);
}
(void) ap_update_child_status(my_child_num, i, SERVER_STARTING,
(request_rec *) NULL);
my_info = NULL;
my_info = (proc_info *) malloc(sizeof(proc_info));
my_info->pid = my_child_num;
my_info->tid = i;
my_info->sd = lr->fd;
accept_thread(my_info);
}
int get_request(struct sockaddr *sa_client)
{
int csd = -1;
int block_if_empty = 1;
increase_blanks(&csd_queue);
while (csd == -1) {
if (workers_may_exit)
block_if_empty = 0;
csd = queue_pop(&csd_queue, sa_client, block_if_empty);
if (workers_may_exit)
break;
}
return csd;
}
void stop_accepting_requests(pool* pconf) {
requests_this_child = 0;
/* The two functions to get all of our other threads to die off. */
kill_acceptors(pconf);
workers_may_exit = 1;
kill_workers();
}