Blame modules/fcgid/fcgid_pm_main.c

Packit d68d13
/*
Packit d68d13
 * Licensed to the Apache Software Foundation (ASF) under one or more
Packit d68d13
 * contributor license agreements.  See the NOTICE file distributed with
Packit d68d13
 * this work for additional information regarding copyright ownership.
Packit d68d13
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit d68d13
 * (the "License"); you may not use this file except in compliance with
Packit d68d13
 * the License.  You may obtain a copy of the License at
Packit d68d13
 *
Packit d68d13
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit d68d13
 *
Packit d68d13
 * Unless required by applicable law or agreed to in writing, software
Packit d68d13
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit d68d13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit d68d13
 * See the License for the specific language governing permissions and
Packit d68d13
 * limitations under the License.
Packit d68d13
 */
Packit d68d13
Packit d68d13
/* For DEFAULT_PATH */
Packit d68d13
#define CORE_PRIVATE
Packit d68d13
#include "httpd.h"
Packit d68d13
#include "http_config.h"
Packit d68d13
#include "apr_strings.h"
Packit d68d13
Packit d68d13
#include "fcgid_pm.h"
Packit d68d13
#include "fcgid_pm_main.h"
Packit d68d13
#include "fcgid_conf.h"
Packit d68d13
#include "fcgid_proctbl.h"
Packit d68d13
#include "fcgid_proc.h"
Packit d68d13
#include "fcgid_spawn_ctl.h"
Packit d68d13
Packit d68d13
#define HAS_GRACEFUL_KILL "Gracefulkill"
Packit d68d13
Packit d68d13
static void
Packit d68d13
link_node_to_list(server_rec * main_server,
Packit d68d13
                  fcgid_procnode * header,
Packit d68d13
                  fcgid_procnode * node, fcgid_procnode * table_array)
