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(); }