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

📄 worker.c

📁 apache的软件linux版本
💻 C
📖 第 1 页 / 共 5 页
字号:
        }        else {            if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex)))                != APR_SUCCESS) {                int level = APLOG_EMERG;                if (ap_scoreboard_image->parent[process_slot].generation !=                     ap_scoreboard_image->global->running_generation) {                    level = APLOG_DEBUG; /* common to get these at restart time */                }                ap_log_error(APLOG_MARK, level, rv, ap_server_conf,                             "apr_proc_mutex_unlock failed. Attempting to "                             "shutdown process gracefully.");                signal_threads(ST_GRACEFUL);            }            break;        }    }    ap_queue_term(worker_queue);    dying = 1;    ap_scoreboard_image->parent[process_slot].quiescing = 1;    /* wake up the main thread */    kill(ap_my_pid, SIGTERM);    apr_thread_exit(thd, APR_SUCCESS);    return NULL;}/* XXX For ungraceful termination/restart, we definitely don't want to *     wait for active connections to finish but we may want to wait *     for idle workers to get out of the queue code and release mutexes, *     since those mutexes are cleaned up pretty soon and some systems *     may not react favorably (i.e., segfault) if operations are attempted *     on cleaned-up mutexes. */static void * APR_THREAD_FUNC worker_thread(apr_thread_t *thd, void * dummy){    proc_info * ti = dummy;    int process_slot = ti->pid;    int thread_slot = ti->tid;    apr_socket_t *csd = NULL;    apr_bucket_alloc_t *bucket_alloc;    apr_pool_t *last_ptrans = NULL;    apr_pool_t *ptrans;                /* Pool for per-transaction stuff */    apr_status_t rv;    int is_idle = 0;    free(ti);    ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_STARTING, NULL);    while (!workers_may_exit) {        if (!is_idle) {            rv = ap_queue_info_set_idle(worker_queue_info, last_ptrans);            last_ptrans = NULL;            if (rv != APR_SUCCESS) {                ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,                             "ap_queue_info_set_idle failed. Attempting to "                             "shutdown process gracefully.");                signal_threads(ST_GRACEFUL);                break;            }            is_idle = 1;        }        ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_READY, NULL);worker_pop:        if (workers_may_exit) {            break;        }        rv = ap_queue_pop(worker_queue, &csd, &ptrans);        if (rv != APR_SUCCESS) {            /* We get APR_EOF during a graceful shutdown once all the connections             * accepted by this server process have been handled.             */            if (APR_STATUS_IS_EOF(rv)) {                break;            }            /* We get APR_EINTR whenever ap_queue_pop() has been interrupted             * from an explicit call to ap_queue_interrupt_all(). This allows             * us to unblock threads stuck in ap_queue_pop() when a shutdown             * is pending.             *             * If workers_may_exit is set and this is ungraceful termination/             * restart, we are bound to get an error on some systems (e.g.,             * AIX, which sanity-checks mutex operations) since the queue             * may have already been cleaned up.  Don't log the "error" if             * workers_may_exit is set.             */            else if (APR_STATUS_IS_EINTR(rv)) {                goto worker_pop;            }            /* We got some other error. */            else if (!workers_may_exit) {                ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,                             "ap_queue_pop failed");            }            continue;        }        is_idle = 0;        worker_sockets[thread_slot] = csd;        bucket_alloc = apr_bucket_alloc_create(ptrans);        process_socket(ptrans, csd, process_slot, thread_slot, bucket_alloc);        worker_sockets[thread_slot] = NULL;        requests_this_child--; /* FIXME: should be synchronized - aaron */        apr_pool_clear(ptrans);        last_ptrans = ptrans;    }    ap_update_child_status_from_indexes(process_slot, thread_slot,        (dying) ? SERVER_DEAD : SERVER_GRACEFUL, (request_rec *) NULL);    apr_thread_exit(thd, APR_SUCCESS);    return NULL;}static int check_signal(int signum){    switch (signum) {    case SIGTERM:    case SIGINT:        return 1;    }    return 0;}static void create_listener_thread(thread_starter *ts){    int my_child_num = ts->child_num_arg;    apr_threadattr_t *thread_attr = ts->threadattr;    proc_info *my_info;    apr_status_t rv;    my_info = (proc_info *)malloc(sizeof(proc_info));    my_info->pid = my_child_num;    my_info->tid = -1; /* listener thread doesn't have a thread slot */    my_info->sd = 0;    rv = apr_thread_create(&ts->listener, thread_attr, listener_thread,                           my_info, pchild);    if (rv != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,                     "apr_thread_create: unable to create listener thread");        /* let the parent decide how bad this really is */        clean_child_exit(APEXIT_CHILDSICK);    }    apr_os_thread_get(&listener_os_thread, ts->listener);}/* XXX under some circumstances not understood, children can get stuck *     in start_threads forever trying to take over slots which will *     never be cleaned up; for now there is an APLOG_DEBUG message issued *     every so often when this condition occurs */static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy){    thread_starter *ts = dummy;    apr_thread_t **threads = ts->threads;    apr_threadattr_t *thread_attr = ts->threadattr;    int child_num_arg = ts->child_num_arg;    int my_child_num = child_num_arg;    proc_info *my_info;    apr_status_t rv;    int i;    int threads_created = 0;    int listener_started = 0;    int loops;    int prev_threads_created;    /* We must create the fd queues before we start up the listener     * and worker threads. */    worker_queue = apr_pcalloc(pchild, sizeof(*worker_queue));    rv = ap_queue_init(worker_queue, ap_threads_per_child, pchild);    if (rv != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,                     "ap_queue_init() failed");        clean_child_exit(APEXIT_CHILDFATAL);    }    rv = ap_queue_info_create(&worker_queue_info, pchild,                              ap_threads_per_child);    if (rv != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,                     "ap_queue_info_create() failed");        clean_child_exit(APEXIT_CHILDFATAL);    }    worker_sockets = apr_pcalloc(pchild, ap_threads_per_child                                        * sizeof(apr_socket_t *));    loops = prev_threads_created = 0;    while (1) {        /* ap_threads_per_child does not include the listener thread */        for (i = 0; i < ap_threads_per_child; i++) {            int status = ap_scoreboard_image->servers[child_num_arg][i].status;            if (status != SERVER_GRACEFUL && status != SERVER_DEAD) {                continue;            }            my_info = (proc_info *)malloc(sizeof(proc_info));            if (my_info == NULL) {                ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf,                             "malloc: out of memory");                clean_child_exit(APEXIT_CHILDFATAL);            }            my_info->pid = my_child_num;            my_info->tid = i;            my_info->sd = 0;                    /* We are creating threads right now */            ap_update_child_status_from_indexes(my_child_num, i,                                                SERVER_STARTING, NULL);            /* We let each thread update its own scoreboard entry.  This is             * done because it lets us deal with tid better.             */            rv = apr_thread_create(&threads[i], thread_attr,                                    worker_thread, my_info, pchild);            if (rv != APR_SUCCESS) {                ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,                    "apr_thread_create: unable to create worker thread");                /* let the parent decide how bad this really is */                clean_child_exit(APEXIT_CHILDSICK);            }            threads_created++;        }        /* Start the listener only when there are workers available */        if (!listener_started && threads_created) {            create_listener_thread(ts);            listener_started = 1;        }        if (start_thread_may_exit || threads_created == ap_threads_per_child) {            break;        }        /* wait for previous generation to clean up an entry */        apr_sleep(apr_time_from_sec(1));        ++loops;        if (loops % 120 == 0) { /* every couple of minutes */            if (prev_threads_created == threads_created) {                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,                             "child %" APR_PID_T_FMT " isn't taking over "                             "slots very quickly (%d of %d)",                             ap_my_pid, threads_created, ap_threads_per_child);            }            prev_threads_created = threads_created;        }    }        /* What state should this child_main process be listed as in the      * scoreboard...?     *  ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING,      *                                      (request_rec *) NULL);     *      *  This state should be listed separately in the scoreboard, in some kind     *  of process_status, not mixed in with the worker threads' status.        *  "life_status" is almost right, but it's in the worker's structure, and      *  the name could be clearer.   gla     */    apr_thread_exit(thd, APR_SUCCESS);    return NULL;}static void join_workers(apr_thread_t *listener, apr_thread_t **threads){    int i;    apr_status_t rv, thread_rv;    if (listener) {        int iter;                /* deal with a rare timing window which affects waking up the         * listener thread...  if the signal sent to the listener thread         * is delivered between the time it verifies that the         * listener_may_exit flag is clear and the time it enters a         * blocking syscall, the signal didn't do any good...  work around         * that by sleeping briefly and sending it again         */        iter = 0;        while (iter < 10 && #ifdef HAVE_PTHREAD_KILL               pthread_kill(*listener_os_thread, 0)#else               kill(ap_my_pid, 0)#endif               == 0) {            /* listener not dead yet */            apr_sleep(apr_time_make(0, 500000));            wakeup_listener();            ++iter;        }        if (iter >= 10) {            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,                         "the listener thread didn't exit");        }        else {            rv = apr_thread_join(&thread_rv, listener);            if (rv != APR_SUCCESS) {                ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,                             "apr_thread_join: unable to join listener thread");            }        }    }        for (i = 0; i < ap_threads_per_child; i++) {        if (threads[i]) { /* if we ever created this thread */            rv = apr_thread_join(&thread_rv, threads[i]);            if (rv != APR_SUCCESS) {                ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,                             "apr_thread_join: unable to join worker "                             "thread %d",                             i);            }        }    }}static void join_start_thread(apr_thread_t *start_thread_id){    apr_status_t rv, thread_rv;    start_thread_may_exit = 1; /* tell it to give up in case it is still                                 * trying to take over slots from a                                 * previous generation                                */    rv = apr_thread_join(&thread_rv, start_thread_id);    if (rv != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,                     "apr_thread_join: unable to join the start "                     "thread");    }}static void child_main(int child_num_arg){    apr_thread_t **threads;    apr_status_t rv;    thread_starter *ts;    apr_threadattr_t *thread_attr;    apr_thread_t *start_thread_id;    mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this                                   * child initializes                                   */    ap_my_pid = getpid();    ap_fatal_signal_child_setup(ap_server_conf);    apr_pool_create(&pchild, pconf);    /*stuff to do before we switch id's, so we have permissions.*/    ap_reopen_scoreboard(pchild, NULL, 0);    rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&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 (unixd_setup_child()) {        clean_child_exit(APEXIT_CHILDFATAL);    }    ap_run_child_init(pchild, ap_server_conf);    /* done with init critical section */

⌨️ 快捷键说明

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