Packit d68d13
{
Packit d68d13
    proctable_pm_lock(main_server);
Packit d68d13
    node->next_index = header->next_index;
Packit d68d13
    header->next_index = node - table_array;
Packit d68d13
    proctable_pm_unlock(main_server);
Packit d68d13
}
Packit d68d13
Packit d68d13
static apr_time_t lastidlescan = 0;
Packit d68d13
static void scan_idlelist(server_rec * main_server)
Packit d68d13
{
Packit d68d13
    /*
Packit d68d13
       Scan the idle list
Packit d68d13
       1. move all processes idle timeout to error list
Packit d68d13
       2. move all processes lifetime expired to error list
Packit d68d13
     */
Packit d68d13
    fcgid_procnode *previous_node, *current_node, *next_node;
Packit d68d13
    fcgid_procnode *error_list_header;
Packit d68d13
    fcgid_procnode *proc_table;
Packit d68d13
    apr_time_t last_active_time, start_time;
Packit d68d13
    apr_time_t now = apr_time_now();
Packit d68d13
    int idle_timeout, proc_lifetime;
Packit d68d13
    fcgid_server_conf *sconf =
Packit d68d13
        ap_get_module_config(main_server->module_config,
Packit d68d13
                             &fcgid_module);
Packit d68d13
Packit d68d13
    /* Should I check the idle list now? */
Packit d68d13
    if (procmgr_must_exit()
Packit d68d13
        || apr_time_sec(now) - apr_time_sec(lastidlescan) <=
Packit d68d13
        sconf->idle_scan_interval)
Packit d68d13
        return;
Packit d68d13
    lastidlescan = now;
Packit d68d13
Packit d68d13
    /* Check the list */
Packit d68d13
    proc_table = proctable_get_table_array();
Packit d68d13
    previous_node = proctable_get_idle_list();
Packit d68d13
    error_list_header = proctable_get_error_list();
Packit d68d13
Packit d68d13
    proctable_pm_lock(main_server);
Packit d68d13
    current_node = &proc_table[previous_node->next_index];
Packit d68d13
    while (current_node != proc_table) {
Packit d68d13
        next_node = &proc_table[current_node->next_index];
Packit d68d13
        last_active_time = current_node->last_active_time;
Packit d68d13
        start_time = current_node->start_time;
Packit d68d13
        idle_timeout = current_node->cmdopts.idle_timeout;
Packit d68d13
        proc_lifetime = current_node->cmdopts.proc_lifetime;
Packit d68d13
        if (((idle_timeout &&
Packit d68d13
              (apr_time_sec(now) - apr_time_sec(last_active_time) >
Packit d68d13
               idle_timeout))
Packit d68d13
             || (proc_lifetime
Packit d68d13
                 && (apr_time_sec(now) - apr_time_sec(start_time) >
Packit d68d13
                     proc_lifetime)))
Packit d68d13
            && is_kill_allowed(main_server, current_node)) {
Packit d68d13
            /* Set die reason for log */
Packit d68d13
            if (idle_timeout &&
Packit d68d13
                (apr_time_sec(now) - apr_time_sec(last_active_time) >
Packit d68d13
                 idle_timeout))
Packit d68d13
                current_node->diewhy = FCGID_DIE_IDLE_TIMEOUT;
Packit d68d13
            else if (proc_lifetime &&
Packit d68d13
                     (apr_time_sec(now) - apr_time_sec(start_time) >
Packit d68d13
                      proc_lifetime))
Packit d68d13
                current_node->diewhy = FCGID_DIE_LIFETIME_EXPIRED;
Packit d68d13
Packit d68d13
            /* Unlink from idle list */
Packit d68d13
            previous_node->next_index = current_node->next_index;
Packit d68d13
Packit d68d13
            /* Link to error list */
Packit d68d13
            current_node->next_index = error_list_header->next_index;
Packit d68d13
            error_list_header->next_index = current_node - proc_table;
Packit d68d13
        }
Packit d68d13
        else
Packit d68d13
            previous_node = current_node;
Packit d68d13
Packit d68d13
        current_node = next_node;
Packit d68d13
    }
Packit d68d13
    proctable_pm_unlock(main_server);
Packit d68d13
}
Packit d68d13
Packit d68d13
static apr_time_t lastbusyscan = 0;
Packit d68d13
static void scan_busylist(server_rec * main_server)
Packit d68d13
{
Packit d68d13
    fcgid_procnode *current_node;
Packit d68d13
    fcgid_procnode *proc_table;
Packit d68d13
    apr_time_t last_active_time;
Packit d68d13
    apr_time_t now = apr_time_now();
Packit d68d13
    fcgid_server_conf *sconf =
Packit d68d13
        ap_get_module_config(main_server->module_config,
Packit d68d13
                             &fcgid_module);
Packit d68d13
Packit d68d13
    /* Should I check the busy list? */
Packit d68d13
    if (procmgr_must_exit()
Packit d68d13
        || apr_time_sec(now) - apr_time_sec(lastbusyscan) <=
Packit d68d13
        sconf->busy_scan_interval)
Packit d68d13
        return;
Packit d68d13
    lastbusyscan = now;
Packit d68d13
Packit d68d13
    /* Check busy list */
Packit d68d13
    proc_table = proctable_get_table_array();
Packit d68d13
Packit d68d13
    proctable_pm_lock(main_server);
Packit d68d13
    current_node = &proc_table[proctable_get_busy_list()->next_index];
Packit d68d13
    while (current_node != proc_table) {
Packit d68d13
        last_active_time = current_node->last_active_time;
Packit d68d13
        if (apr_time_sec(now) - apr_time_sec(last_active_time) >
Packit d68d13
            (current_node->cmdopts.busy_timeout)) {
Packit d68d13
            /* Protocol:
Packit d68d13
               1. diewhy init with FCGID_DIE_KILLSELF
Packit d68d13
               2. Process manager set diewhy to FCGID_DIE_BUSY_TIMEOUT and gracefully kill process while busy timeout
Packit d68d13
               3. Process manager forced kill process while busy timeout and diewhy is FCGID_DIE_BUSY_TIMEOUT
Packit d68d13
             */
Packit d68d13
            if (current_node->diewhy == FCGID_DIE_BUSY_TIMEOUT)
Packit d68d13
                proc_kill_force(current_node, main_server);
Packit d68d13
            else {
Packit d68d13
                current_node->diewhy = FCGID_DIE_BUSY_TIMEOUT;
Packit d68d13
                proc_kill_gracefully(current_node, main_server);
Packit d68d13
            }
Packit d68d13
        }
Packit d68d13
        current_node = &proc_table[current_node->next_index];
Packit d68d13
    }
Packit d68d13
    proctable_pm_unlock(main_server);
Packit d68d13
}
Packit d68d13
Packit d68d13
static apr_time_t lastzombiescan = 0;
Packit d68d13
static void scan_idlelist_zombie(server_rec * main_server)
Packit d68d13
{
Packit d68d13
    /*
Packit d68d13
       Scan the idle list
Packit d68d13
       1. pick up the node for scan(now-last_activ>g_zombie_scan_interval)
Packit d68d13
       2. check if it's zombie process
Packit d68d13
       3. if it's zombie process, wait() and return to free list
Packit d68d13
       4. return to idle list if it's not zombie process
Packit d68d13
     */
Packit d68d13
    pid_t thepid;
Packit d68d13
    fcgid_procnode *previous_node, *current_node, *next_node;
Packit d68d13
    fcgid_procnode *check_list_header;
Packit d68d13
    fcgid_procnode *proc_table;
Packit d68d13
    apr_time_t last_active_time;
Packit d68d13
    apr_time_t now = apr_time_now();
Packit d68d13
    fcgid_procnode temp_header;
Packit d68d13
    fcgid_server_conf *sconf =
Packit d68d13
        ap_get_module_config(main_server->module_config,
Packit d68d13
                             &fcgid_module);
Packit d68d13
Packit d68d13
    memset(&temp_header, 0, sizeof(temp_header));
Packit d68d13
Packit d68d13
    /* Should I check zombie processes in idle list now? */
Packit d68d13
    if (procmgr_must_exit()
Packit d68d13
        || apr_time_sec(now) - apr_time_sec(lastzombiescan) <=
Packit d68d13
        sconf->zombie_scan_interval)
Packit d68d13
        return;
Packit d68d13
    lastzombiescan = now;
Packit d68d13
Packit d68d13
    /*
Packit d68d13
       Check the list
Packit d68d13
     */
Packit d68d13
    proc_table = proctable_get_table_array();
Packit d68d13
    previous_node = proctable_get_idle_list();
Packit d68d13
    check_list_header = &temp_header;
Packit d68d13
Packit d68d13
    proctable_pm_lock(main_server);
Packit d68d13
    current_node = &proc_table[previous_node->next_index];
Packit d68d13
    while (current_node != proc_table) {
Packit d68d13
        next_node = &proc_table[current_node->next_index];
Packit d68d13
Packit d68d13
        /* Is it time for zombie check? */
Packit d68d13
        last_active_time = current_node->last_active_time;
Packit d68d13
        if (apr_time_sec(now) - apr_time_sec(last_active_time) >
Packit d68d13
            sconf->zombie_scan_interval) {
Packit d68d13
            /* Unlink from idle list */
Packit d68d13
            previous_node->next_index = current_node->next_index;
Packit d68d13
Packit d68d13
            /* Link to check list */
Packit d68d13
            current_node->next_index = check_list_header->next_index;
Packit d68d13
            check_list_header->next_index = current_node - proc_table;
Packit d68d13
        }
Packit d68d13
        else
Packit d68d13
            previous_node = current_node;
Packit d68d13
Packit d68d13
        current_node = next_node;
Packit d68d13
    }
Packit d68d13
    proctable_pm_unlock(main_server);
Packit d68d13
Packit d68d13
    /*
Packit d68d13
       Now check every node in check list
Packit d68d13
       1) If it's zombie process, wait() and return to free list
Packit d68d13
       2) If it's not zombie process, link it to the tail of idle list
Packit d68d13
     */
Packit d68d13
    previous_node = check_list_header;
Packit d68d13
    current_node = &proc_table[previous_node->next_index];
Packit d68d13
    while (current_node != proc_table) {
Packit d68d13
        next_node = &proc_table[current_node->next_index];
Packit d68d13
Packit d68d13
        /* Is it zombie process? */
Packit d68d13
        thepid = current_node->proc_id.pid;
Packit d68d13
        if (proc_wait_process(main_server, current_node) == APR_CHILD_DONE) {
Packit d68d13
            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, main_server,
Packit d68d13
                         "mod_fcgid: cleanup zombie process %"
Packit d68d13
                         APR_PID_T_FMT, thepid);
Packit d68d13
Packit d68d13
            /* Unlink from check list */
Packit d68d13
            previous_node->next_index = current_node->next_index;
Packit d68d13
Packit d68d13
            /* Link to free list */
Packit d68d13
            link_node_to_list(main_server, proctable_get_free_list(),
Packit d68d13
                              current_node, proc_table);
Packit d68d13
        }
Packit d68d13
        else
Packit d68d13
            previous_node = current_node;
Packit d68d13
Packit d68d13
        current_node = next_node;
Packit d68d13
    }
