diff options
Diffstat (limited to 'src/lib/daemon_quiesce.c')
-rw-r--r-- | src/lib/daemon_quiesce.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/lib/daemon_quiesce.c b/src/lib/daemon_quiesce.c new file mode 100644 index 00000000..31104a7d --- /dev/null +++ b/src/lib/daemon_quiesce.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | |||
20 | /** | ||
21 | * @file lib/daemon.c | ||
22 | * @brief main functions to quiesce a daemon | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "internal.h" | ||
26 | |||
27 | |||
28 | /** | ||
29 | * Stop accepting connections from the listening socket. Allows | ||
30 | * clients to continue processing, but stops accepting new | ||
31 | * connections. Note that the caller is responsible for closing the | ||
32 | * returned socket; however, if MHD is run using threads (anything but | ||
33 | * external select mode), it must not be closed until AFTER | ||
34 | * #MHD_stop_daemon has been called (as it is theoretically possible | ||
35 | * that an existing thread is still using it). | ||
36 | * | ||
37 | * Note that some thread modes require the caller to have passed | ||
38 | * #MHD_USE_ITC when using this API. If this daemon is | ||
39 | * in one of those modes and this option was not given to | ||
40 | * #MHD_start_daemon, this function will return #MHD_INVALID_SOCKET. | ||
41 | * | ||
42 | * @param daemon daemon to stop accepting new connections for | ||
43 | * @return old listen socket on success, #MHD_INVALID_SOCKET if | ||
44 | * the daemon was already not listening anymore, or | ||
45 | * was never started | ||
46 | * @ingroup specialized | ||
47 | */ | ||
48 | MHD_socket | ||
49 | MHD_daemon_quiesce (struct MHD_Daemon *daemon) | ||
50 | { | ||
51 | MHD_socket listen_socket; | ||
52 | |||
53 | if (MHD_INVALID_SOCKET == (listen_socket = daemon->listen_socket)) | ||
54 | return MHD_INVALID_SOCKET; | ||
55 | if ( (daemon->disable_itc) && | ||
56 | (MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_model) ) | ||
57 | { | ||
58 | #ifdef HAVE_MESSAGES | ||
59 | MHD_DLOG (daemon, | ||
60 | MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC, | ||
61 | "Using MHD_quiesce_daemon in this mode requires ITC\n"); | ||
62 | #endif | ||
63 | return MHD_INVALID_SOCKET; | ||
64 | } | ||
65 | |||
66 | if (NULL != daemon->worker_pool) | ||
67 | { | ||
68 | unsigned int i; | ||
69 | |||
70 | for (i = 0; i < daemon->threading_model; i++) | ||
71 | { | ||
72 | struct MHD_Daemon *worker = &daemon->worker_pool[i]; | ||
73 | |||
74 | worker->was_quiesced = true; | ||
75 | #ifdef EPOLL_SUPPORT | ||
76 | if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) && | ||
77 | (-1 != worker->epoll_fd) && | ||
78 | (worker->listen_socket_in_epoll) ) | ||
79 | { | ||
80 | if (0 != epoll_ctl (worker->epoll_fd, | ||
81 | EPOLL_CTL_DEL, | ||
82 | listen_socket, | ||
83 | NULL)) | ||
84 | MHD_PANIC (_("Failed to remove listen FD from epoll set\n")); | ||
85 | worker->listen_socket_in_epoll = false; | ||
86 | } | ||
87 | else | ||
88 | #endif | ||
89 | if (MHD_ITC_IS_VALID_(worker->itc)) | ||
90 | { | ||
91 | if (! MHD_itc_activate_ (worker->itc, | ||
92 | "q")) | ||
93 | MHD_PANIC (_("Failed to signal quiesce via inter-thread communication channel")); | ||
94 | } | ||
95 | } | ||
96 | daemon->was_quiesced = true; | ||
97 | #ifdef EPOLL_SUPPORT | ||
98 | if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) && | ||
99 | (-1 != daemon->epoll_fd) && | ||
100 | (daemon->listen_socket_in_epoll) ) | ||
101 | { | ||
102 | if (0 != epoll_ctl (daemon->epoll_fd, | ||
103 | EPOLL_CTL_DEL, | ||
104 | listen_socket, | ||
105 | NULL)) | ||
106 | MHD_PANIC ("Failed to remove listen FD from epoll set\n"); | ||
107 | daemon->listen_socket_in_epoll = false; | ||
108 | } | ||
109 | #endif | ||
110 | } | ||
111 | |||
112 | if ( (MHD_ITC_IS_VALID_(daemon->itc)) && | ||
113 | (! MHD_itc_activate_ (daemon->itc, | ||
114 | "q")) ) | ||
115 | MHD_PANIC (_("Failed to signal quiesce via inter-thread communication channel")); | ||
116 | |||
117 | /* FIXME: we might want some bi-directional communication here | ||
118 | (in both the thread-pool and single-thread case!) | ||
119 | to be sure that the threads have stopped using the listen | ||
120 | socket, otherwise there is still the possibility of a race | ||
121 | between a thread accept()ing and the caller closing and | ||
122 | re-binding the socket. */ | ||
123 | |||
124 | return listen_socket; | ||
125 | } | ||
126 | |||
127 | |||