diff options
author | William A. Rowe Jr <wrowe@apache.org> | 2002-07-29 07:12:50 +0200 |
---|---|---|
committer | William A. Rowe Jr <wrowe@apache.org> | 2002-07-29 07:12:50 +0200 |
commit | f48e2283b15a141d5161cd392368579287028787 (patch) | |
tree | ad1ac93807bf4385a231fddbeda7d2989ea790a9 /server/mpm | |
parent | Refactor out the child behavior from mpm_winnt. This is the first (diff) | |
download | apache2-f48e2283b15a141d5161cd392368579287028787.tar.xz apache2-f48e2283b15a141d5161cd392368579287028787.zip |
pconf global factors out nicely. The one other pconf appears to be
eqivilant to pchild.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@96222 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'server/mpm')
-rw-r--r-- | server/mpm/winnt/child.c | 7 | ||||
-rw-r--r-- | server/mpm/winnt/mpm_winnt.c | 1227 | ||||
-rw-r--r-- | server/mpm/winnt/mpm_winnt.h | 43 |
3 files changed, 106 insertions, 1171 deletions
diff --git a/server/mpm/winnt/child.c b/server/mpm/winnt/child.c index b713d2ee06..45dff5dfa7 100644 --- a/server/mpm/winnt/child.c +++ b/server/mpm/winnt/child.c @@ -83,7 +83,6 @@ /* shared with mpm_winnt.c */ extern DWORD my_pid; -extern apr_pool_t *pconf; /* used by parent to signal the child to start and exit */ /* shared with mpm_winnt.c, but should be private to child.c */ @@ -97,7 +96,7 @@ extern int volatile is_graceful; /* Queue for managing the passing of COMP_CONTEXTs between * the accept and worker threads. */ -static apr_pool_t *pchild = NULL; +static apr_pool_t *pchild; static int shutdown_in_progress = 0; static int workers_may_exit = 0; static unsigned int g_blocked_threads = 0; @@ -417,7 +416,7 @@ static PCOMP_CONTEXT win9x_get_connection(PCOMP_CONTEXT context) if (context == NULL) { /* allocate the completion context and the transaction pool */ - context = apr_pcalloc(pconf, sizeof(COMP_CONTEXT)); + context = apr_pcalloc(pchild, sizeof(COMP_CONTEXT)); apr_pool_create(&context->ptrans, pchild); apr_pool_tag(context->ptrans, "ptrans"); context->ba = apr_bucket_alloc_create(pchild); @@ -757,7 +756,7 @@ static void create_listener_thread() } -void child_main() +void child_main(apr_pool_t *pconf) { apr_status_t status; apr_hash_t *ht; diff --git a/server/mpm/winnt/mpm_winnt.c b/server/mpm/winnt/mpm_winnt.c index 05e0292677..6716bfd2f5 100644 --- a/server/mpm/winnt/mpm_winnt.c +++ b/server/mpm/winnt/mpm_winnt.c @@ -56,6 +56,8 @@ * University of Illinois, Urbana-Champaign. */ +#ifdef WIN32 + #define CORE_PRIVATE #include "httpd.h" #include "http_main.h" @@ -108,19 +110,10 @@ */ extern apr_shm_t *ap_scoreboard_shm; server_rec *ap_server_conf; -typedef HANDLE thread; /* Definitions of WINNT MPM specific config globals */ -apr_pool_t *pconf; -static apr_pool_t *pchild = NULL; -static int workers_may_exit = 0; -static int shutdown_in_progress = 0; -static unsigned int g_blocked_threads = 0; - static HANDLE shutdown_event; /* used to signal the parent to shutdown */ static HANDLE restart_event; /* used to signal the parent to restart */ -static HANDLE exit_event; /* used by parent to signal the child to exit */ -static HANDLE max_requests_per_child_event; static char ap_coredump_dir[MAX_STRING_LEN]; @@ -129,23 +122,31 @@ static char const* signal_arg = NULL; OSVERSIONINFO osver; /* VER_PLATFORM_WIN32_NT */ -apr_proc_mutex_t *start_mutex; -static DWORD my_pid; static DWORD parent_pid; +DWORD my_pid; int ap_threads_per_child = 0; /* ap_my_generation are used by the scoreboard code */ ap_generation_t volatile ap_my_generation=0; -/* Queue for managing the passing of COMP_CONTEXTs between - * the accept and worker threads. + +/* shared by service.c as global, although + * perhaps it should be private. + */ +apr_pool_t *pconf; + + +/* definitions from child.c */ +void child_main(apr_pool_t *pconf); + +/* used by parent to signal the child to start and exit + * NOTE: these are not sophisticated enough for multiple children + * so they ultimately should not be shared with child.c */ -static apr_thread_mutex_t *qlock; -static PCOMP_CONTEXT qhead = NULL; -static PCOMP_CONTEXT qtail = NULL; -static int num_completion_contexts = 0; -static HANDLE ThreadDispatchIOCP = NULL; +extern apr_proc_mutex_t *start_mutex; +extern HANDLE exit_event; + /* Stub functions until this MPM supports the connection status API */ @@ -205,206 +206,6 @@ LISTEN_COMMANDS, }; -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->next = NULL; - ResetEvent(context->Overlapped.hEvent); - apr_thread_mutex_lock(qlock); - if (qtail) - qtail->next = context; - else - qhead = context; - qtail = context; - apr_thread_mutex_unlock(qlock); - } -} - -AP_DECLARE(PCOMP_CONTEXT) mpm_get_completion_context(void) -{ - apr_status_t rv; - PCOMP_CONTEXT context = NULL; - - /* Grab a context off the queue */ - apr_thread_mutex_lock(qlock); - if (qhead) { - context = qhead; - qhead = qhead->next; - if (!qhead) - qtail = NULL; - } - apr_thread_mutex_unlock(qlock); - - /* If we failed to grab a context off the queue, alloc one out of - * the child pool. There may be up to ap_threads_per_child contexts - * in the system at once. - */ - if (!context) { - if (num_completion_contexts >= ap_threads_per_child) { - 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; - } - return NULL; - } - /* Note: - * Multiple failures in the next two steps will cause the pchild pool - * to 'leak' storage. I don't think this is worth fixing... - */ - 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."); - return NULL; - } - - /* Create the tranaction pool */ - if ((rv = apr_pool_create(&context->ptrans, pchild)) != 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); - return NULL; - } - apr_pool_tag(context->ptrans, "ptrans"); - - context->accept_socket = INVALID_SOCKET; - context->ba = apr_bucket_alloc_create(pchild); - apr_atomic_inc(&num_completion_contexts); - } - - 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; -} - -/* This is the helper code to resolve late bound entry points - * missing from one or more releases of the Win32 API... - * but it sure would be nice if we didn't duplicate this code - * from the APR ;-) - */ -static const char* const lateDllName[DLL_defined] = { - "kernel32", "advapi32", "mswsock", "ws2_32" }; -static HMODULE lateDllHandle[DLL_defined] = { - NULL, NULL, NULL, NULL }; - -FARPROC ap_load_dll_func(ap_dlltoken_e fnLib, char* fnName, int ordinal) -{ - if (!lateDllHandle[fnLib]) { - lateDllHandle[fnLib] = LoadLibrary(lateDllName[fnLib]); - if (!lateDllHandle[fnLib]) - return NULL; - } - if (ordinal) - return GetProcAddress(lateDllHandle[fnLib], (char *) ordinal); - else - return GetProcAddress(lateDllHandle[fnLib], fnName); -} - -/* To share the semaphores with other processes, we need a NULL ACL - * Code from MS KB Q106387 - */ -static PSECURITY_ATTRIBUTES GetNullACL() -{ - PSECURITY_DESCRIPTOR pSD; - PSECURITY_ATTRIBUTES sa; - - sa = (PSECURITY_ATTRIBUTES) LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES)); - sa->nLength = sizeof(sizeof(SECURITY_ATTRIBUTES)); - - pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); - sa->lpSecurityDescriptor = pSD; - - if (pSD == NULL || sa == NULL) { - return NULL; - } - apr_set_os_error(0); - if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION) - || apr_get_os_error()) { - LocalFree( pSD ); - LocalFree( sa ); - return NULL; - } - if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE) - || apr_get_os_error()) { - LocalFree( pSD ); - LocalFree( sa ); - return NULL; - } - - sa->bInheritHandle = TRUE; - return sa; -} - -static void CleanNullACL( void *sa ) { - if( sa ) { - LocalFree( ((PSECURITY_ATTRIBUTES)sa)->lpSecurityDescriptor); - LocalFree( sa ); - } -} - -/* - * The Win32 call WaitForMultipleObjects will only allow you to wait for - * a maximum of MAXIMUM_WAIT_OBJECTS (current 64). Since the threading - * model in the multithreaded version of apache wants to use this call, - * we are restricted to a maximum of 64 threads. This is a simplistic - * routine that will increase this size. - */ -static DWORD wait_for_many_objects(DWORD nCount, CONST HANDLE *lpHandles, - DWORD dwSeconds) -{ - time_t tStopTime; - DWORD dwRet = WAIT_TIMEOUT; - DWORD dwIndex=0; - BOOL bFirst = TRUE; - - tStopTime = time(NULL) + dwSeconds; - - do { - if (!bFirst) - Sleep(1000); - else - bFirst = FALSE; - - for (dwIndex = 0; dwIndex * MAXIMUM_WAIT_OBJECTS < nCount; dwIndex++) { - dwRet = WaitForMultipleObjects( - min(MAXIMUM_WAIT_OBJECTS, nCount - (dwIndex * MAXIMUM_WAIT_OBJECTS)), - lpHandles + (dwIndex * MAXIMUM_WAIT_OBJECTS), - 0, 0); - - if (dwRet != WAIT_TIMEOUT) { - break; - } - } - } while((time(NULL) < tStopTime) && (dwRet == WAIT_TIMEOUT)); - - return dwRet; -} - /* * Signalling Apache on NT. * @@ -450,7 +251,8 @@ void setup_signal_names(char *prefix) "%s_restart", signal_name_prefix); } -static int volatile is_graceful = 0; +int volatile is_graceful = 0; + AP_DECLARE(int) ap_graceful_stop_signalled(void) { return is_graceful; @@ -517,81 +319,6 @@ AP_DECLARE(void) ap_signal_parent(ap_signal_parent_e type) CloseHandle(e); } -/* set_listeners_noninheritable() - * Make the listening socket handles noninheritable by processes - * started out of this process. - */ -static int set_listeners_noninheritable(apr_pool_t *p) -{ - ap_listen_rec *lr; - HANDLE dup; - SOCKET nsd; - HANDLE hProcess = GetCurrentProcess(); - - for (lr = ap_listeners; lr; lr = lr->next) { - apr_os_sock_get(&nsd,lr->sd); - if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - if (!DuplicateHandle(hProcess, (HANDLE) nsd, hProcess, &dup, - 0, FALSE, DUPLICATE_SAME_ACCESS)) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), ap_server_conf, - "set_listeners_noninheritable: DuplicateHandle failed."); - } - else { - closesocket(nsd); - nsd = (SOCKET) dup; - apr_os_sock_put(&lr->sd, &nsd, p); - } - } - else { - /* A different approach. Many users report errors such as - * (32538)An operation was attempted on something that is not - * a socket. : Parent: WSADuplicateSocket failed... - * - * This appears that the duplicated handle is no longer recognized - * as a socket handle. SetHandleInformation should overcome that - * problem by not altering the handle identifier. But this won't - * work on 9x - it's unsupported. - */ - if (!SetHandleInformation((HANDLE)nsd, HANDLE_FLAG_INHERIT, 0)) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), ap_server_conf, - "set_listeners_noninheritable: SetHandleInformation failed."); - } - } - } - - if (my_pid == parent_pid) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Parent: Marked listeners as not inheritable."); - } else { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Child %d: Marked listeners as not inheritable.", my_pid); - } - return 1; -} - -/* - * 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; - - for (lr = head_listener; lr ; lr = lr->next) { - apr_os_sock_get(&nsd, lr->sd); - if (FD_ISSET(nsd, main_fds)) { - head_listener = lr->next; - if (head_listener == NULL) - head_listener = ap_listeners; - - return (lr); - } - } - return NULL; -} /* * Passed the following handles [in sync with send_handles_to_child()] @@ -600,7 +327,7 @@ static APR_INLINE ap_listen_rec *find_ready_listener(fd_set * main_fds) * exit event [save to poll later] * scoreboard shm handle [to recreate the ap_scoreboard] */ -void get_handles_from_parent(server_rec *s) +void get_handles_from_parent(server_rec *s, apr_shm_t *scoreboard_shm) { HANDLE pipe; HANDLE hScore; @@ -659,829 +386,6 @@ void get_handles_from_parent(server_rec *s) "Child %d: Retrieved our scoreboard from the parent.", my_pid); } -/* - * get_listeners_from_parent() - * The listen sockets are opened in the parent. This function, which runs - * exclusively in the child process, receives them from the parent and - * makes them availeble in the child. - */ -void get_listeners_from_parent(server_rec *s) -{ - WSAPROTOCOL_INFO WSAProtocolInfo; - HANDLE pipe; - ap_listen_rec *lr; - DWORD BytesRead; - int lcnt = 0; - SOCKET nsd; - - /* Set up a default listener if necessary */ - if (ap_listeners == NULL) { - ap_listen_rec *lr; - lr = apr_palloc(s->process->pool, sizeof(ap_listen_rec)); - lr->sd = NULL; - lr->next = ap_listeners; - ap_listeners = lr; - } - - /* Open the pipe to the parent process to receive the inherited socket - * data. The sockets have been set to listening in the parent process. - */ - pipe = GetStdHandle(STD_INPUT_HANDLE); - - for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) { - if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO), - &BytesRead, (LPOVERLAPPED) NULL)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "setup_inherited_listeners: Unable to read socket data from parent"); - exit(APEXIT_CHILDINIT); - } - nsd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, - &WSAProtocolInfo, 0, 0); - if (nsd == INVALID_SOCKET) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), ap_server_conf, - "Child %d: setup_inherited_listeners(), WSASocket failed to open the inherited socket.", my_pid); - exit(APEXIT_CHILDINIT); - } - apr_os_sock_put(&lr->sd, &nsd, s->process->pool); - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Child %d: retrieved %d listeners from parent", my_pid, lcnt); - - if (!set_listeners_noninheritable(s->process->pool)) { - exit(APEXIT_CHILDINIT); - } -} - - -/* 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 100 - -static 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 (-1); - } - 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 void 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; - } - } - } - 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); - } - } - - do { - clen = sizeof(sa_client); - csd = accept(nsd, (struct sockaddr *) &sa_client, &clen); - if (csd == INVALID_SOCKET) { - csd = -1; - } - } while (csd < 0 && APR_STATUS_IS_EINTR(apr_get_netos_error())); - - if (csd < 0) { - if (APR_STATUS_IS_ECONNABORTED(apr_get_netos_error())) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), ap_server_conf, - "accept: (client socket)"); - } - } - else { - add_job(csd); - } - } - SetEvent(exit_event); -} - -static PCOMP_CONTEXT win9x_get_connection(PCOMP_CONTEXT context) -{ - apr_os_sock_info_t sockinfo; - int len; - - if (context == NULL) { - /* allocate the completion context and the transaction pool */ - context = apr_pcalloc(pconf, sizeof(COMP_CONTEXT)); - apr_pool_create(&context->ptrans, pchild); - apr_pool_tag(context->ptrans, "ptrans"); - context->ba = apr_bucket_alloc_create(pchild); - } - - while (1) { - apr_pool_clear(context->ptrans); - context->accept_socket = remove_job(); - if (context->accept_socket == -1) { - return NULL; - } - len = sizeof(struct sockaddr); - context->sa_server = apr_palloc(context->ptrans, len); - if (getsockname(context->accept_socket, - context->sa_server, &len)== SOCKET_ERROR) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), ap_server_conf, - "getsockname failed"); - continue; - } - len = sizeof(struct sockaddr); - context->sa_client = apr_palloc(context->ptrans, len); - if ((getpeername(context->accept_socket, - context->sa_client, &len)) == SOCKET_ERROR) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), ap_server_conf, - "getpeername failed"); - memset(&context->sa_client, '\0', sizeof(context->sa_client)); - } - sockinfo.os_sock = &context->accept_socket; - sockinfo.local = context->sa_server; - sockinfo.remote = context->sa_client; - sockinfo.family = APR_INET; - sockinfo.type = SOCK_STREAM; - apr_os_sock_make(&context->sock, &sockinfo, context->ptrans); - - return context; - } -} -/* Windows NT/2000 specific code... - * Accept processing for on Windows NT uses a producer/consumer queue - * model. An accept thread accepts connections off the network then issues - * PostQueuedCompletionStatus() to awake a thread blocked on the ThreadDispatch - * IOCompletionPort. - * - * winnt_accept() - * One or more accept threads run in this function, each of which accepts - * connections off the network and calls PostQueuedCompletionStatus() to - * queue an io completion packet to the ThreadDispatch IOCompletionPort. - * winnt_get_connection() - * Worker threads block on the ThreadDispatch IOCompletionPort awaiting - * connections to service. - */ -static void winnt_accept(void *lr_) -{ - ap_listen_rec *lr = (ap_listen_rec *)lr_; - apr_os_sock_info_t sockinfo; - PCOMP_CONTEXT context = NULL; - DWORD BytesRead; - SOCKET nlsd; - int rv; - - apr_os_sock_get(&nlsd, lr->sd); - - while (!shutdown_in_progress) { - if (!context) { - context = mpm_get_completion_context(); - if (!context) { - /* Temporary resource constraint? */ - Sleep(0); - continue; - } - } - - /* Create and initialize the accept socket */ - if (context->accept_socket == INVALID_SOCKET) { - context->accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (context->accept_socket == INVALID_SOCKET) { - /* Another temporary condition? */ - ap_log_error(APLOG_MARK,APLOG_WARNING, apr_get_netos_error(), ap_server_conf, - "winnt_accept: Failed to allocate an accept socket. " - "Temporary resource constraint? Try again."); - Sleep(100); - continue; - } - } - - /* AcceptEx on the completion context. The completion context will be - * signaled when a connection is accepted. - */ - if (!AcceptEx(nlsd, context->accept_socket, - context->buff, - 0, - PADDED_ADDR_SIZE, - PADDED_ADDR_SIZE, - &BytesRead, - &context->Overlapped)) { - rv = apr_get_netos_error(); - if (rv == APR_FROM_OS_ERROR(WSAEINVAL)) { - /* Hack alert. Occasionally, TransmitFile will not recycle the - * accept socket (usually when the client disconnects early). - * Get a new socket and try the call again. - */ - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf, - "winnt_accept: AcceptEx failed due to early client " - "disconnect. Reallocate the accept socket and try again."); - continue; - } - else if (rv != APR_FROM_OS_ERROR(ERROR_IO_PENDING)) { - ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf, - "winnt_accept: AcceptEx failed. Attempting to recover."); - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - Sleep(100); - continue; - } - - /* Wait for pending i/o. Wake up once per second to check for shutdown */ - while (1) { - rv = WaitForSingleObject(context->Overlapped.hEvent, 1000); - if (rv == WAIT_OBJECT_0) { - if (!GetOverlappedResult(context->Overlapped.hEvent, - &context->Overlapped, - &BytesRead, FALSE)) { - ap_log_error(APLOG_MARK,APLOG_WARNING, GetLastError(), ap_server_conf, - "winnt_accept: Asynchronous AcceptEx failed."); - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - } - break; - } - /* WAIT_TIMEOUT */ - if (shutdown_in_progress) { - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - break; - } - } - if (context->accept_socket == INVALID_SOCKET) { - continue; - } - } - - /* Inherit the listen socket settings. Required for - * shutdown() to work - */ - if (setsockopt(context->accept_socket, SOL_SOCKET, - SO_UPDATE_ACCEPT_CONTEXT, (char *)&nlsd, - sizeof(nlsd))) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), ap_server_conf, - "setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed."); - /* Not a failure condition. Keep running. */ - } - - /* Get the local & remote address */ - GetAcceptExSockaddrs(context->buff, - 0, - PADDED_ADDR_SIZE, - PADDED_ADDR_SIZE, - &context->sa_server, - &context->sa_server_len, - &context->sa_client, - &context->sa_client_len); - - sockinfo.os_sock = &context->accept_socket; - sockinfo.local = context->sa_server; - sockinfo.remote = context->sa_client; - sockinfo.family = APR_INET; - sockinfo.type = SOCK_STREAM; - apr_os_sock_make(&context->sock, &sockinfo, context->ptrans); - - /* When a connection is received, send an io completion notification to - * the ThreadDispatchIOCP. This function could be replaced by - * mpm_post_completion_context(), but why do an extra function call... - */ - PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, IOCP_CONNECTION_ACCEPTED, - &context->Overlapped); - context = NULL; - } - if (!shutdown_in_progress) { - /* Yow, hit an irrecoverable error! Tell the child to die. */ - SetEvent(exit_event); - } - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, ap_server_conf, - "Child %d: Accept thread exiting.", my_pid); -} -static PCOMP_CONTEXT winnt_get_connection(PCOMP_CONTEXT context) -{ - int rc; - DWORD BytesRead; - DWORD CompKey; - LPOVERLAPPED pol; - - mpm_recycle_completion_context(context); - - apr_atomic_inc(&g_blocked_threads); - while (1) { - if (workers_may_exit) { - apr_atomic_dec(&g_blocked_threads); - return NULL; - } - rc = GetQueuedCompletionStatus(ThreadDispatchIOCP, &BytesRead, &CompKey, - &pol, INFINITE); - if (!rc) { - rc = apr_get_os_error(); - ap_log_error(APLOG_MARK,APLOG_DEBUG, rc, ap_server_conf, - "Child %d: GetQueuedComplationStatus returned %d", my_pid, rc); - continue; - } - - switch (CompKey) { - case IOCP_CONNECTION_ACCEPTED: - context = CONTAINING_RECORD(pol, COMP_CONTEXT, Overlapped); - break; - case IOCP_SHUTDOWN: - apr_atomic_dec(&g_blocked_threads); - return NULL; - default: - apr_atomic_dec(&g_blocked_threads); - return NULL; - } - break; - } - apr_atomic_dec(&g_blocked_threads); - - return context; -} - -/* - * worker_main() - * Main entry point for the worker threads. Worker threads block in - * win*_get_connection() awaiting a connection to service. - */ -static void worker_main(long thread_num) -{ - static int requests_this_child = 0; - PCOMP_CONTEXT context = NULL; - ap_sb_handle_t *sbh; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ap_server_conf, - "Child %d: Worker thread %d starting.", my_pid, thread_num); - while (1) { - conn_rec *c; - apr_int32_t disconnected; - - ap_update_child_status_from_indexes(0, thread_num, SERVER_READY, NULL); - - /* Grab a connection off the network */ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - context = win9x_get_connection(context); - } - else { - context = winnt_get_connection(context); - } - if (!context) { - /* Time for the thread to exit */ - break; - } - - /* Have we hit MaxRequestPerChild connections? */ - if (ap_max_requests_per_child) { - requests_this_child++; - if (requests_this_child > ap_max_requests_per_child) { - SetEvent(max_requests_per_child_event); - } - } - - ap_create_sb_handle(&sbh, context->ptrans, 0, thread_num); - c = ap_run_create_connection(context->ptrans, ap_server_conf, - context->sock, thread_num, sbh, - context->ba); - - if (c) { - ap_process_connection(c, context->sock); - apr_socket_opt_get(context->sock, APR_SO_DISCONNECTED, - &disconnected); - if (!disconnected) { - context->accept_socket = INVALID_SOCKET; - ap_lingering_close(c); - } - } - 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 %d exiting.", my_pid, thread_num); -} - -static void cleanup_thread(thread *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; - if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - _beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE) 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; - for (lr = ap_listeners; lr; lr = lr->next) { - if (lr->sd != NULL) { - _beginthreadex(NULL, 1000, (LPTHREAD_START_ROUTINE) winnt_accept, - (void *) lr, 0, &tid); - } - } - } -} -static void child_main() -{ - 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; - thread *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 (osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) { - /* 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); - } - - /* - * 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 = (thread) apr_pcalloc(pchild, ap_threads_per_child * sizeof(int)); - 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] = (thread) _beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE) 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.", - 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... - */ - score_idx = apr_pcalloc(pchild, sizeof(int)); - *score_idx = i; - apr_hash_set(ht, &child_handles[i], sizeof(thread), score_idx); - } - /* Start the listener only when workers are available */ - if (!listener_started && threads_created) { - create_listener_thread(); - listener_started = 1; - } - 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.) - */ - while (1) { - rv = WaitForMultipleObjects(2, (HANDLE *) child_events, FALSE, 1000); - cld = rv - WAIT_OBJECT_0; - 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"); - break; - } - else if (rv == WAIT_TIMEOUT) { - apr_proc_other_child_check(); - } - 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: - /* 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 (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - for (i = 0; i < threads_created; i++) { - add_job(-1); - } - } - 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); - } - 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(thread)); - 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); - if (osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) - apr_thread_mutex_destroy(qlock); - - apr_pool_destroy(pchild); - CloseHandle(exit_event); -} static int send_handles_to_child(apr_pool_t *p, HANDLE child_ready_event, @@ -1542,6 +446,83 @@ static int send_handles_to_child(apr_pool_t *p, return 0; } + +/* + * get_listeners_from_parent() + * The listen sockets are opened in the parent. This function, which runs + * exclusively in the child process, receives them from the parent and + * makes them availeble in the child. + */ +void get_listeners_from_parent(server_rec *s) +{ + WSAPROTOCOL_INFO WSAProtocolInfo; + HANDLE pipe; + ap_listen_rec *lr; + DWORD BytesRead; + int lcnt = 0; + SOCKET nsd; + + /* Set up a default listener if necessary */ + if (ap_listeners == NULL) { + ap_listen_rec *lr; + lr = apr_palloc(s->process->pool, sizeof(ap_listen_rec)); + lr->sd = NULL; + lr->next = ap_listeners; + ap_listeners = lr; + } + + /* Open the pipe to the parent process to receive the inherited socket + * data. The sockets have been set to listening in the parent process. + */ + pipe = GetStdHandle(STD_INPUT_HANDLE); + + for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) { + if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO), + &BytesRead, (LPOVERLAPPED) NULL)) { + ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, + "setup_inherited_listeners: Unable to read socket data from parent"); + exit(APEXIT_CHILDINIT); + } + nsd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, + &WSAProtocolInfo, 0, 0); + if (nsd == INVALID_SOCKET) { + ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), ap_server_conf, + "Child %d: setup_inherited_listeners(), WSASocket failed to open the inherited socket.", my_pid); + exit(APEXIT_CHILDINIT); + } + + if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { + HANDLE hProcess = GetCurrentProcess(); + HANDLE dup; + if (DuplicateHandle(hProcess, (HANDLE) nsd, hProcess, &dup, + 0, FALSE, DUPLICATE_SAME_ACCESS)) { + closesocket(nsd); + nsd = (SOCKET) dup; + } + } + else { + /* A different approach. Many users report errors such as + * (32538)An operation was attempted on something that is not + * a socket. : Parent: WSADuplicateSocket failed... + * + * This appears that the duplicated handle is no longer recognized + * as a socket handle. SetHandleInformation should overcome that + * problem by not altering the handle identifier. But this won't + * work on 9x - it's unsupported. + */ + if (!SetHandleInformation((HANDLE)nsd, HANDLE_FLAG_INHERIT, 0)) { + ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), ap_server_conf, + "set_listeners_noninheritable: SetHandleInformation failed."); + } + } + apr_os_sock_put(&lr->sd, &nsd, s->process->pool); + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, + "Child %d: retrieved %d listeners from parent", my_pid, lcnt); +} + + static int send_listeners_to_child(apr_pool_t *p, DWORD dwProcessId, apr_file_t *child_in) { @@ -2508,10 +1489,6 @@ static int winnt_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, s return DONE; } - if (!set_listeners_noninheritable(s->process->pool)) { - return 1; - } - return OK; } @@ -2524,7 +1501,7 @@ static void winnt_child_init(apr_pool_t *pchild, struct server_rec *s) /* This is a child process, not in single process mode */ if (!one_process) { /* Set up events and the scoreboard */ - get_handles_from_parent(s); + get_handles_from_parent(s, ap_scoreboard_shm); /* Set up the listeners */ get_listeners_from_parent(s); @@ -2573,7 +1550,7 @@ AP_DECLARE(int) ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s ) ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Child %d: Child process is running", my_pid); - child_main(); + child_main(pconf); ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Child %d: Child process is exiting", my_pid); @@ -2631,3 +1608,5 @@ AP_MODULE_DECLARE_DATA module mpm_winnt_module = { winnt_cmds, /* command apr_table_t */ winnt_hooks /* register_hooks */ }; + +#endif /* def WIN32 */ diff --git a/server/mpm/winnt/mpm_winnt.h b/server/mpm/winnt/mpm_winnt.h index ab3d0011d9..8c9090fa50 100644 --- a/server/mpm/winnt/mpm_winnt.h +++ b/server/mpm/winnt/mpm_winnt.h @@ -113,49 +113,6 @@ typedef enum { } ap_signal_parent_e; AP_DECLARE(void) ap_signal_parent(ap_signal_parent_e type); -/* This code is stolen from the apr_private.h and misc/win32/misc.c - * Please see those sources for detailed documentation. - */ -typedef enum { - DLL_WINBASEAPI = 0, // kernel32 From WinBase.h - DLL_WINADVAPI = 1, // advapi32 From WinBase.h - DLL_WINSOCKAPI = 2, // mswsock From WinSock.h - DLL_WINSOCK2API = 3, // ws2_32 From WinSock2.h - DLL_defined = 4 // must define as last idx_ + 1 -} ap_dlltoken_e; - -FARPROC ap_load_dll_func(ap_dlltoken_e fnLib, char *fnName, int ordinal); - -#define AP_DECLARE_LATE_DLL_FUNC(lib, rettype, calltype, fn, ord, args, names) \ - typedef rettype (calltype *ap_winapi_fpt_##fn) args; \ - static ap_winapi_fpt_##fn ap_winapi_pfn_##fn = NULL; \ - __inline rettype ap_winapi_##fn args \ - { if (!ap_winapi_pfn_##fn) \ - ap_winapi_pfn_##fn = (ap_winapi_fpt_##fn) ap_load_dll_func(lib, #fn, ord); \ - return (*(ap_winapi_pfn_##fn)) names; }; \ - -/* Win2K kernel only */ -AP_DECLARE_LATE_DLL_FUNC(DLL_WINADVAPI, BOOL, WINAPI, ChangeServiceConfig2A, 0, ( - SC_HANDLE hService, - DWORD dwInfoLevel, - LPVOID lpInfo), - (hService, dwInfoLevel, lpInfo)); -#undef ChangeServiceConfig2 -#define ChangeServiceConfig2 ap_winapi_ChangeServiceConfig2A - -/* WinNT kernel only */ -AP_DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, BOOL, WINAPI, CancelIo, 0, ( - IN HANDLE hFile), - (hFile)); -#define CancelIo ap_winapi_CancelIo - -/* Win9x kernel only */ -AP_DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, DWORD, WINAPI, RegisterServiceProcess, 0, ( - DWORD dwProcessId, - DWORD dwType), - (dwProcessId, dwType)); -#define RegisterServiceProcess ap_winapi_RegisterServiceProcess - /* * The Windoes MPM uses a queue of completion contexts that it passes * between the accept threads and the worker threads. Declare the |