Packit d68d13
Packit d68d13
    /*
Packit d68d13
       Now link the check list back to the tail of idle list
Packit d68d13
     */
Packit d68d13
    if (check_list_header->next_index) {
Packit d68d13
        proctable_pm_lock(main_server);
Packit d68d13
        previous_node = proctable_get_idle_list();
Packit d68d13
        current_node = &proc_table[previous_node->next_index];
Packit d68d13
Packit d68d13
        /* Find the tail of idle list */
Packit d68d13
        while (current_node != proc_table) {
Packit d68d13
            previous_node = current_node;
Packit d68d13
            current_node = &proc_table[current_node->next_index];
Packit d68d13
        }
Packit d68d13
Packit d68d13
        /* Link check list to the tail of idle list */
Packit d68d13
        previous_node->next_index = check_list_header->next_index;
Packit d68d13
        proctable_pm_unlock(main_server);
Packit d68d13
    }
Packit d68d13
}
Packit d68d13
Packit d68d13
static apr_time_t lasterrorscan = 0;
Packit d68d13
static void scan_errorlist(server_rec * main_server)
Packit d68d13
{
Packit d68d13
    /*
Packit d68d13
       kill() and wait() every node in error list
Packit d68d13
       put them back to free list after that
Packit d68d13
     */
Packit d68d13
    void *dummy;
Packit d68d13
    fcgid_procnode *previous_node, *current_node, *next_node;
Packit d68d13
    apr_time_t now = apr_time_now();
Packit d68d13
    fcgid_procnode *error_list_header = proctable_get_error_list();
Packit d68d13
    fcgid_procnode *free_list_header = proctable_get_free_list();
Packit d68d13
    fcgid_procnode *proc_table = proctable_get_table_array();
Packit d68d13
    fcgid_procnode temp_error_header;
Packit d68d13
    fcgid_server_conf *sconf =
Packit d68d13
        ap_get_module_config(main_server->module_config,
Packit d68d13
                             &fcgid_module);
Packit d68d13
    int graceful_terminations = 0;
Packit d68d13
Packit d68d13
    /* Should I check the busy list? */
Packit d68d13
    if (procmgr_must_exit()
Packit d68d13
        || apr_time_sec(now) - apr_time_sec(lasterrorscan) <=
Packit d68d13
        sconf->error_scan_interval)
Packit d68d13
        return;
Packit d68d13
    lasterrorscan = now;
Packit d68d13
Packit d68d13
    /* Try wait dead processes, restore to free list */
Packit d68d13
    /* Note: I can't keep the lock during the scan */
Packit d68d13
    proctable_pm_lock(main_server);
Packit d68d13
    temp_error_header.next_index = error_list_header->next_index;
Packit d68d13
    error_list_header->next_index = 0;
Packit d68d13
    proctable_pm_unlock(main_server);
Packit d68d13
Packit d68d13
    previous_node = &temp_error_header;
Packit d68d13
    current_node = &proc_table[previous_node->next_index];
Packit d68d13
    while (current_node != proc_table) {
Packit d68d13
        next_node = &proc_table[current_node->next_index];
Packit d68d13
Packit d68d13
        if (proc_wait_process(main_server, current_node) != APR_CHILD_NOTDONE) {
Packit d68d13
            /* Unlink from error list */
Packit d68d13
            previous_node->next_index = current_node->next_index;
Packit d68d13
Packit d68d13
            /* Link to free list */
Packit d68d13
            current_node->next_index = free_list_header->next_index;
Packit d68d13
            free_list_header->next_index = current_node - proc_table;
Packit d68d13
        }
Packit d68d13
        else
Packit d68d13
            previous_node = current_node;
Packit d68d13
Packit d68d13
        current_node = next_node;
Packit d68d13
    }
Packit d68d13
Packit d68d13
    /* Kill the left processes, wait() them in the next round */
Packit d68d13
    for (current_node = &proc_table[temp_error_header.next_index];
Packit d68d13
         current_node != proc_table;
Packit d68d13
         current_node = &proc_table[current_node->next_index]) {
Packit d68d13
        /* Try gracefully first */
Packit d68d13
        dummy = NULL;
Packit d68d13
        apr_pool_userdata_get(&dummy, HAS_GRACEFUL_KILL,
Packit d68d13
                              current_node->proc_pool);
Packit d68d13
        if (!dummy) {
Packit d68d13
            proc_kill_gracefully(current_node, main_server);
Packit d68d13
            ++graceful_terminations;
Packit d68d13
            apr_pool_userdata_set("set", HAS_GRACEFUL_KILL,
Packit d68d13
                                  apr_pool_cleanup_null,
Packit d68d13
                                  current_node->proc_pool);
Packit d68d13
        }
Packit d68d13
        else {
Packit d68d13
            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, main_server,
Packit d68d13
                         "mod_fcgid: process %" APR_PID_T_FMT
Packit d68d13
                         " graceful kill fail, sending SIGKILL",
Packit d68d13
                         current_node->proc_id.pid);
Packit d68d13
            proc_kill_force(current_node, main_server);
Packit d68d13
        }
Packit d68d13
    }
