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

Reply via email to