Commit 229217ee authored by Greg Ames's avatar Greg Ames
Browse files

Fix a problem where the threaded MPM stalls after restarts or segfaults.

Also prevent multiple active processes from using the same scoreboard slot.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@89761 13f79535-47bb-0310-9956-ffa450edef68
parent c78047ab
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -6,6 +6,10 @@ Changes with Apache 2.0.23

Changes with Apache 2.0.22
  
  *) Fix a problem where the threaded MPM stalls after restarts or
     segfaults.  Also prevent multiple active processes from using
     the same scoreboard slot.  [Greg Ames]

  *) Apache/Win32 now fills in the service description with Apache's
     server version string, including loaded and advertised modules.
     [William Rowe]
+3 −0
Original line number Diff line number Diff line
@@ -178,6 +178,9 @@ struct process_score{
    pid_t pid;
    ap_generation_t generation;	/* generation of this child */
    ap_scoreboard_e sb_type;
    int quiescing;          /* the process whose pid is stored above is
                             * going down gracefully
                             */
};

typedef struct {
+23 −3
Original line number Diff line number Diff line
@@ -648,8 +648,15 @@ static void * worker_thread(apr_thread_t *thd, void * dummy)
    apr_pool_destroy(tpool);
    ap_update_child_status(process_slot, thread_slot, (dying) ? SERVER_DEAD : SERVER_GRACEFUL,
        (request_rec *) NULL);
    dying = 1;
    apr_lock_acquire(worker_thread_count_mutex);
    if (!dying) {
        /* this is the first thread to exit */
        if (ap_my_pid == ap_scoreboard_image->parent[process_slot].pid) {
            /* tell the parent that it may use this scoreboard slot */
            ap_scoreboard_image->parent[process_slot].quiescing = 1;
        }   
        dying = 1;
    }
    worker_thread_count--;
    if (worker_thread_count == 0) {
        /* All the threads have exited, now finish the shutdown process
@@ -900,6 +907,7 @@ static int make_child(server_rec *s, int slot)
        clean_child_exit(0);
    }
    /* else */
    ap_scoreboard_image->parent[slot].quiescing = 0;
    ap_scoreboard_image->parent[slot].pid = pid;
    return 0;
}
@@ -961,6 +969,7 @@ static void perform_idle_server_maintenance(void)
    int i, j;
    int idle_thread_count;
    worker_score *ws;
    process_score *ps;
    int free_length;
    int free_slots[MAX_SPAWN_RATE];
    int last_non_dead;
@@ -985,6 +994,7 @@ static void perform_idle_server_maintenance(void)

	if (i >= ap_max_daemons_limit && free_length == idle_spawn_rate)
	    break;
        ps = &ap_scoreboard_image->parent[i];
	for (j = 0; j < ap_threads_per_child; j++) {
            ws = &ap_scoreboard_image->servers[i][j];
	    status = ws->status;
@@ -998,11 +1008,19 @@ static void perform_idle_server_maintenance(void)
	     * So we hopefully won't need to fork more if we count it.
	     * This depends on the ordering of SERVER_READY and SERVER_STARTING.
	     */
	    if (status <= SERVER_READY && status != SERVER_DEAD) {
	    if (status <= SERVER_READY && status != SERVER_DEAD &&
                    ps->generation == ap_my_generation && 
                 /* XXX the following shouldn't be necessary if we clean up 
                  *     properly after seg faults, but we're not yet    GLA 
                  */     
                    ps->pid != 0) {
	        ++idle_thread_count;
	    }
	}
	if (any_dead_threads && free_length < idle_spawn_rate) {
        /* XXX any_dead_threads may not be needed any more GLA */
        if (any_dead_threads && free_length < idle_spawn_rate 
                && (!ps->pid               /* no process in the slot */
                    || ps->quiescing)) {   /* or at least one is going away */
	    free_slots[free_length] = i;
	    ++free_length;
	}
@@ -1083,6 +1101,8 @@ static void server_main_loop(int remaining_children_to_start)
                for (i = 0; i < ap_threads_per_child; i++)
                    ap_update_child_status(child_slot, i, SERVER_DEAD, (request_rec *) NULL);
                
                ap_scoreboard_image->parent[child_slot].pid = 0;
                ap_scoreboard_image->parent[child_slot].quiescing = 0;
		if (remaining_children_to_start
		    && child_slot < ap_daemons_limit) {
		    /* we're still doing a 1-for-1 replacement of dead