Packit d68d13
Packit d68d13
    /* Link the temp error list back */
Packit d68d13
    proctable_pm_lock(main_server);
Packit d68d13
    /* Find the tail of error list */
Packit d68d13
    previous_node = error_list_header;
Packit d68d13
    current_node = &proc_table[previous_node->next_index];
Packit d68d13
    while (current_node != proc_table) {
Packit d68d13
        previous_node = current_node;
Packit d68d13
        current_node = &proc_table[current_node->next_index];
Packit d68d13
    }
Packit d68d13
    previous_node->next_index = temp_error_header.next_index;
Packit d68d13
    proctable_pm_unlock(main_server);
Packit d68d13
Packit d68d13
    if (graceful_terminations) {
Packit d68d13
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server,
Packit d68d13
                     "mod_fcgid: gracefully terminated %d processes",
Packit d68d13
                     graceful_terminations);
Packit d68d13
    }
Packit d68d13
}
Packit d68d13
Packit d68d13
typedef enum action_t {DO_NOTHING, KILL_GRACEFULLY, KILL_FORCEFULLY,
Packit d68d13
                       HARD_WAIT} action_t;
Packit d68d13
Packit d68d13
static int reclaim_one_pid(server_rec *main_server, fcgid_procnode *proc,
Packit d68d13
                           action_t action)
