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

📄 child.c

📁 apache的软件linux版本
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements.  See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License.  You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#ifdef WIN32#define CORE_PRIVATE #include "httpd.h" #include "http_main.h" #include "http_log.h" #include "http_config.h"	/* for read_config */ #include "http_core.h"		/* for get_remote_host */ #include "http_connection.h"#include "apr_portable.h"#include "apr_thread_proc.h"#include "apr_getopt.h"#include "apr_strings.h"#include "apr_lib.h"#include "apr_shm.h"#include "apr_thread_mutex.h"#include "ap_mpm.h"#include "ap_config.h"#include "ap_listen.h"#include "mpm_default.h"#include "mpm_winnt.h"#include "mpm_common.h"#include <malloc.h>#include "apr_atomic.h"/* shared with mpm_winnt.c */extern DWORD my_pid;/* used by parent to signal the child to start and exit *//* shared with mpm_winnt.c, but should be private to child.c */apr_proc_mutex_t *start_mutex;HANDLE exit_event;/* child_main() should never need to modify is_graceful!?! */extern int volatile is_graceful;/* Queue for managing the passing of COMP_CONTEXTs between * the accept and worker threads. */static apr_pool_t *pchild;static int shutdown_in_progress = 0;static int workers_may_exit = 0;static unsigned int g_blocked_threads = 0;static HANDLE max_requests_per_child_event;static apr_thread_mutex_t  *child_lock;static apr_thread_mutex_t  *qlock;static PCOMP_CONTEXT qhead = NULL;static PCOMP_CONTEXT qtail = NULL;static int num_completion_contexts = 0;static int max_num_completion_contexts = 0;static HANDLE ThreadDispatchIOCP = NULL;static HANDLE qwait_event = NULL;AP_DECLARE(void) mpm_recycle_completion_context(PCOMP_CONTEXT context){    /* Recycle the completion context.     * - clear the ptrans pool     * - put the context on the queue to be consumed by the accept thread     * Note:      * context->accept_socket may be in a disconnected but reusable      * state so -don't- close it.     */    if (context) {        apr_pool_clear(context->ptrans);        context->ba = apr_bucket_alloc_create(context->ptrans);        context->next = NULL;        ResetEvent(context->Overlapped.hEvent);        apr_thread_mutex_lock(qlock);        if (qtail) {            qtail->next = context;        } else {            qhead = context;            SetEvent(qwait_event);        }        qtail = context;        apr_thread_mutex_unlock(qlock);    }}AP_DECLARE(PCOMP_CONTEXT) mpm_get_completion_context(void){    apr_status_t rv;    PCOMP_CONTEXT context = NULL;    while (1) {        /* Grab a context off the queue */        apr_thread_mutex_lock(qlock);        if (qhead) {            context = qhead;            qhead = qhead->next;            if (!qhead)                qtail = NULL;        } else {            ResetEvent(qwait_event);        }        apr_thread_mutex_unlock(qlock);          if (!context) {            /* We failed to grab a context off the queue, consider allocating             * a new one out of the child pool. There may be up to              * (ap_threads_per_child + num_listeners) contexts in the system              * at once.             */            if (num_completion_contexts >= max_num_completion_contexts) {                /* All workers are busy, need to wait for one */                static int reported = 0;                if (!reported) {                    ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,                                 "Server ran out of threads to serve requests. Consider "                                 "raising the ThreadsPerChild setting");                    reported = 1;                }                /* Wait for a worker to free a context. Once per second, give                 * the caller a chance to check for shutdown. If the wait                 * succeeds, get the context off the queue. It must be available,                 * since there's only one consumer.                 */                rv = WaitForSingleObject(qwait_event, 1000);                if (rv == WAIT_OBJECT_0)                    continue;                else /* Hopefully, WAIT_TIMEOUT */                    return NULL;            } else {                /* Allocate another context.                 * Note:                 * Multiple failures in the next two steps will cause the pchild pool                 * to 'leak' storage. I don't think this is worth fixing...                 */                apr_allocator_t *allocator;                apr_thread_mutex_lock(child_lock);                context = (PCOMP_CONTEXT) apr_pcalloc(pchild, sizeof(COMP_CONTEXT));                  context->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);                if (context->Overlapped.hEvent == NULL) {                    /* Hopefully this is a temporary condition ... */                    ap_log_error(APLOG_MARK,APLOG_WARNING, apr_get_os_error(), ap_server_conf,                                 "mpm_get_completion_context: CreateEvent failed.");                    apr_thread_mutex_unlock(child_lock);                    return NULL;                }                 /* Create the tranaction pool */                apr_allocator_create(&allocator);                apr_allocator_max_free_set(allocator, ap_max_mem_free);                rv = apr_pool_create_ex(&context->ptrans, pchild, NULL, allocator);                if (rv != APR_SUCCESS) {                    ap_log_error(APLOG_MARK,APLOG_WARNING, rv, ap_server_conf,                                 "mpm_get_completion_context: Failed to create the transaction pool.");                    CloseHandle(context->Overlapped.hEvent);                    apr_thread_mutex_unlock(child_lock);                    return NULL;                }                apr_allocator_owner_set(allocator, context->ptrans);                apr_pool_tag(context->ptrans, "transaction");                context->accept_socket = INVALID_SOCKET;                context->ba = apr_bucket_alloc_create(context->ptrans);                apr_atomic_inc(&num_completion_contexts);                 apr_thread_mutex_unlock(child_lock);                break;            }        } else {            /* Got a context from the queue */            break;        }    }    return context;}AP_DECLARE(apr_status_t) mpm_post_completion_context(PCOMP_CONTEXT context,                                                      io_state_e state){    LPOVERLAPPED pOverlapped;    if (context)        pOverlapped = &context->Overlapped;    else        pOverlapped = NULL;    PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, state, pOverlapped);    return APR_SUCCESS;}/* * find_ready_listener() * Only used by Win9* and should go away when the win9*_accept() function is  * reimplemented using apr_poll(). */static ap_listen_rec *head_listener;static APR_INLINE ap_listen_rec *find_ready_listener(fd_set * main_fds){    ap_listen_rec *lr;    SOCKET nsd;    lr = head_listener;    do {        apr_os_sock_get(&nsd, lr->sd);        if (FD_ISSET(nsd, main_fds)) {            head_listener = lr->next;            if (!head_listener) {                head_listener = ap_listeners;            }            return lr;        }        lr = lr->next;        if (!lr) {            lr = ap_listeners;        }    } while (lr != head_listener);    return NULL;}/* Windows 9x specific code... * Accept processing for on Windows 95/98 uses a producer/consumer queue  * model. A single thread accepts connections and queues the accepted socket  * to the accept queue for consumption by a pool of worker threads. * * win9x_accept() *    The accept threads runs this function, which accepts connections off  *    the network and calls add_job() to queue jobs to the accept_queue. * add_job()/remove_job() *    Add or remove an accepted socket from the list of sockets  *    connected to clients. allowed_globals.jobmutex protects *    against multiple concurrent access to the linked list of jobs. * win9x_get_connection() *    Calls remove_job() to pull a job from the accept queue. All the worker  *    threads block on remove_job. */typedef struct joblist_s {    struct joblist_s *next;    int sock;} joblist;typedef struct globals_s {    HANDLE jobsemaphore;    joblist *jobhead;    joblist *jobtail;    apr_thread_mutex_t *jobmutex;    int jobcount;} globals;globals allowed_globals = {NULL, NULL, NULL, NULL, 0};#define MAX_SELECT_ERRORS 100static void add_job(int sock){    joblist *new_job;    new_job = (joblist *) malloc(sizeof(joblist));    if (new_job == NULL) {	ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,                      "Ouch!  Out of memory in add_job()!");        return;    }    new_job->next = NULL;    new_job->sock = sock;    apr_thread_mutex_lock(allowed_globals.jobmutex);    if (allowed_globals.jobtail != NULL)	allowed_globals.jobtail->next = new_job;    allowed_globals.jobtail = new_job;    if (!allowed_globals.jobhead)	allowed_globals.jobhead = new_job;    allowed_globals.jobcount++;    ReleaseSemaphore(allowed_globals.jobsemaphore, 1, NULL);    apr_thread_mutex_unlock(allowed_globals.jobmutex);}static int remove_job(void){    joblist *job;    int sock;    WaitForSingleObject(allowed_globals.jobsemaphore, INFINITE);    apr_thread_mutex_lock(allowed_globals.jobmutex);    if (shutdown_in_progress && !allowed_globals.jobhead) {        apr_thread_mutex_unlock(allowed_globals.jobmutex);	return (INVALID_SOCKET);    }    job = allowed_globals.jobhead;    ap_assert(job);    allowed_globals.jobhead = job->next;    if (allowed_globals.jobhead == NULL)	allowed_globals.jobtail = NULL;    apr_thread_mutex_unlock(allowed_globals.jobmutex);    sock = job->sock;    free(job);    return (sock);}static unsigned int __stdcall win9x_accept(void * dummy){    struct timeval tv;    fd_set main_fds;    int wait_time = 1;    int csd;    SOCKET nsd = INVALID_SOCKET;    struct sockaddr_in sa_client;    int count_select_errors = 0;    int rc;    int clen;    ap_listen_rec *lr;    struct fd_set listenfds;    SOCKET listenmaxfd = INVALID_SOCKET;    /* Setup the listeners      * ToDo: Use apr_poll()     */    FD_ZERO(&listenfds);    for (lr = ap_listeners; lr; lr = lr->next) {        if (lr->sd != NULL) {            apr_os_sock_get(&nsd, lr->sd);            FD_SET(nsd, &listenfds);            if (listenmaxfd == INVALID_SOCKET || nsd > listenmaxfd) {                listenmaxfd = nsd;            }            ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,                         "Child %d: Listening on port %d.", my_pid, lr->bind_addr->port);        }    }    head_listener = ap_listeners;    while (!shutdown_in_progress) {	tv.tv_sec = wait_time;	tv.tv_usec = 0;	memcpy(&main_fds, &listenfds, sizeof(fd_set));	rc = select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv);        if (rc == 0 || (rc == SOCKET_ERROR && APR_STATUS_IS_EINTR(apr_get_netos_error()))) {            count_select_errors = 0;    /* reset count of errors */                        continue;        }        else if (rc == SOCKET_ERROR) {            /* A "real" error occurred, log it and increment the count of             * select errors. This count is used to ensure we don't go into             * a busy loop of continuous errors.             */            ap_log_error(APLOG_MARK, APLOG_INFO, apr_get_netos_error(), ap_server_conf,                          "select failed with error %d", apr_get_netos_error());            count_select_errors++;            if (count_select_errors > MAX_SELECT_ERRORS) {                shutdown_in_progress = 1;                ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), ap_server_conf,                             "Too many errors in select loop. Child process exiting.");                break;            }	} else {	    ap_listen_rec *lr;	    lr = find_ready_listener(&main_fds);	    if (lr != NULL) {                /* fetch the native socket descriptor */                apr_os_sock_get(&nsd, lr->sd);	    }

⌨️ 快捷键说明

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