⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 perchild.c

📁 Apache 2.0.63 is the current stable version of the 2.0 series, and is recommended over any previous
💻 C
📖 第 1 页 / 共 5 页
字号:
            else {
                thread_socket_table[thread_num] = AP_PERCHILD_THISCHILD;
            }  
            requests_this_child--;
        }
        else {
            if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(process_accept_mutex)))
                != APR_SUCCESS) {
                ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
                             "apr_proc_mutex_unlock failed. Attempting to shutdown "
                             "process gracefully.");
                workers_may_exit = 1;
            }
            apr_thread_mutex_unlock(thread_accept_mutex);
            apr_thread_mutex_lock(idle_thread_count_mutex);
            idle_thread_count--;
            apr_thread_mutex_unlock(idle_thread_count_mutex);
        break;
        }
        apr_pool_clear(ptrans);
    }

    apr_thread_mutex_lock(thread_pool_parent_mutex);
    ap_update_child_status_from_indexes(child_num, thread_num, SERVER_DEAD,
                                        (request_rec *) NULL);
    apr_pool_destroy(tpool);
    apr_thread_mutex_unlock(thread_pool_parent_mutex);
    apr_thread_mutex_lock(worker_thread_count_mutex);
    worker_thread_count--;
    worker_thread_free_ids[worker_thread_count] = thread_num;
    if (worker_thread_count == 0) {
        /* All the threads have exited, now finish the shutdown process
         * by signalling the sigwait thread */
        kill(my_pid, SIGTERM);
    }
    apr_thread_mutex_unlock(worker_thread_count_mutex);

    apr_bucket_alloc_destroy(bucket_alloc);

    return NULL;
}



/* Set group privileges.
 *
 * Note that we use the username as set in the config files, rather than
 * the lookup of to uid --- the same uid may have multiple passwd entries,
 * with different sets of groups for each.
 */

static int set_group_privs(uid_t uid, gid_t gid)
{
    if (!geteuid()) {
        const char *name;

        /* Get username if passed as a uid */

        struct passwd *ent;

        if ((ent = getpwuid(uid)) == NULL) {
            ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
                         "getpwuid: couldn't determine user name from uid %u, "
                         "you probably need to modify the User directive",
                         (unsigned)uid);
            return -1;
        }

        name = ent->pw_name;

        /*
         * Set the GID before initgroups(), since on some platforms
         * setgid() is known to zap the group list.
         */
        if (setgid(gid) == -1) {
            ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
                         "setgid: unable to set group id to Group %u",
                         (unsigned)gid);
            return -1;
        }

        /* Reset `groups' attributes. */

        if (initgroups(name, gid) == -1) {
            ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
                         "initgroups: unable to set groups for User %s "
                         "and Group %u", name, (unsigned)gid);
            return -1;
        }
    }
    return 0;
}


static int perchild_setup_child(int childnum)
{
    child_info_t *ug = &child_info_table[childnum];

    if (ug->uid == -1 && ug->gid == -1) {
        return unixd_setup_child();
    }
    if (set_group_privs(ug->uid, ug->gid)) {
        return -1;
    }
    /* Only try to switch if we're running as root */
    if (!geteuid()
        && (
#ifdef _OSD_POSIX
            os_init_job_environment(server_conf, unixd_config.user_name,
                                    one_process) != 0 ||
#endif
            setuid(ug->uid) == -1)) {
        ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
                     "setuid: unable to change to uid: %ld",
                     (long) ug->uid);
        return -1;
    }
    return 0;
}

static int check_signal(int signum)
{
    switch (signum) {
    case SIGTERM:
    case SIGINT:
        just_die(signum);
        return 1;
    }
    return 0;
}                                                                               

typedef struct perchild_header {
    char *headers;
    apr_pool_t *p;
} perchild_header;

/* Send a single HTTP header field to the client.  Note that this function
 * is used in calls to table_do(), so their interfaces are co-dependent.
 * In other words, don't change this one without checking table_do in alloc.c.
 * It returns true unless there was a write error of some kind.
 */
static int perchild_header_field(perchild_header *h,
                             const char *fieldname, const char *fieldval)
{
    apr_pstrcat(h->p, h->headers, fieldname, ": ", fieldval, CRLF, NULL); 
    return 1;
}