Packit d68d13
{
Packit d68d13
    int exitcode;
Packit d68d13
    apr_exit_why_e exitwhy;
Packit d68d13
    apr_wait_how_e wait_how = action == HARD_WAIT ? APR_WAIT : APR_NOWAIT;
Packit d68d13
Packit d68d13
    if (apr_proc_wait(&proc->proc_id, &exitcode, &exitwhy,
Packit d68d13
                      wait_how) != APR_CHILD_NOTDONE) {
Packit d68d13
        proc->diewhy = FCGID_DIE_SHUTDOWN;
Packit d68d13
        proc_print_exit_info(proc, exitcode, exitwhy,
Packit d68d13
                             main_server);
Packit d68d13
        proc->proc_pool = NULL;
Packit d68d13
        return 1;
Packit d68d13
    }
Packit d68d13
Packit d68d13
    switch(action) {
Packit d68d13
    case DO_NOTHING:
Packit d68d13
    case HARD_WAIT:
Packit d68d13
        break;
Packit d68d13
Packit d68d13
    case KILL_GRACEFULLY:
Packit d68d13
        proc_kill_gracefully(proc, main_server);
Packit d68d13
        break;
Packit d68d13
Packit d68d13
    case KILL_FORCEFULLY:
Packit d68d13
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server,
Packit d68d13
                     "FastCGI process %" APR_PID_T_FMT
Packit d68d13
                     " still did not exit, "
Packit d68d13
                     "terminating forcefully",
Packit d68d13
                     proc->proc_id.pid);
Packit d68d13
        proc_kill_force(proc, main_server);
Packit d68d13
        break;
Packit d68d13
    }
Packit d68d13
Packit d68d13
    return 0;
