Index: src/microhttpd/internal.h =================================================================== --- src/microhttpd/internal.h (revision 30839) +++ src/microhttpd/internal.h (working copy) @@ -116,8 +116,12 @@ /** * Is this connection currently in the 'epoll' set? */ - MHD_EPOLL_STATE_IN_EPOLL_SET = 8 + MHD_EPOLL_STATE_IN_EPOLL_SET = 8, + /** + * Is this connection currently suspended? + */ + MHD_EPOLL_STATE_SUSPENDED = 16 }; @@ -452,7 +456,7 @@ * Handshake messages will be processed in this state & while * in the 'MHD_TLS_HELLO_REQUEST' state */ - MHD_TLS_CONNECTION_INIT = MHD_CONNECTION_CLOSED + 1 + MHD_TLS_CONNECTION_INIT = MHD_CONNECTION_IN_CLEANUP + 1 }; Index: src/microhttpd/connection.c =================================================================== --- src/microhttpd/connection.c (revision 30839) +++ src/microhttpd/connection.c (working copy) @@ -2474,6 +2474,7 @@ { case MHD_EVENT_LOOP_INFO_READ: if ( (0 != (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) && + (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) && (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) ) { EDLL_insert (daemon->eready_head, @@ -2485,6 +2486,7 @@ case MHD_EVENT_LOOP_INFO_WRITE: if ( (connection->read_buffer_size > connection->read_buffer_offset) && (0 != (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) && + (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) && (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) ) { EDLL_insert (daemon->eready_head, @@ -2493,6 +2495,7 @@ connection->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL; } if ( (0 != (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY)) && + (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) && (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) ) { EDLL_insert (daemon->eready_head, @@ -2504,7 +2507,8 @@ case MHD_EVENT_LOOP_INFO_BLOCK: /* we should look at this connection again in the next iteration of the event loop, as we're waiting on the application */ - if (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) + if ( (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL) && + (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED))) ) { EDLL_insert (daemon->eready_head, daemon->eready_tail, @@ -2539,6 +2543,7 @@ if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) && (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) && + (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) && ( (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY)) || ( (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) && ( (MHD_EVENT_LOOP_INFO_READ == connection->event_loop_info) || Index: src/microhttpd/daemon.c =================================================================== --- src/microhttpd/daemon.c (revision 30839) +++ src/microhttpd/daemon.c (working copy) @@ -1398,6 +1398,9 @@ daemon = connection->daemon; if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) MHD_PANIC ("Cannot suspend connections in THREAD_PER_CONNECTION mode!\n"); + if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && + (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) + MHD_PANIC ("Failed to acquire cleanup mutex\n"); DLL_remove (daemon->connections_head, daemon->connections_tail, connection); @@ -1410,22 +1413,29 @@ daemon->manual_timeout_tail, connection); #if EPOLL_SUPPORT - if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) - { - EDLL_remove (daemon->eready_head, - daemon->eready_tail, - connection); - } - if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) - { - if (0 != epoll_ctl (daemon->epoll_fd, - EPOLL_CTL_DEL, - connection->socket_fd, - NULL)) - MHD_PANIC ("Failed to remove FD from epoll set\n"); - connection->epoll_state &= ~MHD_EPOLL_STATE_IN_EPOLL_SET; - } + if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) + { + if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) + { + EDLL_remove (daemon->eready_head, + daemon->eready_tail, + connection); + } + if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) + { + if (0 != epoll_ctl (daemon->epoll_fd, + EPOLL_CTL_DEL, + connection->socket_fd, + NULL)) + MHD_PANIC ("Failed to remove FD from epoll set\n"); + connection->epoll_state &= ~MHD_EPOLL_STATE_IN_EPOLL_SET; + } + connection->epoll_state |= MHD_EPOLL_STATE_SUSPENDED; + } #endif + if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && + (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) ) + MHD_PANIC ("Failed to release cleanup mutex\n"); } @@ -1460,33 +1470,30 @@ daemon->manual_timeout_tail, connection); #if EPOLL_SUPPORT - if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) - { - EDLL_insert (daemon->eready_head, - daemon->eready_tail, - connection); - } - else - { - struct epoll_event event; + if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) + { + if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) + { + EDLL_insert (daemon->eready_head, + daemon->eready_tail, + connection); + } + else + { + struct epoll_event event; - event.events = EPOLLIN | EPOLLOUT | EPOLLET; - event.data.ptr = connection; - if (0 != epoll_ctl (daemon->epoll_fd, - EPOLL_CTL_ADD, - connection->socket_fd, - &event)) - { -#if HAVE_MESSAGES - MHD_DLOG (daemon, - "Call to epoll_ctl failed: %s\n", - STRERROR (errno)); -#endif - /* and now, good luck with this... */ - } - else - connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET; + event.events = EPOLLIN | EPOLLOUT | EPOLLET; + event.data.ptr = connection; + if (0 != epoll_ctl (daemon->epoll_fd, + EPOLL_CTL_ADD, + connection->socket_fd, + &event)) + MHD_PANIC ("Failed to add FD to epoll set\n"); + else + connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET; } + connection->epoll_state &= ~MHD_EPOLL_STATE_SUSPENDED; + } #endif if ( (-1 != daemon->wpipe[1]) && (1 != WRITE (daemon->wpipe[1], "n", 1)) ) @@ -3581,6 +3588,38 @@ d->worker_pool_size = 0; d->worker_pool = NULL; + if ( (use_pipe) && +#ifdef WINDOWS + (0 != SOCKETPAIR (AF_INET, SOCK_STREAM, IPPROTO_TCP, d->wpipe)) +#else + (0 != PIPE (d->wpipe)) +#endif + ) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, + "Failed to create worker control pipe: %s\n", + STRERROR (errno)); +#endif + goto thread_failed; + } +#ifndef WINDOWS + if ( (0 == (flags & MHD_USE_POLL)) && + (1 == use_pipe) && + (d->wpipe[0] >= FD_SETSIZE) ) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, + "file descriptor for worker control pipe exceeds maximum value\n"); +#endif + if (0 != CLOSE (d->wpipe[0])) + MHD_PANIC ("close failed\n"); + if (0 != CLOSE (d->wpipe[1])) + MHD_PANIC ("close failed\n"); + goto thread_failed; + } +#endif + /* Divide available connections evenly amongst the threads. * Thread indexes in [0, leftover_conns) each get one of the * leftover connections. */ @@ -3678,6 +3717,9 @@ MHD_connection_close (pos, MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); + if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && + (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) ) + MHD_PANIC ("Failed to acquire cleanup mutex\n"); if (pos->connection_timeout == pos->daemon->connection_timeout) XDLL_remove (daemon->normal_timeout_head, daemon->normal_timeout_tail, @@ -3690,9 +3732,13 @@ daemon->connections_tail, pos); pos->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; + pos->state = MHD_CONNECTION_IN_CLEANUP; DLL_insert (daemon->cleanup_head, daemon->cleanup_tail, pos); + if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && + (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) ) + MHD_PANIC ("Failed to release cleanup mutex\n"); } @@ -3794,10 +3840,14 @@ { daemon->worker_pool[i].shutdown = MHD_YES; daemon->worker_pool[i].socket_fd = -1; + if (-1 != daemon->wpipe[1]) + { + if (1 != WRITE (daemon->worker_pool[i].wpipe[1], "e", 1)) + MHD_PANIC ("failed to signal shutdownn via pipe"); + } #if EPOLL_SUPPORT if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) && - (-1 != daemon->worker_pool[i].epoll_fd) && - (-1 == fd) ) + (-1 != daemon->worker_pool[i].epoll_fd) ) epoll_shutdown (&daemon->worker_pool[i]); #endif } @@ -3839,6 +3889,13 @@ MHD_PANIC ("Failed to join a thread\n"); close_all_connections (&daemon->worker_pool[i]); pthread_mutex_destroy (&daemon->worker_pool[i].cleanup_connection_mutex); + if (-1 != daemon->wpipe[1]) + { + if (0 != CLOSE (daemon->worker_pool[i].wpipe[0])) + MHD_PANIC ("close failed\n"); + if (0 != CLOSE (daemon->worker_pool[i].wpipe[1])) + MHD_PANIC ("close failed\n"); + } #if EPOLL_SUPPORT if ( (-1 != daemon->worker_pool[i].epoll_fd) && (0 != CLOSE (daemon->worker_pool[i].epoll_fd)) )