From: Bradley Nicholes Date: Fri, 11 Jan 2002 23:19:45 +0000 (+0000) Subject: Combination of blocking and nonblocking accept loop X-Git-Tag: 2.0.31~211 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=057bd297b4701518fa265452db0be3eed5534fc5;p=apache Combination of blocking and nonblocking accept loop git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@92832 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/server/mpm/netware/mpm_netware.c b/server/mpm/netware/mpm_netware.c index 372549ccb4..9df5acc7ad 100644 --- a/server/mpm/netware/mpm_netware.c +++ b/server/mpm/netware/mpm_netware.c @@ -174,6 +174,7 @@ static apr_pool_t *pmain; /* Pool for httpd child stuff */ static pid_t ap_my_pid; /* it seems silly to call getpid all the time */ static int die_now = 0; + static apr_thread_mutex_t *accept_mutex = NULL; /* Keep track of the number of worker threads currently active */ @@ -323,9 +324,14 @@ int ap_graceful_stop_signalled(void) return 0; } -static int just_go = 0; +static int dont_block = 0; +static int missed_accept = 0; +static apr_socket_t *sd = NULL; + +static int skipped_selects = 0; static int would_block = 0; -static void worker_main(void *arg) +/*static */ +void worker_main(void *arg) { ap_listen_rec *lr; ap_listen_rec *last_lr = NULL; @@ -337,10 +343,15 @@ static void worker_main(void *arg) int my_worker_num = worker_num_arg; apr_socket_t *csd = NULL; - apr_socket_t *sd = NULL; int requests_this_child = 0; - DWORD ret; + int sockdes; + ap_listen_rec *first_lr; + int srv; + struct timeval tv; + + tv.tv_sec = 1; + tv.tv_usec = 0; apr_pool_create(&ptrans, pmain); @@ -370,7 +381,7 @@ static void worker_main(void *arg) * Wait for an acceptable connection to arrive. */ - /* Lock around "accept", if necessary */ + /* Only allow a single thread at a time into the "accept" loop */ apr_thread_mutex_lock(accept_mutex); for (;;) { @@ -380,31 +391,80 @@ static void worker_main(void *arg) clean_child_exit(0, my_worker_num); } - /* we remember the last_lr we searched last time around so that - we don't end up starving any particular listening socket */ - if (last_lr == NULL) { - lr = ap_listeners; + /* If we just satisfied a request on listen port x, assume that more + is coming. Don't bother using select() to determine if there is + more, just try to accept() the next request. */ + if (dont_block && (missed_accept<10)) { + skipped_selects++; } else { - lr = last_lr->next; - if (!lr) + /* If we determine that there are no more requests on the listen + queue then set the socket back to blocking and move back into + more of an idle listen state. */ + if (dont_block) { + apr_setsocketopt(sd, APR_SO_NONBLOCK, 0); + dont_block = 0; + } + + /* Check the listen queue on all sockets for requests */ + memcpy(&main_fds, &listenfds, sizeof(fd_set)); + srv = select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv); + + if (srv <= 0) + continue; + + /* remember the last_lr we searched last time around so that + we don't end up starving any particular listening socket */ + if (last_lr == NULL) { lr = ap_listeners; + } + else { + lr = last_lr->next; + if (!lr) + lr = ap_listeners; + } + first_lr = lr; + do { + apr_os_sock_get(&sockdes, lr->sd); + if (FD_ISSET(sockdes, &main_fds)) + goto got_listener; + lr = lr->next; + if (!lr) + lr = ap_listeners; + } while (lr != first_lr); + /* FIXME: if we get here, something bad has happened, and we're + probably gonna spin forever. + */ + continue; +got_listener: + last_lr = lr; + sd = lr->sd; + + /* Just got a request on one of the listen sockets so assume that + there are more coming. Set the socket to non-blocking and + move into a fast pull mode. */ + apr_setsocketopt(sd, APR_SO_NONBLOCK, 1); + dont_block = 1; + missed_accept = 0; } - last_lr = lr; - sd = lr->sd; - + stat = apr_accept(&csd, sd, ptrans); + + /* If we got a new socket, set it to non-blocking mode and process + it. Otherwise handle the error. */ if (stat == APR_SUCCESS) { apr_setsocketopt(csd, APR_SO_NONBLOCK, 0); break; /* We have a socket ready for reading */ } else { - just_go = 0; - ret = APR_TO_NETOS_ERROR(stat); - - switch (ret) { + switch (APR_TO_NETOS_ERROR(stat)) { + /* if the error is a wouldblock then maybe we were too + quick try to pull the next request from the listen + queue. Try a few more times then return to our idle + listen state. */ case WSAEWOULDBLOCK: + missed_accept++; would_block++; apr_thread_yield(); continue; @@ -443,6 +503,7 @@ static void worker_main(void *arg) } } + /* Unlock the mutext so that the next thread can start listening for requests. */ apr_thread_mutex_unlock(accept_mutex); ap_create_sb_handle(&sbh, ptrans, 0, my_worker_num); @@ -656,9 +717,11 @@ static void display_settings () int status_array[SERVER_NUM_STATUS]; int i, status, total=0; int reqs = request_count; + int skips = skipped_selects; int wblock = would_block; request_count = 0; + skipped_selects = 0; would_block = 0; ClearScreen (getscreenhandle()); @@ -718,6 +781,7 @@ static void display_settings () } printf ("Total Running:\t%d\tout of: \t%d\n", total, ap_threads_limit); printf ("Requests per interval:\t%d\n", reqs); + printf ("Skipped selects:\t%d\n", skips); printf ("Would blocks:\t%d\n", wblock); } @@ -765,7 +829,19 @@ static int setup_listeners(server_rec *s) if (sockdes > listenmaxfd) { listenmaxfd = sockdes; } +#ifdef NONBLOCK1 apr_setsocketopt(lr->sd, APR_SO_NONBLOCK, 1); +#endif + } + return 0; +} + +static int shutdown_listeners() +{ + ap_listen_rec *lr; + + for (lr = ap_listeners; lr; lr = lr->next) { + apr_socket_close(lr->sd); } return 0; } @@ -826,6 +902,10 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL); } + + /* Shutdown the listen sockets so that we don't get stuck in a blocking call. */ + shutdown_listeners(); + if (shutdown_pending) { /* Got an unload from the console */ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, "caught SIGTERM, shutting down");