You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by st...@hyperreal.org on 1999/08/20 22:20:34 UTC

cvs commit: apache-2.0/mpm/src/modules/mpm/winnt winnt.h winnt.c

stoddard    99/08/20 13:20:34

  Modified:    mpm/src/modules/mpm/winnt winnt.h winnt.c
  Log:
  Use AcceptEx (a.k.a. accept and receive) on windows NT. Begin work to make
  the WIN9x code co-exist with the NT specific code. Since I started this work,
  I've managed to improve the static page serving performance of Apache on NT by
  almost 50%. Still a long way from Apache on Linux though.
  
  TODO:
  - Reuse the AcceptEx accept socket (performance)
  - Clean up the organization of the winnt mpm
  - Implement Async AcceptEx and Receive. Will this break modules?
  - File handle cache (file i/o accounts for more than 50% of the time per request)
  - TransmitFile (I have prototype code implemented). Should we add a send_file API
  to the I/O control layer? Maybe Apache should always try to send_file. Platforms
  that don't support send_file could in turn, invoke the appropriate buff code
  which would then invoke socket iol write/writev.
  
  Revision  Changes    Path
  1.2       +11 -0     apache-2.0/mpm/src/modules/mpm/winnt/winnt.h
  
  Index: winnt.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/mpm/src/modules/mpm/winnt/winnt.h,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- winnt.h	1999/08/05 21:08:25	1.1
  +++ winnt.h	1999/08/20 20:20:32	1.2
  @@ -64,4 +64,15 @@
   extern int ap_extended_status;
   extern void clean_child_exit(int);
   
  +typedef struct CompContext {
  +    OVERLAPPED Overlapped;
  +    SOCKET accept_socket;
  +    BUFF* conn_io;
  +    pool *ptrans;
  +    struct sockaddr sa_server;
  +    int sa_server_len;
  +    struct sockaddr sa_client;
  +    int sa_client_len;
  +} COMP_CONTEXT, *PCOMP_CONTEXT;
  +
   #endif /* APACHE_MPM_WINNT_H */
  
  
  
  1.9       +281 -214  apache-2.0/mpm/src/modules/mpm/winnt/winnt.c
  
  Index: winnt.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/mpm/src/modules/mpm/winnt/winnt.c,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- winnt.c	1999/08/17 22:05:17	1.8
  +++ winnt.c	1999/08/20 20:20:33	1.9
  @@ -70,6 +70,7 @@
   #include "../os/win32/getopt.h"
   #include "mpm_default.h"
   #include "../os/win32/iol_socket.h"
  +#include "winnt.h"
   
   /*
    * Definitions of WINNT MPM specific config globals
  @@ -80,7 +81,6 @@
   static int ap_threads_per_child = 0;
   static int workers_may_exit = 0;
   static int max_requests_per_child = 0;
  -static int requests_this_child;
   
   static struct pollfd *listenfds;
   static int num_listenfds = 0;
  @@ -248,12 +248,7 @@
   }
   
   /*
  - * Routines to deal with managing the list of listening sockets...
  - * find_ready_listener()
  - *   Finds a listener which is ready for accept(). This advances 
  - *   the head_listener global.
  - * setup_listeners()
  - * setup_inherited_listeners() 
  + * Routines to deal with managing the list of listening sockets.
    */
   static ap_listen_rec *head_listener;
   static ap_inline ap_listen_rec *find_ready_listener(fd_set * main_fds)
  @@ -431,15 +426,6 @@
    * process is active at once.
    **********************************************************************/
   
  -/* The code protected by #ifdef UNGRACEFUL_RESTARTS/#endif sections
  - * could implement a sort-of ungraceful restart for Win32. instead of
  - * graceful restarts. 
  - *
  - * However it does not work too well because it does not intercept a
  - * connection already in progress (in child_sub_main()). We'd have to
  - * get that to poll on the exit event. 
  - */
  -
   int service_init()
   {
   /*
  @@ -473,20 +459,15 @@
    */
   
   typedef struct globals_s {
  -#ifdef UNGRACEFUL_RESTART
  -    HANDLE thread_exit_event;
  -#else
  -    int exit_now;
  -#endif
       semaphore *jobsemaphore;
       joblist *jobhead;
       joblist *jobtail;
  -    mutex *jobmutex;
  +    CRITICAL_SECTION jobmutex;
       int jobcount;
   } globals;
   
   globals allowed_globals =
  -{0, NULL, NULL, NULL, NULL, 0};
  +{NULL, NULL, NULL, NULL, 0};
   
   /*
    * add_job()/remove_job() - add or remove an accepted socket from the
  @@ -494,19 +475,19 @@
    * against multiple concurrent access to the linked list of jobs.
    */
   
  -void add_job(int sock)
  +static void add_job(int sock)
   {
       joblist *new_job;
   
  -    ap_assert(allowed_globals.jobmutex);
  -    /* TODO: If too many jobs in queue, sleep, check for problems */
  -    ap_acquire_mutex(allowed_globals.jobmutex);
       new_job = (joblist *) malloc(sizeof(joblist));
       if (new_job == NULL) {
   	fprintf(stderr, "Ouch!  Out of memory in add_job()!\n");
  +        return;
       }
       new_job->next = NULL;
       new_job->sock = sock;
  +
  +    EnterCriticalSection(&allowed_globals.jobmutex);
       if (allowed_globals.jobtail != NULL)
   	allowed_globals.jobtail->next = new_job;
       allowed_globals.jobtail = new_job;
  @@ -514,39 +495,19 @@
   	allowed_globals.jobhead = new_job;
       allowed_globals.jobcount++;
       release_semaphore(allowed_globals.jobsemaphore);
  -    ap_release_mutex(allowed_globals.jobmutex);
  +    LeaveCriticalSection(&allowed_globals.jobmutex);
   }
   
  -int remove_job(void)
  +static int remove_job(void)
   {
       joblist *job;
       int sock;
   
  -#ifdef UNGRACEFUL_RESTART
  -    HANDLE hObjects[2];
  -    int rv;
  -
  -    hObjects[0] = allowed_globals.jobsemaphore;
  -    hObjects[1] = allowed_globals.thread_exit_event;
  -
  -    rv = WaitForMultipleObjects(2, hObjects, FALSE, INFINITE);
  -    ap_assert(rv != WAIT_FAILED);
  -    if (rv == WAIT_OBJECT_0 + 1) {
  -	return -1;
  -    }
  -    /* must be semaphore */
  -#else
       acquire_semaphore(allowed_globals.jobsemaphore);
  -#endif
  -    ap_assert(allowed_globals.jobmutex);
  +    EnterCriticalSection(&allowed_globals.jobmutex);
   
  -#ifdef UNGRACEFUL_RESTART
  -    if (!allowed_globals.jobhead) {
  -#else
  -    ap_acquire_mutex(allowed_globals.jobmutex);
  -    if (allowed_globals.exit_now && !allowed_globals.jobhead) {
  -#endif
  -	ap_release_mutex(allowed_globals.jobmutex);
  +    if (workers_may_exit && !allowed_globals.jobhead) {
  +        LeaveCriticalSection(&allowed_globals.jobmutex);
   	return (-1);
       }
       job = allowed_globals.jobhead;
  @@ -554,11 +515,212 @@
       allowed_globals.jobhead = job->next;
       if (allowed_globals.jobhead == NULL)
   	allowed_globals.jobtail = NULL;
  -    ap_release_mutex(allowed_globals.jobmutex);
  +    LeaveCriticalSection(&allowed_globals.jobmutex);
       sock = job->sock;
       free(job);
  +
       return (sock);
   }
  +#define MAX_SELECT_ERRORS 100
  +#define PADDED_ADDR_SIZE sizeof(SOCKADDR_IN)+16
  +static void accept_and_queue_connections(void * dummy)
  +{
  +    int requests_this_child = 0;
  +    struct timeval tv;
  +    fd_set main_fds;
  +    int wait_time = 1;
  +    int csd;
  +    int sd = -1;
  +    struct sockaddr_in sa_client;
  +    int count_select_errors = 0;
  +    int rc;
  +    int clen;
  +
  +    while (!workers_may_exit) {
  +        if (ap_max_requests_per_child && (requests_this_child > ap_max_requests_per_child)) {
  +            break;
  +	}
  +
  +	tv.tv_sec = wait_time;
  +	tv.tv_usec = 0;
  +	memcpy(&main_fds, &listenfds, sizeof(fd_set));
  +
  +	rc = ap_select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv);
  +
  +        if (rc == 0 || (rc == SOCKET_ERROR && h_errno == WSAEINTR)) {
  +            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|APLOG_WIN32ERROR, server_conf, "select failed with errno %d", h_errno);
  +            count_select_errors++;
  +            if (count_select_errors > MAX_SELECT_ERRORS) {
  +                ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, 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) {
  +		sd = lr->fd;
  +	    }
  +	}
  +
  +	do {
  +	    clen = sizeof(sa_client);
  +	    csd = accept(sd, (struct sockaddr *) &sa_client, &clen);
  +	    if (csd == INVALID_SOCKET) {
  +		csd = -1;
  +	    }
  +	} while (csd < 0 && h_errno == WSAEINTR);
  +
  +	if (csd < 0) {
  +            if (h_errno != WSAECONNABORTED) {
  +		ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf,
  +			    "accept: (client socket)");
  +            }
  +	}
  +	else {
  +	    add_job(csd);
  +	    requests_this_child++;
  +	}
  +    }
  +    SetEvent(exit_event);
  +}
  +static PCOMP_CONTEXT win9x_get_connection(PCOMP_CONTEXT context)
  +{
  +    int len;
  +    while (1) {
  +        context->accept_socket = remove_job();
  +        if (context->accept_socket == -1) {
  +            CloseHandle(context->Overlapped.hEvent); /* TODO: Clean up in the caller not here */
  +            return NULL;
  +        }
  +
  +        len = sizeof(struct sockaddr);
  +        if (getsockname(context->accept_socket, 
  +                        &context->sa_server, &len)== SOCKET_ERROR) {
  +            ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, 
  +                         "getsockname failed with error %d\n", WSAGetLastError());
  +            continue;
  +        }
  +        
  +        len = sizeof(struct sockaddr);
  +        if ((getpeername(context->accept_socket,
  +                         &context->sa_client, &len)) == SOCKET_ERROR) {
  +            ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, 
  +                         "getpeername failed with error %d\n", WSAGetLastError());
  +            memset(&context->sa_client, '\0', sizeof(context->sa_client));
  +        }
  +
  +        return context;
  +    }
  +}
  +static PCOMP_CONTEXT winnt_get_connection(PCOMP_CONTEXT context)
  +{
  +    int requests_this_child = 0;
  +    int count_select_errors = 0;
  +    struct timeval tv;
  +    fd_set main_fds;
  +    int wait_time = 1;
  +    int sd = -1;
  +    int rc;
  +
  +    /* AcceptEx needs a pre-allocated accept socket */
  +    context->accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  +
  +    EnterCriticalSection(&allowed_globals.jobmutex);    
  +
  +    while (!workers_may_exit) {
  +        workers_may_exit |= ((ap_max_requests_per_child != 0) && (requests_this_child > ap_max_requests_per_child));
  +        if (workers_may_exit)
  +            break;
  +
  +        tv.tv_sec = wait_time;
  +        tv.tv_usec = 0;
  +        memcpy(&main_fds, &listenfds, sizeof(fd_set));
  +
  +        rc = ap_select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv);
  +
  +        if (rc == 0 || (rc == SOCKET_ERROR && h_errno == WSAEINTR)) {
  +            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|APLOG_WIN32ERROR, server_conf, "select failed with errno %d", h_errno);
  +            count_select_errors++;
  +            if (count_select_errors > MAX_SELECT_ERRORS) {
  +                ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf,
  +                             "Too many errors in select loop. Child process exiting.");
  +                break;
  +            }
  +        }
  +        else {
  +            DWORD BytesRead;
  +            ap_listen_rec *lr;
  +            
  +            lr = find_ready_listener(&main_fds);
  +            if (lr != NULL) {
  +                sd = lr->fd;
  +            }
  +            else {
  +                ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf,
  +                             "select returned but there are no ready listeners! Exiting.");
  +                break;
  +            }
  +
  +            rc = AcceptEx(sd, context->accept_socket,
  +                          context->conn_io->inbase,
  +                          context->conn_io->bufsiz - 2*PADDED_ADDR_SIZE,
  +                          PADDED_ADDR_SIZE,
  +                          PADDED_ADDR_SIZE,
  +                          &BytesRead,
  +                          &context->Overlapped);
  +            
  +            if (!rc && (h_errno == WSA_IO_PENDING)) {
  +                rc = GetOverlappedResult(context->Overlapped.hEvent,
  +                                         &context->Overlapped,
  +                                         &BytesRead,
  +                                         INFINITE); /* TODO: get timeout from the config file */
  +            }
  +            if (!rc) {
  +                if (h_errno != WSAECONNABORTED) {
  +                    ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf,
  +                                 "AcceptEx failed.");
  +                }
  +                continue;  /* go back to select */
  +            }
  +            requests_this_child++;   
  +            context->conn_io->incnt = BytesRead;
  +            GetAcceptExSockaddrs(context->conn_io->inbase, 
  +                                 context->conn_io->bufsiz - 2*PADDED_ADDR_SIZE,
  +                                 PADDED_ADDR_SIZE,
  +                                 PADDED_ADDR_SIZE,
  +                                 &context->sa_server,
  +                                 &context->sa_server_len,
  +                                 &context->sa_client,
  +                                 &context->sa_client_len);
  +
  +
  +            LeaveCriticalSection(&allowed_globals.jobmutex);
  +            return context;
  +        }
  +    }
  +    CloseHandle(context->Overlapped.hEvent);
  +    LeaveCriticalSection(&allowed_globals.jobmutex);
  +    SetEvent(exit_event);
  +    return NULL;
  +}
   
   /*
    * child_main() - this is the main loop for the worker threads
  @@ -578,61 +740,49 @@
    *  - block in remove_job, and when unblocked we have an already
    *    accepted socket, instead of blocking on a mutex or select().
    */
  -
  +//#define QUEUED_ACCEPT  for Windows 95 TODO: Make this a run time check
   static void child_main(int child_num)
   {
  -    struct sockaddr sa_server;
  -    struct sockaddr sa_client;
  -    int len;
  -    BUFF *conn_io;
  -    conn_rec *current_conn;
  +    PCOMP_CONTEXT lpCompContext;
       ap_iol *iol;
  -
  -    pool *ptrans;
  -    int requests_this_child = 0;
  -    int csd = -1;
   
  -    ptrans = ap_make_sub_pool(pconf);
  +    /* Create and initialize the static (unchangeing) portion of the 
  +     * completion context 
  +     */
  +    lpCompContext = ap_pcalloc(pconf, sizeof(COMP_CONTEXT));
  +    lpCompContext->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
  +    lpCompContext->ptrans = ap_make_sub_pool(pconf);
   
   #if 0
       (void) ap_update_child_status(child_num, SERVER_READY, (request_rec *) NULL);
   #endif
   
       while (1) {
  -	current_conn = NULL;
  -	ap_clear_pool(ptrans);
  -#if 0
  -	(void) ap_update_child_status(child_num, SERVER_READY,
  -	                              (request_rec *) NULL);
  +        BUFF *conn_io;
  +        pool *ptrans;
  +        int csd = -1;
  +        conn_rec *current_conn;
  +
  +        /* Initialize the dynamic portion of the completion context */
  +	ap_clear_pool(lpCompContext->ptrans);
  +        lpCompContext->conn_io =  ap_bcreate(lpCompContext->ptrans, B_RDWR);
  +
  +
  +#ifdef QUEUED_ACCEPT
  +        lpCompContext = win9x_get_connection(lpCompContext);
  +#else
  +        lpCompContext = winnt_get_connection(lpCompContext);
   #endif
   
  -	/* Get job from the job list. This will block until a job is ready.
  -	 * If -1 is returned then the main thread wants us to exit.
  -	 */
  -	csd = remove_job();
  -	if (csd == -1)
  -	    break;		/* time to exit */
  -	requests_this_child++;
  +        if (!lpCompContext)
  +            break;
   
  -	ap_note_cleanups_for_socket(ptrans, csd);
  +        conn_io = lpCompContext->conn_io;
  +        ptrans = lpCompContext->ptrans;
  +        csd = lpCompContext->accept_socket;
   
  -	/*
  -	 * We now have a connection, so set it up with the appropriate
  -	 * socket options, file descriptors, and read/write buffers.
  -	 */
  -        len = sizeof(struct sockaddr);
  -	if (getsockname(csd, &sa_server, &len)== SOCKET_ERROR) {
  -	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, 
  -                         "getsockname failed with error %d\n", WSAGetLastError());
  -	    continue;
  -	}
  +	ap_note_cleanups_for_socket(ptrans, csd);
   
  -	len = sizeof(struct sockaddr);
  -	if ((getpeername(csd, &sa_client, &len)) == SOCKET_ERROR) {
  -            ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, 
  -                         "getpeername failed with error %d\n", WSAGetLastError());
  -	    memset(&sa_client, '\0', sizeof(sa_client));
  -	}
   #if 0
   	(void) ap_update_child_status(child_num, SERVER_BUSY_READ,
                                         (request_rec *) NULL);
  @@ -647,16 +797,16 @@
               continue;
           }
   
  -	conn_io = ap_bcreate(ptrans, B_RDWR);
           ap_bpush_iol(conn_io, iol);
   
   	current_conn = ap_new_connection(ptrans, server_conf, conn_io,
  -                                         (struct sockaddr_in *) &sa_client,
  -                                         (struct sockaddr_in *) &sa_server,
  +                                         (struct sockaddr_in *) &lpCompContext->sa_client,
  +                                         (struct sockaddr_in *) &lpCompContext->sa_server,
                                            child_num);
   
           ap_process_connection(current_conn);
       }
  +    /* TODO: Add code to clean-up completion contexts here */
   }
   
   static void cleanup_thread(thread **handles, int *thread_cnt, int thread_to_clean)
  @@ -708,10 +858,7 @@
       return dwRet;
   }
   
  -//extern void main_control_server(void *); /* in hellop.c */
   
  -#define MAX_SELECT_ERRORS 100
  -
   /*
    * Initialise the signal names, in the global variables signal_name_prefix, 
    * signal_restart_name and signal_shutdown_name.
  @@ -730,7 +877,6 @@
   	"%s_restart", signal_name_prefix);    
   }
   
  -
   /*
    * worker_main() is main loop for the child process. The loop in
    * this function becomes the controlling thread for the actually working
  @@ -739,24 +885,15 @@
    *  exit_event, start_mutex, ap_threads_per_child, server_conf,
    *  h_errno defined to WSAGetLastError in winsock2.h,
    */
  -static void worker_main(void)
  +static void worker_main()
   {
       int nthreads = ap_threads_per_child;
  -    fd_set main_fds;
  -    int srv;
  -    int clen;
  -    int csd;
  -    int sd = -1;
  -    struct sockaddr_in sa_client;
  -    int total_jobs = 0;
  +
  +
       thread **child_handles;
       int rv;
       time_t end_time;
       int i;
  -    struct timeval tv;
  -    int wait_time = 1;
  -    HANDLE hObjects[2];
  -    int count_select_errors = 0;
       pool *pchild;
   
       pchild = ap_make_sub_pool(pconf);
  @@ -774,9 +911,7 @@
        * in case we (this child) is told to die before we get a chance to
        * serve any requests.
        */
  -    hObjects[0] = (HANDLE)start_mutex;
  -    hObjects[1] = (HANDLE)exit_event;
  -    rv = WaitForMultipleObjects(2, hObjects, FALSE, INFINITE);
  +    rv = WaitForSingleObject(start_mutex,0);
       if (rv == WAIT_FAILED) {
   	ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_WIN32ERROR, server_conf,
                        "Waiting for start_mutex or exit_event -- process will exit");
  @@ -786,15 +921,8 @@
   	cleanup_scoreboard();
   #endif
   	exit(0);
  -    }
  -    if (rv == WAIT_OBJECT_0 + 1) {
  -	/* exit event signalled - exit now */
  -	ap_destroy_pool(pchild);
  -#if 0
  -	cleanup_scoreboard();
  -#endif
  -	exit(0);
       }
  +
       /* start_mutex obtained, continue into the select() loop */
       if (one_process) {
           setup_listeners(pconf, server_conf);
  @@ -818,91 +946,30 @@
       }
   
       allowed_globals.jobsemaphore = create_semaphore(0);
  -    allowed_globals.jobmutex = ap_create_mutex(NULL);
  +    InitializeCriticalSection(&allowed_globals.jobmutex);
   
  -    /* spawn off the threads */
  +    /* spawn off the worker threads */
       child_handles = (thread *) alloca(nthreads * sizeof(int));
       for (i = 0; i < nthreads; i++) {
   	child_handles[i] = create_thread((void (*)(void *)) child_main, (void *) i);
       }
   
  -    while (1) {
  -        if (ap_max_requests_per_child && (total_jobs > ap_max_requests_per_child)) {
  -            break;
  -	}
  -        /* Always check for the exit event being signaled.
  -         */
  -        rv = WaitForSingleObject(exit_event, 0);
  -        ap_assert((rv == WAIT_TIMEOUT) || (rv == WAIT_OBJECT_0));
  -        if (rv == WAIT_OBJECT_0) {
  -            break;
  -        }
  -
  -	tv.tv_sec = wait_time;
  -	tv.tv_usec = 0;
  -
  -	memcpy(&main_fds, &listenfds, sizeof(fd_set));
  -	srv = ap_select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv);
  -	if (srv == SOCKET_ERROR) {
  -	    /* Error occurred - if EINTR, loop around with problem */
  -	    if (WSAGetLastError() != WSAEINTR) {
  -		/* 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|APLOG_WIN32ERROR, server_conf, "select: (listen)");
  -		count_select_errors++;
  -		if (count_select_errors > MAX_SELECT_ERRORS) {
  -		    ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf,
  -                                 "Too many errors in select loop. Child process exiting.");
  -		    break;
  -		}
  -	    }
  -	    continue;
  -	}
  -	count_select_errors = 0;    /* reset count of errors */
  -	if (srv == 0) {
  -            continue;
  -	} else {
  -	    ap_listen_rec *lr;
  +#ifdef QUEUED_ACCEPT
  +    /* spawn off accept thread */
  +    create_thread((void (*)(void *)) accept_and_queue_connections, (void *) NULL);
  +#endif
   
  -	    lr = find_ready_listener(&main_fds);
  -	    if (lr != NULL) {
  -		sd = lr->fd;
  -	    }
  -	}
  -	do {
  -	    clen = sizeof(sa_client);
  -	    csd = accept(sd, (struct sockaddr *) &sa_client, &clen);
  -	    if (csd == INVALID_SOCKET) {
  -		csd = -1;
  -	    }
  -	} while (csd < 0 && h_errno == WSAEINTR);
  +    rv = WaitForSingleObject(exit_event, INFINITE);
  +    printf("exit event signalled \n");
  +    workers_may_exit = 1;      
   
  -	if (csd < 0) {
  -            if (h_errno != WSAECONNABORTED) {
  -		ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf,
  -			    "accept: (client socket)");
  -            }
  -	}
  -	else {
  -	    add_job(csd);
  -	    total_jobs++;
  -	}
  -    }
  -      
       /* Get ready to shutdown and exit */
  -    allowed_globals.exit_now = 1;
       ap_release_mutex(start_mutex);
  -
  -#ifdef UNGRACEFUL_RESTART
  -    SetEvent(allowed_globals.thread_exit_event);
  -#else
  +#ifdef QUEUED_ACCEPT
       for (i = 0; i < nthreads; i++) {
   	add_job(-1);
       }
   #endif
  -
       /* Wait for all your children */
       end_time = time(NULL) + 180;
       while (nthreads) {
  @@ -921,20 +988,20 @@
   	kill_thread(child_handles[i]);
   	free_thread(child_handles[i]);
       }
  -#ifdef UNGRACEFUL_RESTART
  -    ap_assert(CloseHandle(allowed_globals.thread_exit_event));
  -#endif
  +
       destroy_semaphore(allowed_globals.jobsemaphore);
  -    ap_destroy_mutex(allowed_globals.jobmutex);
  +    DeleteCriticalSection(&allowed_globals.jobmutex);
   
       ap_destroy_pool(pchild);
   
   #if 0
       cleanup_scoreboard();
   #endif
  -
   }
  -
  +static HANDLE create_exit_event(const char* event_name)
  +{
  +    return CreateEvent(NULL, TRUE, FALSE, event_name);
  +}
   /*
    * Spawn a child Apache process. The child process has the command line arguments from
    * argc and argv[], plus a -Z argument giving the name of an event. The child should
  @@ -1062,8 +1129,8 @@
           SetEnvironmentVariable("AP_PARENT_PID",NULL);
   
           /* Create the exit_event, apCHILD_PID */
  -        kill_event = CreateEvent(NULL, TRUE, FALSE, 
  -                                 ap_psprintf(pconf,"apC%d", pi.dwProcessId)); // exit_event_name...
  +        kill_event = create_exit_event(ap_psprintf(pconf,"apC%d", pi.dwProcessId));
  +//CreateEvent(NULL, TRUE, TRUE, ap_psprintf(pconf,"apC%d", pi.dwProcessId)); // exit_event_name...
           if (!kill_event) {
               ap_log_error(APLOG_MARK, APLOG_WIN32ERROR | APLOG_CRIT, server_conf,
                            "Parent: Could not create exit event for child process");
  @@ -1293,15 +1360,15 @@
       char *pid;
       one_process=1;//!!getenv("ONE_PROCESS");
   
  -    /* Track parent/child pids... */
  +    /* AP_PARENT_PID is only valid in the child */
       pid = getenv("AP_PARENT_PID");
       if (pid) {
  -        /* AP_PARENT_PID is only valid in the child */
  +        /* This is the child */
           parent_pid = atoi(pid);
           my_pid = getpid();
       }
       else {
  -        /* This is the parent... */
  +        /* This is the parent */
           parent_pid = my_pid = getpid();
           ap_log_pid(pconf, mpm_pid_fname);
       }
  @@ -1340,7 +1407,8 @@
           setup_signal_names(ap_psprintf(pconf,"ap%d", parent_pid));
           if (one_process) {
               start_mutex = ap_create_mutex(signal_name_prefix);        
  -            exit_event = CreateEvent(NULL, TRUE, FALSE, exit_event_name);
  +            exit_event = create_exit_event(exit_event_name);
  +
           }
           else {
               start_mutex = ap_open_mutex(signal_name_prefix);
  @@ -1458,10 +1526,10 @@
       ap_threads_per_child = atoi(arg);
       if (ap_threads_per_child > HARD_THREAD_LIMIT) {
           fprintf(stderr, "WARNING: ThreadsPerChild of %d exceeds compile time"
  -                "limit of %d threads,\n", ap_threads_per_child,
  +                " limit of %d threads,\n", ap_threads_per_child,
                   HARD_THREAD_LIMIT);
           fprintf(stderr, " lowering ThreadsPerChild to %d. To increase, please"
  -                "see the\n", HARD_THREAD_LIMIT);
  +                " see the\n", HARD_THREAD_LIMIT);
           fprintf(stderr, " HARD_THREAD_LIMIT define in src/include/httpd.h.\n");
       }
       else if (ap_threads_per_child < 1) {
  @@ -1532,7 +1600,7 @@
   */
   
   struct ap_thread_mutex {
  -    HANDLE _mutex;
  +    CRITICAL_SECTION _mutex;
   };
   
   
  @@ -1541,26 +1609,25 @@
       ap_thread_mutex *mtx;
   
       mtx = malloc(sizeof(ap_thread_mutex));
  -    mtx->_mutex = CreateMutex(NULL, FALSE, NULL);
  +    InitializeCriticalSection(&(mtx->_mutex));
       return mtx;
   }
   
   
   API_EXPORT(void) ap_thread_mutex_lock(ap_thread_mutex *mtx)
   {
  -    int rv;
  -    rv = WaitForSingleObject(mtx->_mutex, INFINITE);
  +    EnterCriticalSection(&(mtx->_mutex));
   }
   
   
   API_EXPORT(void) ap_thread_mutex_unlock(ap_thread_mutex *mtx)
   {
  -    ReleaseMutex(mtx->_mutex);
  +    LeaveCriticalSection(&(mtx->_mutex));
   }
   
   API_EXPORT(void) ap_thread_mutex_destroy(ap_thread_mutex *mtx)
   {
  -    CloseHandle(mtx->_mutex);
  +    DeleteCriticalSection(&(mtx->_mutex));
       free(mtx);
   }
   
  
  
  

sendfile

Posted by Dean Gaudet <dg...@arctic.org>.

On 20 Aug 1999 stoddard@hyperreal.org wrote:

>   - TransmitFile (I have prototype code implemented). Should we add a send_file API
>   to the I/O control layer? Maybe Apache should always try to send_file. Platforms
>   that don't support send_file could in turn, invoke the appropriate buff code
>   which would then invoke socket iol write/writev.

yup, i'm not quite sure what the right way is.  but someone should jump in
and try it. 

Dean