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");
  
  
  

Reply via email to