Packit d68d13
}
Packit d68d13
Packit d68d13
static void kill_all_subprocess(server_rec *main_server)
Packit d68d13
{
Packit d68d13
    apr_time_t waittime = 1024 * 16;
Packit d68d13
    size_t i, table_size = proctable_get_table_size();
Packit d68d13
    int not_dead_yet;
Packit d68d13
    int cur_action, next_action;
Packit d68d13
    apr_time_t starttime = apr_time_now();
Packit d68d13
    struct {
Packit d68d13
        action_t action;
Packit d68d13
        apr_time_t action_time;
Packit d68d13
    } action_table[] = {
Packit d68d13
        {DO_NOTHING,      0}, /* dummy entry for iterations where
Packit d68d13
                              * we reap children but take no action
Packit d68d13
                              * against stragglers
Packit d68d13
                              */
Packit d68d13
        {KILL_GRACEFULLY, apr_time_from_sec(0)},
Packit d68d13
        {KILL_GRACEFULLY, apr_time_from_sec(1)},
Packit d68d13
        {KILL_FORCEFULLY, apr_time_from_sec(8)},
Packit d68d13
        {HARD_WAIT,       apr_time_from_sec(8)}
Packit d68d13
    };
Packit d68d13
    fcgid_procnode *proc_table = proctable_get_table_array();
Packit d68d13
Packit d68d13
    next_action = 1;
Packit d68d13
    do {
Packit d68d13
        apr_sleep(waittime);
Packit d68d13
        /* don't let waittime get longer than 1 second; otherwise, we don't
Packit d68d13
         * react quickly to the last child exiting, and taking action can
Packit d68d13
         * be delayed
Packit d68d13
         */
Packit d68d13
        waittime = waittime * 4;
Packit d68d13
        if (waittime > apr_time_from_sec(1)) {
Packit d68d13
            waittime = apr_time_from_sec(1);
Packit d68d13
        }
Packit d68d13
Packit d68d13
        /* see what action to take, if any */
Packit d68d13
        if (action_table[next_action].action_time <= apr_time_now() - starttime) {
Packit d68d13
            cur_action = next_action;
Packit d68d13
            ++next_action;
Packit d68d13
        }
Packit d68d13
        else {
Packit d68d13
            cur_action = 0; /* index of DO_NOTHING entry */
Packit d68d13
        }
Packit d68d13
Packit d68d13
        /* now see who is done */
Packit d68d13
        not_dead_yet = 0;
Packit d68d13
        for (i = 0; i < table_size; i++) {
Packit d68d13
            if (!proc_table[i].proc_pool) {
Packit d68d13
                continue; /* unused */
Packit d68d13
            }
Packit d68d13
Packit d68d13
            if (!reclaim_one_pid(main_server, &proc_table[i],
Packit d68d13
                                 action_table[cur_action].action)) {
Packit d68d13
                ++not_dead_yet;
Packit d68d13
            }
Packit d68d13
        }
Packit d68d13
Packit d68d13
    } while (not_dead_yet &&
Packit d68d13
             action_table[cur_action].action != HARD_WAIT);
Packit d68d13
}
Packit d68d13
Packit d68d13
/* This should be proposed as a stand-alone improvement to the httpd module,
Packit d68d13
 * either in the arch/ platform-specific modules or util_script.c from whence
Packit d68d13
 * it came.
Packit d68d13
 */
Packit d68d13
static void default_proc_env(apr_table_t * e)
Packit d68d13
{
Packit d68d13
    const char *env_temp;
Packit d68d13
Packit d68d13
    if (!(env_temp = getenv("PATH"))) {
Packit d68d13
        env_temp = DEFAULT_PATH;
Packit d68d13
    }
Packit d68d13
    apr_table_addn(e, "PATH", env_temp);
Packit d68d13
Packit d68d13
#ifdef WIN32
Packit d68d13
    if ((env_temp = getenv("SYSTEMROOT"))) {
Packit d68d13
        apr_table_addn(e, "SYSTEMROOT", env_temp);
Packit d68d13
    }
Packit d68d13
    if ((env_temp = getenv("COMSPEC"))) {
Packit d68d13
        apr_table_addn(e, "COMSPEC", env_temp);
Packit d68d13
    }
Packit d68d13
    if ((env_temp = getenv("PATHEXT"))) {
Packit d68d13
        apr_table_addn(e, "PATHEXT", env_temp);
Packit d68d13
    }
Packit d68d13
    if ((env_temp = getenv("WINDIR"))) {
Packit d68d13
        apr_table_addn(e, "WINDIR", env_temp);
Packit d68d13
    }
Packit d68d13
#elif defined(OS2)
Packit d68d13
    if ((env_temp = getenv("COMSPEC")) != NULL) {
Packit d68d13
        apr_table_addn(e, "COMSPEC", env_temp);
Packit d68d13
    }
Packit d68d13
    if ((env_temp = getenv("ETC")) != NULL) {
Packit d68d13
        apr_table_addn(e, "ETC", env_temp);
Packit d68d13
    }
Packit d68d13
    if ((env_temp = getenv("DPATH")) != NULL) {
Packit d68d13
        apr_table_addn(e, "DPATH", env_temp);
Packit d68d13
    }
Packit d68d13
    if ((env_temp = getenv("PERLLIB_PREFIX")) != NULL) {
Packit d68d13
        apr_table_addn(e, "PERLLIB_PREFIX", env_temp);
Packit d68d13
    }
Packit d68d13
#elif defined(BEOS)
Packit d68d13
    if ((env_temp = getenv("LIBRARY_PATH")) != NULL) {
Packit d68d13
        apr_table_addn(e, "LIBRARY_PATH", env_temp);
Packit d68d13
    }
Packit d68d13
#elif defined (AIX)
Packit d68d13
    if ((env_temp = getenv("LIBPATH"))) {
Packit d68d13
        apr_table_addn(e, "LIBPATH", env_temp);
Packit d68d13
    }
Packit d68d13
#else
Packit d68d13
/* DARWIN, HPUX vary depending on circumstance */
Packit d68d13
#if defined (DARWIN)
Packit d68d13
    if ((env_temp = getenv("DYLD_LIBRARY_PATH"))) {
Packit d68d13
        apr_table_addn(e, "DYLD_LIBRARY_PATH", env_temp);
Packit d68d13
    }
Packit d68d13
#elif defined (HPUX11) || defined (HPUX10) || defined (HPUX)
Packit d68d13
    if ((env_temp = getenv("SHLIB_PATH"))) {
Packit d68d13
        apr_table_addn(e, "SHLIB_PATH", env_temp);
Packit d68d13
    }
Packit d68d13
#endif
Packit d68d13
    if ((env_temp = getenv("LD_LIBRARY_PATH"))) {
Packit d68d13
        apr_table_addn(e, "LD_LIBRARY_PATH", env_temp);
Packit d68d13
    }
Packit d68d13
#endif
Packit d68d13
}
Packit d68d13
Packit d68d13
/* End of common to util_script.c */
Packit d68d13
Packit d68d13
static void
Packit d68d13
fastcgi_spawn(fcgid_command * command, server_rec * main_server,
Packit d68d13
              apr_pool_t * configpool)
Packit d68d13
{
Packit d68d13
    fcgid_procnode *free_list_header, *proctable_array,
Packit d68d13
        *procnode, *idle_list_header;
Packit d68d13
    fcgid_proc_info procinfo;
Packit d68d13
    apr_status_t rv;
Packit d68d13
    int i;
Packit d68d13
Packit d68d13
    free_list_header = proctable_get_free_list();
Packit d68d13
    idle_list_header = proctable_get_idle_list();
Packit d68d13
    proctable_array = proctable_get_table_array();
Packit d68d13
Packit d68d13
    /* Apply a slot from free list */
Packit d68d13
    proctable_pm_lock(main_server);
Packit d68d13
    if (free_list_header->next_index == 0) {
Packit d68d13
        proctable_pm_unlock(main_server);
Packit d68d13
        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, main_server,
Packit d68d13
                     "mod_fcgid: too much processes, please increase FCGID_MAX_APPLICATION");
Packit d68d13
        return;
Packit d68d13
    }
Packit d68d13
    procnode = &proctable_array[free_list_header->next_index];
Packit d68d13
    free_list_header->next_index = procnode->next_index;
Packit d68d13
    procnode->next_index = 0;
Packit d68d13
    proctable_pm_unlock(main_server);
Packit d68d13
Packit d68d13
    /* Prepare to spawn */
Packit d68d13
    procnode->deviceid = command->deviceid;
Packit d68d13
    procnode->inode = command->inode;
Packit d68d13
Packit d68d13
    /* no truncation should ever occur */
Packit d68d13
    AP_DEBUG_ASSERT(sizeof procnode->cmdline > strlen(command->cmdline));
Packit d68d13
    apr_cpystrn(procnode->cmdline, command->cmdline, sizeof procnode->cmdline);
Packit d68d13
Packit d68d13
    procnode->vhost_id = command->vhost_id;
Packit d68d13
    procnode->uid = command->uid;
Packit d68d13
    procnode->gid = command->gid;
Packit d68d13
    procnode->start_time = procnode->last_active_time = apr_time_now();
Packit d68d13
    procnode->requests_handled = 0;
Packit d68d13
    procnode->diewhy = FCGID_DIE_KILLSELF;
Packit d68d13
    procnode->proc_pool = NULL;
Packit d68d13
    procnode->cmdopts = command->cmdopts;
Packit d68d13
Packit d68d13
    procinfo.cgipath = command->cgipath;
Packit d68d13
    procinfo.configpool = configpool;
Packit d68d13
    procinfo.main_server = main_server;
Packit d68d13
    procinfo.uid = command->uid;
Packit d68d13
    procinfo.gid = command->gid;
Packit d68d13
    procinfo.userdir = command->userdir;
Packit d68d13
    if ((rv =
Packit d68d13
         apr_pool_create(&procnode->proc_pool, configpool)) != APR_SUCCESS
Packit d68d13
        || (procinfo.proc_environ =
Packit d68d13
            apr_table_make(procnode->proc_pool, INITENV_CNT)) == NULL) {
Packit d68d13
        /* Link the node back to free list in this case */
Packit d68d13
        if (procnode->proc_pool)
Packit d68d13
            apr_pool_destroy(procnode->proc_pool);
Packit d68d13
        link_node_to_list(main_server, free_list_header, procnode,
Packit d68d13
                          proctable_array);
Packit d68d13
Packit d68d13
        ap_log_error(APLOG_MARK, APLOG_WARNING, rv, main_server,
Packit d68d13
                     "mod_fcgid: can't create pool for process");
Packit d68d13
        return;
Packit d68d13
    }
Packit d68d13
    /* Set up longer, system defaults before falling into parsing fixed-limit
Packit d68d13
     * request-by-request variables, so if any are overriden, they preempt
Packit d68d13
     * any system default assumptions
Packit d68d13
     */
Packit d68d13
    default_proc_env(procinfo.proc_environ);
Packit d68d13
    for (i = 0; i < INITENV_CNT; i++) {
Packit d68d13
        if (command->cmdenv.initenv_key[i][0] == '\0')
Packit d68d13
            break;
Packit d68d13
        apr_table_set(procinfo.proc_environ, command->cmdenv.initenv_key[i],
Packit d68d13
                      command->cmdenv.initenv_val[i]);
Packit d68d13
    }
Packit d68d13
Packit d68d13
    /* Spawn the process now */
Packit d68d13
    /* XXX Spawn uses wrapper_cmdline, but log uses cgipath ? */
Packit d68d13
    if ((rv =
Packit d68d13
         proc_spawn_process(command->cmdline, &procinfo,
Packit d68d13
                            procnode)) != APR_SUCCESS) {
Packit d68d13
        ap_log_error(APLOG_MARK, APLOG_WARNING, rv, main_server,
Packit d68d13
                     "mod_fcgid: spawn process %s error", command->cgipath);
Packit d68d13
Packit d68d13
        apr_pool_destroy(procnode->proc_pool);
Packit d68d13
        link_node_to_list(main_server, free_list_header,
Packit d68d13
                          procnode, proctable_array);
Packit d68d13
        return;
Packit d68d13
    }
Packit d68d13
    else {
Packit d68d13
        /* The job done */
Packit d68d13
        link_node_to_list(main_server, idle_list_header,
Packit d68d13
                          procnode, proctable_array);
Packit d68d13
        ap_log_error(APLOG_MARK, APLOG_INFO, 0, main_server,
Packit d68d13
                     "mod_fcgid: server %s:%s(%" APR_PID_T_FMT ") started",
Packit d68d13
                     command->server_hostname[0] ?
Packit d68d13
                         command->server_hostname : "(unknown)",
Packit d68d13
                     command->cgipath,
Packit d68d13
                     procnode->proc_id.pid);
Packit d68d13
        register_spawn(main_server, procnode);
Packit d68d13
    }
Packit d68d13
}
Packit d68d13
Packit d68d13
apr_status_t pm_main(server_rec * main_server, apr_pool_t * configpool)
Packit d68d13
{
Packit d68d13
    fcgid_command command;
Packit d68d13
Packit d68d13
    while (1) {
Packit d68d13
        if (procmgr_must_exit())
Packit d68d13
            break;
Packit d68d13
Packit d68d13
        /* Wait for command */
Packit d68d13
        if (procmgr_fetch_cmd(&command, main_server) == APR_SUCCESS) {
Packit d68d13
            if (is_spawn_allowed(main_server, &command))
Packit d68d13
                fastcgi_spawn(&command, main_server, configpool);
Packit d68d13
Packit d68d13
            procmgr_finish_notify(main_server);
Packit d68d13
        }
Packit d68d13
Packit d68d13
        /* Move matched node to error list */
Packit d68d13
        scan_idlelist_zombie(main_server);
Packit d68d13
        scan_idlelist(main_server);
Packit d68d13
        scan_busylist(main_server);
Packit d68d13
Packit d68d13
        /* Kill() and wait() nodes in error list */
Packit d68d13
        scan_errorlist(main_server);
Packit d68d13
    }
Packit d68d13
Packit d68d13
    /* Stop all processes */
Packit d68d13
    kill_all_subprocess(main_server);
Packit d68d13
Packit d68d13
    return APR_SUCCESS;
Packit d68d13
}