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

📄 child.c

📁 最新apache的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
                closesocket(context->accept_socket);                context->accept_socket = INVALID_SOCKET;            }        }        else {            /* ap_run_create_connection closes the socket on failure */            context->accept_socket = INVALID_SOCKET;        }    }    ap_update_child_status_from_indexes(0, thread_num, SERVER_DEAD,                                         (request_rec *) NULL);    ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ap_server_conf,                 "Child %d: Worker thread %ld exiting.", my_pid, thread_num);    return 0;}static void cleanup_thread(HANDLE *handles, int *thread_cnt, int thread_to_clean){    int i;    CloseHandle(handles[thread_to_clean]);    for (i = thread_to_clean; i < ((*thread_cnt) - 1); i++)	handles[i] = handles[i + 1];    (*thread_cnt)--;}/* * child_main()  * Entry point for the main control thread for the child process.  * This thread creates the accept thread, worker threads and * monitors the child process for maintenance and shutdown * events. */static void create_listener_thread(){    int tid;    int num_listeners = 0;    if (!use_acceptex) {        _beginthreadex(NULL, 0, win9x_accept,                       NULL, 0, &tid);    } else {        /* Start an accept thread per listener          * XXX: Why would we have a NULL sd in our listeners?         */        ap_listen_rec *lr;        /* Number of completion_contexts allowed in the system is         * (ap_threads_per_child + num_listeners). We need the additional         * completion contexts to prevent server hangs when ThreadsPerChild         * is configured to something less than or equal to the number         * of listeners. This is not a usual case, but people have          * encountered it.         * */        for (lr = ap_listeners; lr ; lr = lr->next) {            num_listeners++;        }        max_num_completion_contexts = ap_threads_per_child + num_listeners;        /* Now start a thread per listener */        for (lr = ap_listeners; lr; lr = lr->next) {            if (lr->sd != NULL) {                _beginthreadex(NULL, 1000, winnt_accept,                               (void *) lr, 0, &tid);            }        }    }}void child_main(apr_pool_t *pconf){    apr_status_t status;    apr_hash_t *ht;    ap_listen_rec *lr;    HANDLE child_events[2];    int threads_created = 0;    int listener_started = 0;    int tid;    HANDLE *child_handles;    int rv;    time_t end_time;    int i;    int cld;    apr_pool_create(&pchild, pconf);    apr_pool_tag(pchild, "pchild");    ap_run_child_init(pchild, ap_server_conf);    ht = apr_hash_make(pchild);    /* Initialize the child_events */    max_requests_per_child_event = CreateEvent(NULL, TRUE, FALSE, NULL);    if (!max_requests_per_child_event) {        ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,                     "Child %d: Failed to create a max_requests event.", my_pid);        exit(APEXIT_CHILDINIT);    }    child_events[0] = exit_event;    child_events[1] = max_requests_per_child_event;    allowed_globals.jobsemaphore = CreateSemaphore(NULL, 0, 1000000, NULL);    apr_thread_mutex_create(&allowed_globals.jobmutex,                             APR_THREAD_MUTEX_DEFAULT, pchild);    /*     * Wait until we have permission to start accepting connections.     * start_mutex is used to ensure that only one child ever     * goes into the listen/accept loop at once.     */    status = apr_proc_mutex_lock(start_mutex);    if (status != APR_SUCCESS) {        ap_log_error(APLOG_MARK,APLOG_ERR, status, ap_server_conf,                     "Child %d: Failed to acquire the start_mutex. Process will exit.", my_pid);        exit(APEXIT_CHILDINIT);    }    ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf,                  "Child %d: Acquired the start mutex.", my_pid);    /*     * Create the worker thread dispatch IOCompletionPort     * on Windows NT/2000     */    if (use_acceptex) {        /* Create the worker thread dispatch IOCP */        ThreadDispatchIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE,                                                    NULL,                                                    0,                                                    0); /* CONCURRENT ACTIVE THREADS */        apr_thread_mutex_create(&qlock, APR_THREAD_MUTEX_DEFAULT, pchild);        qwait_event = CreateEvent(NULL, TRUE, FALSE, NULL);        if (!qwait_event) {            ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,                         "Child %d: Failed to create a qwait event.", my_pid);            exit(APEXIT_CHILDINIT);        }    }    /*      * Create the pool of worker threads     */    ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf,                  "Child %d: Starting %d worker threads.", my_pid, ap_threads_per_child);    child_handles = (HANDLE) apr_pcalloc(pchild, ap_threads_per_child * sizeof(int));    apr_thread_mutex_create(&child_lock, APR_THREAD_MUTEX_DEFAULT, pchild);    while (1) {        for (i = 0; i < ap_threads_per_child; i++) {            int *score_idx;            int status = ap_scoreboard_image->servers[0][i].status;            if (status != SERVER_GRACEFUL && status != SERVER_DEAD) {                continue;            }            ap_update_child_status_from_indexes(0, i, SERVER_STARTING, NULL);            child_handles[i] = (HANDLE) _beginthreadex(NULL, 0, worker_main,                                                       (void *) i, 0, &tid);            if (child_handles[i] == 0) {                ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,                             "Child %d: _beginthreadex failed. Unable to create all worker threads. "                             "Created %d of the %d threads requested with the ThreadsPerChild configuration directive.",                              my_pid, threads_created, ap_threads_per_child);                ap_signal_parent(SIGNAL_PARENT_SHUTDOWN);                goto shutdown;            }            threads_created++;            /* Save the score board index in ht keyed to the thread handle. We need this              * when cleaning up threads down below...             */            apr_thread_mutex_lock(child_lock);            score_idx = apr_pcalloc(pchild, sizeof(int));            *score_idx = i;            apr_hash_set(ht, &child_handles[i], sizeof(HANDLE), score_idx);            apr_thread_mutex_unlock(child_lock);        }        /* Start the listener only when workers are available */        if (!listener_started && threads_created) {            create_listener_thread();            listener_started = 1;            winnt_mpm_state = AP_MPMQ_RUNNING;        }        if (threads_created == ap_threads_per_child) {            break;        }        /* Check to see if the child has been told to exit */        if (WaitForSingleObject(exit_event, 0) != WAIT_TIMEOUT) {            break;        }        /* wait for previous generation to clean up an entry in the scoreboard */        apr_sleep(1 * APR_USEC_PER_SEC);    }    /* Wait for one of three events:     * exit_event:      *    The exit_event is signaled by the parent process to notify      *    the child that it is time to exit.     *     * max_requests_per_child_event:      *    This event is signaled by the worker threads to indicate that     *    the process has handled MaxRequestsPerChild connections.     *     * TIMEOUT:     *    To do periodic maintenance on the server (check for thread exits,     *    number of completion contexts, etc.)     *     * XXX: thread exits *aren't* being checked.     *     * XXX: other_child - we need the process handles to the other children     *      in order to map them to apr_proc_other_child_read (which is not     *      named well, it's more like a_p_o_c_died.)     *     * XXX: however - if we get a_p_o_c handle inheritance working, and     *      the parent process creates other children and passes the pipes      *      to our worker processes, then we have no business doing such      *      things in the child_main loop, but should happen in master_main.     */    while (1) {#if !APR_HAS_OTHER_CHILD        rv = WaitForMultipleObjects(2, (HANDLE *) child_events, FALSE, INFINITE);        cld = rv - WAIT_OBJECT_0;#else        rv = WaitForMultipleObjects(2, (HANDLE *) child_events, FALSE, 1000);        cld = rv - WAIT_OBJECT_0;        if (rv == WAIT_TIMEOUT) {            apr_proc_other_child_check();        }        else #endif            if (rv == WAIT_FAILED) {            /* Something serious is wrong */            ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,                         "Child %d: WAIT_FAILED -- shutting down server", my_pid);            break;        }        else if (cld == 0) {            /* Exit event was signaled */            ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf,                         "Child %d: Exit event signaled. Child process is ending.", my_pid);            break;        }        else {            /* MaxRequestsPerChild event set by the worker threads.             * Signal the parent to restart             */            ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf,                         "Child %d: Process exiting because it reached "                         "MaxRequestsPerChild. Signaling the parent to "                         "restart a new child process.", my_pid);            ap_signal_parent(SIGNAL_PARENT_RESTART);            break;        }    }    /*      * Time to shutdown the child process      */ shutdown:    winnt_mpm_state = AP_MPMQ_STOPPING;    /* Setting is_graceful will cause threads handling keep-alive connections      * to close the connection after handling the current request.     */    is_graceful = 1;    /* Close the listening sockets. Note, we must close the listeners     * before closing any accept sockets pending in AcceptEx to prevent     * memory leaks in the kernel.     */    for (lr = ap_listeners; lr ; lr = lr->next) {        apr_socket_close(lr->sd);    }    /* Shutdown listener threads and pending AcceptEx socksts      * but allow the worker threads to continue consuming from     * the queue of accepted connections.     */    shutdown_in_progress = 1;    Sleep(1000);    /* Tell the worker threads to exit */    workers_may_exit = 1;    /* Release the start_mutex to let the new process (in the restart     * scenario) a chance to begin accepting and servicing requests      */    rv = apr_proc_mutex_unlock(start_mutex);    if (rv == APR_SUCCESS) {        ap_log_error(APLOG_MARK,APLOG_NOTICE, rv, ap_server_conf,                      "Child %d: Released the start mutex", my_pid);    }    else {        ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf,                      "Child %d: Failure releasing the start mutex", my_pid);    }    /* Shutdown the worker threads */    if (!use_acceptex) {        for (i = 0; i < threads_created; i++) {            add_job(INVALID_SOCKET);        }    }    else { /* Windows NT/2000 */        /* Post worker threads blocked on the ThreadDispatch IOCompletion port */        while (g_blocked_threads > 0) {            ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, ap_server_conf,                          "Child %d: %d threads blocked on the completion port", my_pid, g_blocked_threads);            for (i=g_blocked_threads; i > 0; i--) {                PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, IOCP_SHUTDOWN, NULL);            }            Sleep(1000);        }        /* Empty the accept queue of completion contexts */        apr_thread_mutex_lock(qlock);        while (qhead) {            CloseHandle(qhead->Overlapped.hEvent);            closesocket(qhead->accept_socket);            qhead = qhead->next;        }        apr_thread_mutex_unlock(qlock);    }    /* Give busy worker threads a chance to service their connections */    ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf,                  "Child %d: Waiting for %d worker threads to exit.", my_pid, threads_created);    end_time = time(NULL) + 180;    while (threads_created) {        rv = wait_for_many_objects(threads_created, child_handles, end_time - time(NULL));        if (rv != WAIT_TIMEOUT) {            rv = rv - WAIT_OBJECT_0;            ap_assert((rv >= 0) && (rv < threads_created));            cleanup_thread(child_handles, &threads_created, rv);            continue;        }        break;    }    /* Kill remaining threads off the hard way */    if (threads_created) {        ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf,                      "Child %d: Terminating %d threads that failed to exit.",                      my_pid, threads_created);    }    for (i = 0; i < threads_created; i++) {        int *score_idx;        TerminateThread(child_handles[i], 1);        CloseHandle(child_handles[i]);        /* Reset the scoreboard entry for the thread we just whacked */        score_idx = apr_hash_get(ht, &child_handles[i], sizeof(HANDLE));        ap_update_child_status_from_indexes(0, *score_idx, SERVER_DEAD, NULL);            }    ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf,                  "Child %d: All worker threads have exited.", my_pid);    CloseHandle(allowed_globals.jobsemaphore);    apr_thread_mutex_destroy(allowed_globals.jobmutex);    apr_thread_mutex_destroy(child_lock);    if (use_acceptex) {        apr_thread_mutex_destroy(qlock);        CloseHandle(qwait_event);    }    apr_pool_destroy(pchild);    CloseHandle(exit_event);}#endif /* def WIN32 */

⌨️ 快捷键说明

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