diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-07-19 15:51:45 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-07-19 15:51:45 +0000 |
commit | 1237387390f4be97f861a5cb93eec2445fe1a565 (patch) | |
tree | c05e35d19805c6fd5aae0a85759288f44afe89e2 | |
parent | 14e4efd674ad0c3a40868057fb6754727a1e7b39 (diff) | |
download | libmicrohttpd-1237387390f4be97f861a5cb93eec2445fe1a565.tar.gz libmicrohttpd-1237387390f4be97f861a5cb93eec2445fe1a565.zip |
adding experimental turbo mode
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | src/examples/benchmark.c | 11 | ||||
-rw-r--r-- | src/include/microhttpd.h | 8 | ||||
-rw-r--r-- | src/microhttpd/connection.c | 139 | ||||
-rw-r--r-- | src/microhttpd/daemon.c | 148 | ||||
-rw-r--r-- | src/microhttpd/internal.h | 12 |
6 files changed, 221 insertions, 100 deletions
@@ -1,6 +1,7 @@ | |||
1 | Fri Jul 19 09:57:27 CEST 2013 | 1 | Fri Jul 19 09:57:27 CEST 2013 |
2 | Fix issue where connections were not cleaned up when | 2 | Fix issue where connections were not cleaned up when |
3 | 'MHD_run_from_select' was used. | 3 | 'MHD_run_from_select' was used. Adding experimental |
4 | TURBO mode. | ||
4 | Releasing libmicrohttpd 0.9.28. -CG | 5 | Releasing libmicrohttpd 0.9.28. -CG |
5 | 6 | ||
6 | Sun Jul 14 19:57:56 CEST 2013 | 7 | Sun Jul 14 19:57:56 CEST 2013 |
diff --git a/src/examples/benchmark.c b/src/examples/benchmark.c index 711d118a..48f294e0 100644 --- a/src/examples/benchmark.c +++ b/src/examples/benchmark.c | |||
@@ -122,10 +122,12 @@ main (int argc, char *const *argv) | |||
122 | response = MHD_create_response_from_buffer (strlen (PAGE), | 122 | response = MHD_create_response_from_buffer (strlen (PAGE), |
123 | (void *) PAGE, | 123 | (void *) PAGE, |
124 | MHD_RESPMEM_PERSISTENT); | 124 | MHD_RESPMEM_PERSISTENT); |
125 | 125 | (void) MHD_add_response_header (response, | |
126 | d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | 126 | MHD_HTTP_HEADER_CONNECTION, |
127 | #if ! EPOLL_SUPPORT | 127 | "close"); |
128 | | MHD_USE_EPOLL_LINUX_ONLY | 128 | d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_SUPPRESS_DATE_NO_CLOCK |
129 | #if EPOLL_SUPPORT | ||
130 | | MHD_USE_EPOLL_LINUX_ONLY | MHD_USE_EPOLL_TURBO | ||
129 | #endif | 131 | #endif |
130 | , | 132 | , |
131 | atoi (argv[1]), | 133 | atoi (argv[1]), |
@@ -134,6 +136,7 @@ main (int argc, char *const *argv) | |||
134 | MHD_OPTION_THREAD_POOL_SIZE, (unsigned int) NUMBER_OF_THREADS, | 136 | MHD_OPTION_THREAD_POOL_SIZE, (unsigned int) NUMBER_OF_THREADS, |
135 | MHD_OPTION_URI_LOG_CALLBACK, &uri_logger_cb, NULL, | 137 | MHD_OPTION_URI_LOG_CALLBACK, &uri_logger_cb, NULL, |
136 | MHD_OPTION_NOTIFY_COMPLETED, &completed_callback, NULL, | 138 | MHD_OPTION_NOTIFY_COMPLETED, &completed_callback, NULL, |
139 | MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 1000, | ||
137 | MHD_OPTION_END); | 140 | MHD_OPTION_END); |
138 | if (d == NULL) | 141 | if (d == NULL) |
139 | return 1; | 142 | return 1; |
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index f5397cc5..461c95cd 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h | |||
@@ -436,7 +436,13 @@ enum MHD_FLAG | |||
436 | /** | 436 | /** |
437 | * Use a single socket for IPv4 and IPv6. | 437 | * Use a single socket for IPv4 and IPv6. |
438 | */ | 438 | */ |
439 | MHD_USE_DUAL_STACK = MHD_USE_IPv6 | 2048 | 439 | MHD_USE_DUAL_STACK = MHD_USE_IPv6 | 2048, |
440 | |||
441 | /** | ||
442 | * Enable EPOLL turbo. Only useful with MHD_USE_EPOLL_LINUX_ONLY. | ||
443 | * Highly experimental, do not use in production yet. | ||
444 | */ | ||
445 | MHD_USE_EPOLL_TURBO = 4096 | ||
440 | 446 | ||
441 | }; | 447 | }; |
442 | 448 | ||
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index a16bf62d..de67f800 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of libmicrohttpd | 2 | This file is part of libmicrohttpd |
3 | (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff | 3 | (C) 2007-2013 Daniel Pittman and Christian Grothoff |
4 | 4 | ||
5 | This library is free software; you can redistribute it and/or | 5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public | 6 | modify it under the terms of the GNU Lesser General Public |
@@ -266,8 +266,9 @@ MHD_connection_close (struct MHD_Connection *connection, | |||
266 | struct MHD_Daemon *daemon; | 266 | struct MHD_Daemon *daemon; |
267 | 267 | ||
268 | daemon = connection->daemon; | 268 | daemon = connection->daemon; |
269 | SHUTDOWN (connection->socket_fd, | 269 | if (0 == (connection->daemon->options & MHD_USE_EPOLL_TURBO)) |
270 | (MHD_YES == connection->read_closed) ? SHUT_WR : SHUT_RDWR); | 270 | SHUTDOWN (connection->socket_fd, |
271 | (MHD_YES == connection->read_closed) ? SHUT_WR : SHUT_RDWR); | ||
271 | connection->state = MHD_CONNECTION_CLOSED; | 272 | connection->state = MHD_CONNECTION_CLOSED; |
272 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; | 273 | connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; |
273 | if ( (NULL != daemon->notify_completed) && | 274 | if ( (NULL != daemon->notify_completed) && |
@@ -1485,7 +1486,7 @@ do_read (struct MHD_Connection *connection) | |||
1485 | if (bytes_read < 0) | 1486 | if (bytes_read < 0) |
1486 | { | 1487 | { |
1487 | if ((EINTR == errno) || (EAGAIN == errno)) | 1488 | if ((EINTR == errno) || (EAGAIN == errno)) |
1488 | return MHD_NO; | 1489 | return MHD_NO; |
1489 | #if HAVE_MESSAGES | 1490 | #if HAVE_MESSAGES |
1490 | #if HTTPS_SUPPORT | 1491 | #if HTTPS_SUPPORT |
1491 | if (0 != (connection->daemon->options & MHD_USE_SSL)) | 1492 | if (0 != (connection->daemon->options & MHD_USE_SSL)) |
@@ -2032,6 +2033,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2032 | int rend; | 2033 | int rend; |
2033 | char *line; | 2034 | char *line; |
2034 | 2035 | ||
2036 | connection->in_idle = MHD_YES; | ||
2035 | while (1) | 2037 | while (1) |
2036 | { | 2038 | { |
2037 | #if DEBUG_STATES | 2039 | #if DEBUG_STATES |
@@ -2376,32 +2378,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2376 | } | 2378 | } |
2377 | continue; | 2379 | continue; |
2378 | case MHD_CONNECTION_CLOSED: | 2380 | case MHD_CONNECTION_CLOSED: |
2379 | if (connection->response != NULL) | 2381 | goto cleanup_connection; |
2380 | { | ||
2381 | MHD_destroy_response (connection->response); | ||
2382 | connection->response = NULL; | ||
2383 | } | ||
2384 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
2385 | (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) | ||
2386 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); | ||
2387 | if (connection->connection_timeout == daemon->connection_timeout) | ||
2388 | XDLL_remove (daemon->normal_timeout_head, | ||
2389 | daemon->normal_timeout_tail, | ||
2390 | connection); | ||
2391 | else | ||
2392 | XDLL_remove (daemon->manual_timeout_head, | ||
2393 | daemon->manual_timeout_tail, | ||
2394 | connection); | ||
2395 | DLL_remove (daemon->connections_head, | ||
2396 | daemon->connections_tail, | ||
2397 | connection); | ||
2398 | DLL_insert (daemon->cleanup_head, | ||
2399 | daemon->cleanup_tail, | ||
2400 | connection); | ||
2401 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
2402 | (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex)) ) | ||
2403 | MHD_PANIC ("Failed to release cleanup mutex\n"); | ||
2404 | return MHD_NO; | ||
2405 | default: | 2382 | default: |
2406 | EXTRA_CHECK (0); | 2383 | EXTRA_CHECK (0); |
2407 | break; | 2384 | break; |
@@ -2413,35 +2390,109 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2413 | (timeout <= (MHD_monotonic_time() - connection->last_activity)) ) | 2390 | (timeout <= (MHD_monotonic_time() - connection->last_activity)) ) |
2414 | { | 2391 | { |
2415 | MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); | 2392 | MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); |
2393 | connection->in_idle = MHD_NO; | ||
2416 | return MHD_YES; | 2394 | return MHD_YES; |
2417 | } | 2395 | } |
2418 | MHD_connection_update_event_loop_info (connection); | 2396 | MHD_connection_update_event_loop_info (connection); |
2419 | switch (connection->event_loop_info) | 2397 | switch (connection->event_loop_info) |
2420 | { | 2398 | { |
2421 | case MHD_EVENT_LOOP_INFO_READ: | 2399 | case MHD_EVENT_LOOP_INFO_READ: |
2422 | if (0 != (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) | 2400 | if ( (0 != (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) && |
2423 | EDLL_insert (daemon->eready_head, | 2401 | (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) ) |
2424 | daemon->eready_tail, | 2402 | { |
2425 | connection); | 2403 | EDLL_insert (daemon->eready_head, |
2404 | daemon->eready_tail, | ||
2405 | connection); | ||
2406 | connection->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL; | ||
2407 | } | ||
2426 | break; | 2408 | break; |
2427 | case MHD_EVENT_LOOP_INFO_WRITE: | 2409 | case MHD_EVENT_LOOP_INFO_WRITE: |
2428 | if (0 != (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY)) | 2410 | if ( (0 != (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY)) && |
2429 | EDLL_insert (daemon->eready_head, | 2411 | (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) ) |
2430 | daemon->eready_tail, | 2412 | { |
2431 | connection); | 2413 | EDLL_insert (daemon->eready_head, |
2414 | daemon->eready_tail, | ||
2415 | connection); | ||
2416 | connection->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL; | ||
2417 | } | ||
2432 | break; | 2418 | break; |
2433 | case MHD_EVENT_LOOP_INFO_BLOCK: | 2419 | case MHD_EVENT_LOOP_INFO_BLOCK: |
2434 | /* we should look at this connection again in the next iteration | 2420 | /* we should look at this connection again in the next iteration |
2435 | of the event loop, as we're waiting on the application */ | 2421 | of the event loop, as we're waiting on the application */ |
2436 | EDLL_insert (daemon->eready_head, | 2422 | if (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) |
2437 | daemon->eready_tail, | 2423 | { |
2438 | connection); | 2424 | EDLL_insert (daemon->eready_head, |
2425 | daemon->eready_tail, | ||
2426 | connection); | ||
2427 | connection->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL; | ||
2428 | } | ||
2439 | break; | 2429 | break; |
2440 | case MHD_EVENT_LOOP_INFO_CLEANUP: | 2430 | case MHD_EVENT_LOOP_INFO_CLEANUP: |
2441 | /* This connection is finished, nothing left to do */ | 2431 | /* This connection is finished, nothing left to do */ |
2442 | break; | 2432 | break; |
2443 | } | 2433 | } |
2434 | |||
2435 | #if EPOLL_SUPPORT | ||
2436 | if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) && | ||
2437 | (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) && | ||
2438 | ( (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY)) || | ||
2439 | ( (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) && | ||
2440 | (MHD_EVENT_LOOP_INFO_READ == connection->event_loop_info) && | ||
2441 | (MHD_NO == connection->read_closed) ) ) ) | ||
2442 | { | ||
2443 | /* add to epoll set */ | ||
2444 | struct epoll_event event; | ||
2445 | |||
2446 | event.events = EPOLLIN | EPOLLOUT | EPOLLET; | ||
2447 | event.data.ptr = connection; | ||
2448 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
2449 | EPOLL_CTL_ADD, | ||
2450 | connection->socket_fd, | ||
2451 | &event)) | ||
2452 | { | ||
2453 | #if HAVE_MESSAGES | ||
2454 | if (0 != (daemon->options & MHD_USE_DEBUG)) | ||
2455 | MHD_DLOG (daemon, | ||
2456 | "Call to epoll_ctl failed: %s\n", | ||
2457 | STRERROR (errno)); | ||
2458 | #endif | ||
2459 | connection->state = MHD_CONNECTION_CLOSED; | ||
2460 | goto cleanup_connection; | ||
2461 | } | ||
2462 | connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET; | ||
2463 | } | ||
2464 | #endif | ||
2465 | connection->in_idle = MHD_NO; | ||
2444 | return MHD_YES; | 2466 | return MHD_YES; |
2467 | |||
2468 | cleanup_connection: | ||
2469 | if (NULL != connection->response) | ||
2470 | { | ||
2471 | MHD_destroy_response (connection->response); | ||
2472 | connection->response = NULL; | ||
2473 | } | ||
2474 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
2475 | (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) | ||
2476 | MHD_PANIC ("Failed to acquire cleanup mutex\n"); | ||
2477 | if (connection->connection_timeout == daemon->connection_timeout) | ||
2478 | XDLL_remove (daemon->normal_timeout_head, | ||
2479 | daemon->normal_timeout_tail, | ||
2480 | connection); | ||
2481 | else | ||
2482 | XDLL_remove (daemon->manual_timeout_head, | ||
2483 | daemon->manual_timeout_tail, | ||
2484 | connection); | ||
2485 | DLL_remove (daemon->connections_head, | ||
2486 | daemon->connections_tail, | ||
2487 | connection); | ||
2488 | DLL_insert (daemon->cleanup_head, | ||
2489 | daemon->cleanup_tail, | ||
2490 | connection); | ||
2491 | if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && | ||
2492 | (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex)) ) | ||
2493 | MHD_PANIC ("Failed to release cleanup mutex\n"); | ||
2494 | connection->in_idle = MHD_NO; | ||
2495 | return MHD_NO; | ||
2445 | } | 2496 | } |
2446 | 2497 | ||
2447 | 2498 | ||
@@ -2589,11 +2640,13 @@ MHD_queue_response (struct MHD_Connection *connection, | |||
2589 | /* response was queued "early", | 2640 | /* response was queued "early", |
2590 | refuse to read body / footers or further | 2641 | refuse to read body / footers or further |
2591 | requests! */ | 2642 | requests! */ |
2592 | (void) SHUTDOWN (connection->socket_fd, SHUT_RD); | 2643 | if (0 == (connection->daemon->options & MHD_USE_EPOLL_TURBO)) |
2644 | (void) SHUTDOWN (connection->socket_fd, SHUT_RD); | ||
2593 | connection->read_closed = MHD_YES; | 2645 | connection->read_closed = MHD_YES; |
2594 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; | 2646 | connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; |
2595 | } | 2647 | } |
2596 | (void) MHD_connection_handle_idle (connection); | 2648 | if (MHD_NO == connection->in_idle) |
2649 | (void) MHD_connection_handle_idle (connection); | ||
2597 | return MHD_YES; | 2650 | return MHD_YES; |
2598 | } | 2651 | } |
2599 | 2652 | ||
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 1625078d..d111d9cd 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -809,7 +809,7 @@ recv_param_adapter (struct MHD_Connection *connection, | |||
809 | } | 809 | } |
810 | ret = RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); | 810 | ret = RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); |
811 | #if EPOLL_SUPPORT | 811 | #if EPOLL_SUPPORT |
812 | if (ret < i) | 812 | if (ret < (ssize_t) i) |
813 | { | 813 | { |
814 | /* partial read --- no longer read-ready */ | 814 | /* partial read --- no longer read-ready */ |
815 | connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; | 815 | connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY; |
@@ -884,7 +884,7 @@ send_param_adapter (struct MHD_Connection *connection, | |||
884 | #endif | 884 | #endif |
885 | ret = SEND (connection->socket_fd, other, i, MSG_NOSIGNAL); | 885 | ret = SEND (connection->socket_fd, other, i, MSG_NOSIGNAL); |
886 | #if EPOLL_SUPPORT | 886 | #if EPOLL_SUPPORT |
887 | if (ret < i) | 887 | if (ret < (ssize_t) i) |
888 | { | 888 | { |
889 | /* partial write --- no longer write-ready */ | 889 | /* partial write --- no longer write-ready */ |
890 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; | 890 | connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; |
@@ -1121,37 +1121,43 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
1121 | MHD_set_http_callbacks_ (connection); | 1121 | MHD_set_http_callbacks_ (connection); |
1122 | connection->recv_cls = &recv_param_adapter; | 1122 | connection->recv_cls = &recv_param_adapter; |
1123 | connection->send_cls = &send_param_adapter; | 1123 | connection->send_cls = &send_param_adapter; |
1124 | /* non-blocking sockets are required on most systems and for GNUtls; | 1124 | |
1125 | however, they somehow cause serious problems on CYGWIN (#1824) */ | 1125 | if (0 == (connection->daemon->options & MHD_USE_EPOLL_TURBO)) |
1126 | { | ||
1127 | /* non-blocking sockets are required on most systems and for GNUtls; | ||
1128 | however, they somehow cause serious problems on CYGWIN (#1824); | ||
1129 | in turbo mode, we assume that non-blocking was already set | ||
1130 | by 'accept4' or whoever calls 'MHD_add_connection' */ | ||
1126 | #ifdef CYGWIN | 1131 | #ifdef CYGWIN |
1127 | if (0 != (daemon->options & MHD_USE_SSL)) | 1132 | if (0 != (daemon->options & MHD_USE_SSL)) |
1128 | #endif | 1133 | #endif |
1129 | { | 1134 | { |
1130 | /* make socket non-blocking */ | 1135 | /* make socket non-blocking */ |
1131 | #ifndef MINGW | 1136 | #ifndef MINGW |
1132 | int flags = fcntl (connection->socket_fd, F_GETFL); | 1137 | int flags = fcntl (connection->socket_fd, F_GETFL); |
1133 | if ( (-1 == flags) || | 1138 | if ( (-1 == flags) || |
1134 | (0 != fcntl (connection->socket_fd, F_SETFL, flags | O_NONBLOCK)) ) | 1139 | (0 != fcntl (connection->socket_fd, F_SETFL, flags | O_NONBLOCK)) ) |
1135 | { | 1140 | { |
1136 | #if HAVE_MESSAGES | 1141 | #if HAVE_MESSAGES |
1137 | MHD_DLOG (daemon, | 1142 | MHD_DLOG (daemon, |
1138 | "Failed to make socket %d non-blocking: %s\n", | 1143 | "Failed to make socket %d non-blocking: %s\n", |
1139 | connection->socket_fd, | 1144 | connection->socket_fd, |
1140 | STRERROR (errno)); | 1145 | STRERROR (errno)); |
1141 | #endif | 1146 | #endif |
1142 | } | 1147 | } |
1143 | #else | 1148 | #else |
1144 | unsigned long flags = 1; | 1149 | unsigned long flags = 1; |
1145 | if (0 != ioctlsocket (connection->socket_fd, FIONBIO, &flags)) | 1150 | if (0 != ioctlsocket (connection->socket_fd, FIONBIO, &flags)) |
1146 | { | 1151 | { |
1147 | #if HAVE_MESSAGES | 1152 | #if HAVE_MESSAGES |
1148 | MHD_DLOG (daemon, | 1153 | MHD_DLOG (daemon, |
1149 | "Failed to make socket non-blocking: %s\n", | 1154 | "Failed to make socket non-blocking: %s\n", |
1150 | STRERROR (errno)); | 1155 | STRERROR (errno)); |
1151 | #endif | 1156 | #endif |
1152 | } | 1157 | } |
1153 | #endif | 1158 | #endif |
1154 | } | 1159 | } |
1160 | } | ||
1155 | 1161 | ||
1156 | #if HTTPS_SUPPORT | 1162 | #if HTTPS_SUPPORT |
1157 | if (0 != (daemon->options & MHD_USE_SSL)) | 1163 | if (0 != (daemon->options & MHD_USE_SSL)) |
@@ -1228,25 +1234,35 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
1228 | #if EPOLL_SUPPORT | 1234 | #if EPOLL_SUPPORT |
1229 | if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) | 1235 | if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) |
1230 | { | 1236 | { |
1231 | struct epoll_event event; | 1237 | if (0 == (daemon->options & MHD_USE_EPOLL_TURBO)) |
1232 | |||
1233 | event.events = EPOLLIN | EPOLLOUT | EPOLLET; | ||
1234 | event.data.ptr = connection; | ||
1235 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
1236 | EPOLL_CTL_ADD, | ||
1237 | client_socket, | ||
1238 | &event)) | ||
1239 | { | 1238 | { |
1239 | struct epoll_event event; | ||
1240 | |||
1241 | event.events = EPOLLIN | EPOLLOUT | EPOLLET; | ||
1242 | event.data.ptr = connection; | ||
1243 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
1244 | EPOLL_CTL_ADD, | ||
1245 | client_socket, | ||
1246 | &event)) | ||
1247 | { | ||
1240 | #if HAVE_MESSAGES | 1248 | #if HAVE_MESSAGES |
1241 | if (0 != (daemon->options & MHD_USE_DEBUG)) | 1249 | if (0 != (daemon->options & MHD_USE_DEBUG)) |
1242 | MHD_DLOG (daemon, | 1250 | MHD_DLOG (daemon, |
1243 | "Call to epoll_ctl failed: %s\n", | 1251 | "Call to epoll_ctl failed: %s\n", |
1244 | STRERROR (errno)); | 1252 | STRERROR (errno)); |
1245 | #endif | 1253 | #endif |
1246 | goto cleanup; | 1254 | goto cleanup; |
1255 | } | ||
1256 | connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET; | ||
1257 | } | ||
1258 | else | ||
1259 | { | ||
1260 | connection->epoll_state |= MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY | ||
1261 | | MHD_EPOLL_STATE_IN_EREADY_EDLL; | ||
1262 | EDLL_insert (daemon->eready_head, | ||
1263 | daemon->eready_tail, | ||
1264 | connection); | ||
1247 | } | 1265 | } |
1248 | daemon->listen_socket_in_epoll = MHD_YES; | ||
1249 | |||
1250 | } | 1266 | } |
1251 | #endif | 1267 | #endif |
1252 | daemon->max_connections--; | 1268 | daemon->max_connections--; |
@@ -1300,13 +1316,19 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
1300 | socklen_t addrlen; | 1316 | socklen_t addrlen; |
1301 | int s; | 1317 | int s; |
1302 | int fd; | 1318 | int fd; |
1319 | int nonblock; | ||
1303 | 1320 | ||
1304 | addrlen = sizeof (addrstorage); | 1321 | addrlen = sizeof (addrstorage); |
1305 | memset (addr, 0, sizeof (addrstorage)); | 1322 | memset (addr, 0, sizeof (addrstorage)); |
1306 | if (-1 == (fd = daemon->socket_fd)) | 1323 | if (-1 == (fd = daemon->socket_fd)) |
1307 | return MHD_NO; | 1324 | return MHD_NO; |
1325 | nonblock = SOCK_NONBLOCK; | ||
1326 | #ifdef CYGWIN | ||
1327 | if (0 == (daemon->options & MHD_USE_SSL)) | ||
1328 | nonblock = 0; | ||
1329 | #endif | ||
1308 | #if HAVE_ACCEPT4 | 1330 | #if HAVE_ACCEPT4 |
1309 | s = accept4 (fd, addr, &addrlen, SOCK_CLOEXEC); | 1331 | s = accept4 (fd, addr, &addrlen, SOCK_CLOEXEC | nonblock); |
1310 | #else | 1332 | #else |
1311 | s = ACCEPT (fd, addr, &addrlen); | 1333 | s = ACCEPT (fd, addr, &addrlen); |
1312 | #endif | 1334 | #endif |
@@ -1329,9 +1351,19 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
1329 | } | 1351 | } |
1330 | #if !HAVE_ACCEPT4 | 1352 | #if !HAVE_ACCEPT4 |
1331 | { | 1353 | { |
1332 | /* make socket non-inheritable */ | 1354 | /* make socket non-inheritable and non-blocking */ |
1333 | #ifdef WINDOWS | 1355 | #ifdef WINDOWS |
1334 | DWORD dwFlags; | 1356 | DWORD dwFlags; |
1357 | unsigned long flags = 1; | ||
1358 | |||
1359 | if (0 != ioctlsocket (s, FIONBIO, &flags)) | ||
1360 | { | ||
1361 | #if HAVE_MESSAGES | ||
1362 | MHD_DLOG (daemon, | ||
1363 | "Failed to make socket non-blocking: %s\n", | ||
1364 | STRERROR (errno)); | ||
1365 | #endif | ||
1366 | } | ||
1335 | if (!GetHandleInformation ((HANDLE) s, &dwFlags) || | 1367 | if (!GetHandleInformation ((HANDLE) s, &dwFlags) || |
1336 | ((dwFlags != dwFlags & ~HANDLE_FLAG_INHERIT) && | 1368 | ((dwFlags != dwFlags & ~HANDLE_FLAG_INHERIT) && |
1337 | !SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0))) | 1369 | !SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0))) |
@@ -1342,14 +1374,19 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
1342 | "Failed to make socket non-inheritable: %s\n", | 1374 | "Failed to make socket non-inheritable: %s\n", |
1343 | STRERROR (errno)); | 1375 | STRERROR (errno)); |
1344 | #endif | 1376 | #endif |
1345 | } | 1377 | } |
1346 | #else | 1378 | #else |
1347 | int flags; | 1379 | int flags; |
1348 | 1380 | ||
1381 | nonblock = O_NONBLOCK; | ||
1382 | #ifdef CYGWIN | ||
1383 | if (0 == (daemon->options & MHD_USE_SSL)) | ||
1384 | nonblock = 0; | ||
1385 | #endif | ||
1349 | flags = fcntl (s, F_GETFD); | 1386 | flags = fcntl (s, F_GETFD); |
1350 | if ( ( (-1 == flags) || | 1387 | if ( ( (-1 == flags) || |
1351 | ( (flags != (flags | FD_CLOEXEC)) && | 1388 | ( (flags != (flags | FD_CLOEXEC)) && |
1352 | (0 != fcntl (s, F_SETFD, flags | FD_CLOEXEC)) ) ) ) | 1389 | (0 != fcntl (s, F_SETFD, flags | nonblock | FD_CLOEXEC)) ) ) ) |
1353 | { | 1390 | { |
1354 | #if HAVE_MESSAGES | 1391 | #if HAVE_MESSAGES |
1355 | MHD_DLOG (daemon, | 1392 | MHD_DLOG (daemon, |
@@ -1358,7 +1395,10 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
1358 | #endif | 1395 | #endif |
1359 | } | 1396 | } |
1360 | #endif | 1397 | #endif |
1398 | /* make socket non-blocking */ | ||
1399 | |||
1361 | } | 1400 | } |
1401 | |||
1362 | #endif | 1402 | #endif |
1363 | #if HAVE_MESSAGES | 1403 | #if HAVE_MESSAGES |
1364 | #if DEBUG_CONNECT | 1404 | #if DEBUG_CONNECT |
@@ -1406,10 +1446,13 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon) | |||
1406 | if (pos->tls_session != NULL) | 1446 | if (pos->tls_session != NULL) |
1407 | gnutls_deinit (pos->tls_session); | 1447 | gnutls_deinit (pos->tls_session); |
1408 | #endif | 1448 | #endif |
1409 | MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len); | 1449 | MHD_ip_limit_del (daemon, |
1450 | (struct sockaddr *) pos->addr, | ||
1451 | pos->addr_len); | ||
1410 | #if EPOLL_SUPPORT | 1452 | #if EPOLL_SUPPORT |
1411 | if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) && | 1453 | if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) && |
1412 | (-1 != daemon->epoll_fd) ) | 1454 | (-1 != daemon->epoll_fd) && |
1455 | (0 != (pos->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) ) | ||
1413 | { | 1456 | { |
1414 | /* epoll documentation suggests that closing a FD | 1457 | /* epoll documentation suggests that closing a FD |
1415 | automatically removes it from the epoll set; however, | 1458 | automatically removes it from the epoll set; however, |
@@ -1422,6 +1465,7 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon) | |||
1422 | pos->socket_fd, | 1465 | pos->socket_fd, |
1423 | NULL)) | 1466 | NULL)) |
1424 | MHD_PANIC ("Failed to remove FD from epoll set\n"); | 1467 | MHD_PANIC ("Failed to remove FD from epoll set\n"); |
1468 | pos->epoll_state &= ~MHD_EPOLL_STATE_IN_EPOLL_SET; | ||
1425 | } | 1469 | } |
1426 | #endif | 1470 | #endif |
1427 | if (NULL != pos->response) | 1471 | if (NULL != pos->response) |
@@ -1949,10 +1993,10 @@ MHD_poll (struct MHD_Daemon *daemon, | |||
1949 | 1993 | ||
1950 | /** | 1994 | /** |
1951 | * Do 'epoll'-based processing (this function is allowed to | 1995 | * Do 'epoll'-based processing (this function is allowed to |
1952 | * block). | 1996 | * block if 'may_block' is set to MHD_YES). |
1953 | * | 1997 | * |
1954 | * @param daemon daemon to run poll loop for | 1998 | * @param daemon daemon to run poll loop for |
1955 | * @param may_block YES if blocking, NO if non-blocking | 1999 | * @param may_block MHD_YES if blocking, MHD_NO if non-blocking |
1956 | * @return MHD_NO on serious errors, MHD_YES on success | 2000 | * @return MHD_NO on serious errors, MHD_YES on success |
1957 | */ | 2001 | */ |
1958 | static int | 2002 | static int |
@@ -1966,7 +2010,8 @@ MHD_epoll (struct MHD_Daemon *daemon, | |||
1966 | int timeout_ms; | 2010 | int timeout_ms; |
1967 | MHD_UNSIGNED_LONG_LONG timeout_ll; | 2011 | MHD_UNSIGNED_LONG_LONG timeout_ll; |
1968 | int num_events; | 2012 | int num_events; |
1969 | unsigned int i; | 2013 | unsigned int i; |
2014 | unsigned int series_length; | ||
1970 | 2015 | ||
1971 | if (-1 == daemon->epoll_fd) | 2016 | if (-1 == daemon->epoll_fd) |
1972 | return MHD_NO; /* we're down! */ | 2017 | return MHD_NO; /* we're down! */ |
@@ -2082,8 +2127,11 @@ MHD_epoll (struct MHD_Daemon *daemon, | |||
2082 | { | 2127 | { |
2083 | /* run 'accept' until it fails or we are not allowed to take | 2128 | /* run 'accept' until it fails or we are not allowed to take |
2084 | on more connections */ | 2129 | on more connections */ |
2130 | series_length = 0; | ||
2085 | while ( (MHD_YES == MHD_accept_connection (daemon)) && | 2131 | while ( (MHD_YES == MHD_accept_connection (daemon)) && |
2086 | (0 != daemon->max_connections) ) ; | 2132 | (0 != daemon->max_connections) && |
2133 | (series_length < 128) ) | ||
2134 | series_length++; | ||
2087 | } | 2135 | } |
2088 | } | 2136 | } |
2089 | } | 2137 | } |
@@ -2094,7 +2142,7 @@ MHD_epoll (struct MHD_Daemon *daemon, | |||
2094 | EDLL_remove (daemon->eready_head, | 2142 | EDLL_remove (daemon->eready_head, |
2095 | daemon->eready_tail, | 2143 | daemon->eready_tail, |
2096 | pos); | 2144 | pos); |
2097 | pos->epoll_state -= MHD_EPOLL_STATE_IN_EREADY_EDLL; | 2145 | pos->epoll_state &= ~MHD_EPOLL_STATE_IN_EREADY_EDLL; |
2098 | if (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) | 2146 | if (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) |
2099 | pos->read_handler (pos); | 2147 | pos->read_handler (pos); |
2100 | if (MHD_EVENT_LOOP_INFO_WRITE == pos->event_loop_info) | 2148 | if (MHD_EVENT_LOOP_INFO_WRITE == pos->event_loop_info) |
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h index 61424ca5..5c5605a7 100644 --- a/src/microhttpd/internal.h +++ b/src/microhttpd/internal.h | |||
@@ -111,7 +111,12 @@ enum MHD_EpollState | |||
111 | /** | 111 | /** |
112 | * Is this connection currently in the 'eready' EDLL? | 112 | * Is this connection currently in the 'eready' EDLL? |
113 | */ | 113 | */ |
114 | MHD_EPOLL_STATE_IN_EREADY_EDLL = 4 | 114 | MHD_EPOLL_STATE_IN_EREADY_EDLL = 4, |
115 | |||
116 | /** | ||
117 | * Is this connection currently in the 'epoll' set? | ||
118 | */ | ||
119 | MHD_EPOLL_STATE_IN_EPOLL_SET = 8 | ||
115 | 120 | ||
116 | }; | 121 | }; |
117 | 122 | ||
@@ -719,6 +724,11 @@ struct MHD_Connection | |||
719 | */ | 724 | */ |
720 | int thread_joined; | 725 | int thread_joined; |
721 | 726 | ||
727 | /** | ||
728 | * Are we currently inside the "idle" handler (to avoid recursively invoking it). | ||
729 | */ | ||
730 | int in_idle; | ||
731 | |||
722 | #if EPOLL_SUPPORT | 732 | #if EPOLL_SUPPORT |
723 | /** | 733 | /** |
724 | * What is the state of this socket in relation to epoll? | 734 | * What is the state of this socket in relation to epoll? |