static void child_main(int child_num_arg)
{
    int i;
    apr_status_t rv;
    apr_socket_t *sock = NULL;
    ap_listen_rec *lr;
    
    my_pid = getpid();
    ap_fatal_signal_child_setup(ap_server_conf);
    child_num = child_num_arg;
    apr_pool_create(&pchild, pconf);

    for (lr = ap_listeners ; lr->next != NULL; lr = lr->next) {
        continue;
    }

    apr_os_sock_put(&sock, &child_info_table[child_num].input, pconf);
    lr->next = apr_palloc(pconf, sizeof(*lr));
    lr->next->sd = sock;
    lr->next->active = 1;
    lr->next->accept_func = receive_from_other_child;
    lr->next->next = NULL;
    lr = lr->next;
    num_listensocks++;

    /*stuff to do before we switch id's, so we have permissions.*/

    rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&process_accept_mutex, 
                                               ap_lock_fname, pchild));
    if (rv != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
                     "Couldn't initialize cross-process lock in child");
        clean_child_exit(APEXIT_CHILDFATAL);
    }

    if (perchild_setup_child(child_num)) {
        clean_child_exit(APEXIT_CHILDFATAL);
    }

    ap_run_child_init(pchild, ap_server_conf);

    /*done with init critical section */

    apr_setup_signal_thread();

    requests_this_child = ap_max_requests_per_child;
    

    /* Setup worker threads */

    if (threads_to_start > max_threads) {
        threads_to_start = max_threads;
    }
    idle_thread_count = threads_to_start;
    worker_thread_count = 0;
    worker_thread_free_ids = (int *)apr_pcalloc(pchild, thread_limit * sizeof(int));
    for (i = 0; i < max_threads; i++) {
        worker_thread_free_ids[i] = i;
    }
    apr_pool_create(&thread_pool_parent, pchild);
    apr_thread_mutex_create(&thread_pool_parent_mutex, 
                    APR_THREAD_MUTEX_DEFAULT, pchild);
    apr_thread_mutex_create(&idle_thread_count_mutex, 
                    APR_THREAD_MUTEX_DEFAULT, pchild);
    apr_thread_mutex_create(&worker_thread_count_mutex,
                    APR_THREAD_MUTEX_DEFAULT, pchild);
    apr_thread_mutex_create(&pipe_of_death_mutex,
                    APR_THREAD_MUTEX_DEFAULT, pchild);
    apr_thread_mutex_create(&thread_accept_mutex,
                    APR_THREAD_MUTEX_DEFAULT, pchild);

    apr_threadattr_create(&worker_thread_attr, pchild);
    apr_threadattr_detach_set(worker_thread_attr, 1);                                     

    /* We are creating worker threads right now */
    for (i=0; i < threads_to_start; i++) {
        /* start_thread shouldn't fail here */
        if (!start_thread()) {
            break;
        }
    }

    apr_signal_thread(check_signal);
}

static int make_child(server_rec *s, int slot)
{
    int pid;

    if (slot + 1 > ap_max_daemons_limit) {
        ap_max_daemons_limit = slot + 1;
    }

    if (one_process) {
        set_signals();
        ap_child_table[slot].pid = getpid();
        ap_child_table[slot].status = SERVER_ALIVE;
        child_main(slot);
    }
    (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
                                               (request_rec *) NULL);

    if ((pid = fork()) == -1) {
        ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,
                     "fork: Unable to fork new process");
        /* In case system resources are maxxed out, we don't want
         * Apache running away with the CPU trying to fork over and
         * over and over again. */
        sleep(10);

        return -1;
    }

    if (!pid) {
#ifdef HAVE_BINDPROCESSOR
        /* By default, AIX binds to a single processor.  This bit unbinds
         * children which will then bind to another CPU.
         */
        int status = bindprocessor(BINDPROCESS, (int)getpid(),
                                   PROCESSOR_CLASS_ANY);
        if (status != OK) {
            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, 
                         ap_server_conf, "processor unbind failed %d", status);
        }
#endif

        RAISE_SIGSTOP(MAKE_CHILD);

        /* XXX - For an unthreaded server, a signal handler will be necessary
         * apr_signal(SIGTERM, just_die);
         */
        child_main(slot);
        clean_child_exit(0);
    }
    /* else */
    ap_child_table[slot].pid = pid;
    ap_child_table[slot].status = SERVER_ALIVE;

    return 0;
}

/* start up a bunch of children */
static int startup_children(int number_to_start)
{
    int i;

    for (i = 0; number_to_start && i < num_daemons; ++i) {
        if (ap_child_table[i].pid) {
            continue;
        }
        if (make_child(ap_server_conf, i) < 0) {
            break;
        }
        --number_to_start;
    }
    return number_to_start;
}


/*
 * spawn_rate is the number of children that will be spawned on the
 * next maintenance cycle if there aren't enough servers.  It is
 * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
 * without the need to spawn.
 */
static int spawn_rate = 1;
#ifndef MAX_SPAWN_RATE
#define MAX_SPAWN_RATE  (32)
#endif
static int hold_off_on_exponential_spawning;

static void perform_child_maintenance(void)
{
    int i;
    int free_length;
    int free_slots[MAX_SPAWN_RATE];
    int last_non_dead = -1;

    /* initialize the free_list */
    free_length = 0;
    
    for (i = 0; i < num_daemons; ++i) {
        if (ap_child_table[i].pid == 0) {
            if (free_length < spawn_rate) {
                free_slots[free_length] = i;
                ++free_length;
            }
        }
        else {
            last_non_dead = i;
        }

        if (i >= ap_max_daemons_limit && free_length >= spawn_rate) {
            break;
        }
    }
    ap_max_daemons_limit = last_non_dead + 1;

    if (free_length > 0) {
        for (i = 0; i < free_length; ++i) {
            make_child(ap_server_conf, free_slots[i]);
        }
        /* the next time around we want to spawn twice as many if this
         * wasn't good enough, but not if we've just done a graceful
         */
        if (hold_off_on_exponential_spawning) {
            --hold_off_on_exponential_spawning;
        }
        else if (spawn_rate < MAX_SPAWN_RATE) {
            spawn_rate *= 2;
        }
    }
    else {
        spawn_rate = 1;
    }
}

static void server_main_loop(int remaining_children_to_start)
{
    int child_slot;
    apr_exit_why_e exitwhy;
    int status;
    apr_proc_t pid;
    int i;

    while (!restart_pending && !shutdown_pending) {
        ap_wait_or_timeout(&exitwhy, &status, &pid, pconf);
        
        if (pid.pid != -1) {
            if (ap_process_child_status(&pid, exitwhy, status)
                == APEXIT_CHILDFATAL) {
                shutdown_pending = 1;
                child_fatal = 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -