diff options
Diffstat (limited to 'src/lib/mhd_itc.h')
-rw-r--r-- | src/lib/mhd_itc.h | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/src/lib/mhd_itc.h b/src/lib/mhd_itc.h new file mode 100644 index 00000000..7bfccf30 --- /dev/null +++ b/src/lib/mhd_itc.h | |||
@@ -0,0 +1,361 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2016 Karlson2k (Evgeny Grin) | ||
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 | /** | ||
22 | * @file microhttpd/mhd_itc.h | ||
23 | * @brief Header for platform-independent inter-thread communication | ||
24 | * @author Karlson2k (Evgeny Grin) | ||
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | * Provides basic abstraction for inter-thread communication. | ||
28 | * Any functions can be implemented as macro on some platforms | ||
29 | * unless explicitly marked otherwise. | ||
30 | * Any function argument can be skipped in macro, so avoid | ||
31 | * variable modification in function parameters. | ||
32 | */ | ||
33 | #ifndef MHD_ITC_H | ||
34 | #define MHD_ITC_H 1 | ||
35 | #include "mhd_itc_types.h" | ||
36 | |||
37 | #include <fcntl.h> | ||
38 | |||
39 | #ifndef MHD_PANIC | ||
40 | # include <stdio.h> | ||
41 | # include <stdlib.h> | ||
42 | /* Simple implementation of MHD_PANIC, to be used outside lib */ | ||
43 | # define MHD_PANIC(msg) do { fprintf (stderr, \ | ||
44 | "Abnormal termination at %d line in file %s: %s\n", \ | ||
45 | (int)__LINE__, __FILE__, msg); abort();} while(0) | ||
46 | #endif /* ! MHD_PANIC */ | ||
47 | |||
48 | #if defined(_MHD_ITC_EVENTFD) | ||
49 | |||
50 | /* **************** Optimized GNU/Linux ITC implementation by eventfd ********** */ | ||
51 | #include <sys/eventfd.h> | ||
52 | #include <stdint.h> /* for uint64_t */ | ||
53 | #ifdef HAVE_UNISTD_H | ||
54 | #include <unistd.h> /* for read(), write(), errno */ | ||
55 | #endif /* HAVE_UNISTD_H */ | ||
56 | #ifdef HAVE_STRING_H | ||
57 | #include <string.h> /* for strerror() */ | ||
58 | #endif | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Initialise ITC by generating eventFD | ||
63 | * @param itc the itc to initialise | ||
64 | * @return non-zero if succeeded, zero otherwise | ||
65 | */ | ||
66 | #define MHD_itc_init_(itc) (-1 != ((itc).fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK))) | ||
67 | |||
68 | /** | ||
69 | * Get description string of last errno for itc operations. | ||
70 | */ | ||
71 | #define MHD_itc_last_strerror_() strerror(errno) | ||
72 | |||
73 | /** | ||
74 | * Internal static const helper for MHD_itc_activate_() | ||
75 | */ | ||
76 | static const uint64_t _MHD_itc_wr_data = 1; | ||
77 | |||
78 | /** | ||
79 | * Activate signal on @a itc | ||
80 | * @param itc the itc to use | ||
81 | * @param str ignored | ||
82 | * @return non-zero if succeeded, zero otherwise | ||
83 | */ | ||
84 | #define MHD_itc_activate_(itc, str) \ | ||
85 | ((write((itc).fd, (const void*)&_MHD_itc_wr_data, 8) > 0) || (EAGAIN == errno)) | ||
86 | |||
87 | /** | ||
88 | * Return read FD of @a itc which can be used for poll(), select() etc. | ||
89 | * @param itc the itc to get FD | ||
90 | * @return FD of read side | ||
91 | */ | ||
92 | #define MHD_itc_r_fd_(itc) ((itc).fd) | ||
93 | |||
94 | /** | ||
95 | * Return write FD of @a itc | ||
96 | * @param itc the itc to get FD | ||
97 | * @return FD of write side | ||
98 | */ | ||
99 | #define MHD_itc_w_fd_(itc) ((itc).fd) | ||
100 | |||
101 | /** | ||
102 | * Clear signaled state on @a itc | ||
103 | * @param itc the itc to clear | ||
104 | */ | ||
105 | #define MHD_itc_clear_(itc) \ | ||
106 | do { uint64_t __b; int __r; \ | ||
107 | __r = read((itc).fd, &__b, sizeof(__b)); \ | ||
108 | (void)__r; } while(0) | ||
109 | |||
110 | /** | ||
111 | * Destroy previously initialised ITC | ||
112 | * @param itc the itc to destroy | ||
113 | * @return non-zero if succeeded, zero otherwise | ||
114 | */ | ||
115 | #define MHD_itc_destroy_(itc) ((0 != close ((itc).fd)) || (EBADF != errno)) | ||
116 | |||
117 | /** | ||
118 | * Check whether ITC has valid value. | ||
119 | * | ||
120 | * Macro check whether @a itc value is valid (allowed), | ||
121 | * macro does not check whether @a itc was really initialised. | ||
122 | * @param itc the itc to check | ||
123 | * @return boolean true if @a itc has valid value, | ||
124 | * boolean false otherwise. | ||
125 | */ | ||
126 | #define MHD_ITC_IS_VALID_(itc) (-1 != ((itc).fd)) | ||
127 | |||
128 | /** | ||
129 | * Set @a itc to invalid value. | ||
130 | * @param itc the itc to set | ||
131 | */ | ||
132 | #define MHD_itc_set_invalid_(itc) ((itc).fd = -1) | ||
133 | |||
134 | |||
135 | #elif defined(_MHD_ITC_PIPE) | ||
136 | |||
137 | /* **************** Standard UNIX ITC implementation by pipe ********** */ | ||
138 | |||
139 | #if defined(HAVE_PIPE2_FUNC) && defined(HAVE_FCNTL_H) | ||
140 | # include <fcntl.h> /* for O_CLOEXEC, O_NONBLOCK */ | ||
141 | #endif /* HAVE_PIPE2_FUNC && HAVE_FCNTL_H */ | ||
142 | #ifdef HAVE_UNISTD_H | ||
143 | #include <unistd.h> /* for read(), write(), errno */ | ||
144 | #endif /* HAVE_UNISTD_H */ | ||
145 | #ifdef HAVE_STRING_H | ||
146 | #include <string.h> /* for strerror() */ | ||
147 | #endif | ||
148 | |||
149 | |||
150 | /** | ||
151 | * Initialise ITC by generating pipe | ||
152 | * @param itc the itc to initialise | ||
153 | * @return non-zero if succeeded, zero otherwise | ||
154 | */ | ||
155 | #ifdef HAVE_PIPE2_FUNC | ||
156 | # define MHD_itc_init_(itc) (!pipe2((itc).fd, O_CLOEXEC | O_NONBLOCK)) | ||
157 | #else /* ! HAVE_PIPE2_FUNC */ | ||
158 | # define MHD_itc_init_(itc) \ | ||
159 | ( (!pipe((itc).fd)) ? \ | ||
160 | (MHD_itc_nonblocking_((itc)) ? \ | ||
161 | (!0) : \ | ||
162 | (MHD_itc_destroy_((itc)), 0) ) \ | ||
163 | : (0) ) | ||
164 | #endif /* ! HAVE_PIPE2_FUNC */ | ||
165 | |||
166 | /** | ||
167 | * Get description string of last errno for itc operations. | ||
168 | */ | ||
169 | #define MHD_itc_last_strerror_() strerror(errno) | ||
170 | |||
171 | /** | ||
172 | * Activate signal on @a itc | ||
173 | * @param itc the itc to use | ||
174 | * @param str one-symbol string, useful only for strace debug | ||
175 | * @return non-zero if succeeded, zero otherwise | ||
176 | */ | ||
177 | #define MHD_itc_activate_(itc, str) \ | ||
178 | ((write((itc).fd[1], (const void*)(str), 1) > 0) || (EAGAIN == errno)) | ||
179 | |||
180 | |||
181 | /** | ||
182 | * Return read FD of @a itc which can be used for poll(), select() etc. | ||
183 | * @param itc the itc to get FD | ||
184 | * @return FD of read side | ||
185 | */ | ||
186 | #define MHD_itc_r_fd_(itc) ((itc).fd[0]) | ||
187 | |||
188 | /** | ||
189 | * Return write FD of @a itc | ||
190 | * @param itc the itc to get FD | ||
191 | * @return FD of write side | ||
192 | */ | ||
193 | #define MHD_itc_w_fd_(itc) ((itc).fd[1]) | ||
194 | |||
195 | /** | ||
196 | * Clear signaled state on @a itc | ||
197 | * @param itc the itc to clear | ||
198 | */ | ||
199 | #define MHD_itc_clear_(itc) do \ | ||
200 | { long __b; \ | ||
201 | while(0 < read((itc).fd[0], &__b, sizeof(__b))) \ | ||
202 | {} } while(0) | ||
203 | |||
204 | /** | ||
205 | * Destroy previously initialised ITC | ||
206 | * @param itc the itc to destroy | ||
207 | * @return non-zero if succeeded, zero otherwise | ||
208 | */ | ||
209 | #define MHD_itc_destroy_(itc) \ | ||
210 | ( (0 == close ((itc).fd[0])) ? \ | ||
211 | (0 == close ((itc).fd[1])) : \ | ||
212 | ((close ((itc).fd[1])), 0) ) | ||
213 | |||
214 | /** | ||
215 | * Check whether ITC has valid value. | ||
216 | * | ||
217 | * Macro check whether @a itc value is valid (allowed), | ||
218 | * macro does not check whether @a itc was really initialised. | ||
219 | * @param itc the itc to check | ||
220 | * @return boolean true if @a itc has valid value, | ||
221 | * boolean false otherwise. | ||
222 | */ | ||
223 | #define MHD_ITC_IS_VALID_(itc) (-1 != (itc).fd[0]) | ||
224 | |||
225 | /** | ||
226 | * Set @a itc to invalid value. | ||
227 | * @param itc the itc to set | ||
228 | */ | ||
229 | #define MHD_itc_set_invalid_(itc) ((itc).fd[0] = (itc).fd[1] = -1) | ||
230 | |||
231 | #ifndef HAVE_PIPE2_FUNC | ||
232 | /** | ||
233 | * Change itc FD options to be non-blocking. | ||
234 | * | ||
235 | * @param fd the FD to manipulate | ||
236 | * @return non-zero if succeeded, zero otherwise | ||
237 | */ | ||
238 | int | ||
239 | MHD_itc_nonblocking_ (struct MHD_itc_ itc); | ||
240 | #endif /* ! HAVE_PIPE2_FUNC */ | ||
241 | |||
242 | |||
243 | #elif defined(_MHD_ITC_SOCKETPAIR) | ||
244 | |||
245 | /* **************** ITC implementation by socket pair ********** */ | ||
246 | |||
247 | #include "mhd_sockets.h" | ||
248 | |||
249 | |||
250 | /** | ||
251 | * Initialise ITC by generating socketpair | ||
252 | * @param itc the itc to initialise | ||
253 | * @return non-zero if succeeded, zero otherwise | ||
254 | */ | ||
255 | #ifdef MHD_socket_pair_nblk_ | ||
256 | # define MHD_itc_init_(itc) MHD_socket_pair_nblk_((itc).sk) | ||
257 | #else /* ! MHD_socket_pair_nblk_ */ | ||
258 | # define MHD_itc_init_(itc) \ | ||
259 | (MHD_socket_pair_((itc).sk) ? \ | ||
260 | (MHD_itc_nonblocking_((itc)) ? \ | ||
261 | (!0) : \ | ||
262 | (MHD_itc_destroy_((itc)), 0) ) \ | ||
263 | : (0)) | ||
264 | #endif /* ! MHD_socket_pair_nblk_ */ | ||
265 | |||
266 | /** | ||
267 | * Get description string of last error for itc operations. | ||
268 | */ | ||
269 | #define MHD_itc_last_strerror_() MHD_socket_last_strerr_() | ||
270 | |||
271 | /** | ||
272 | * Activate signal on @a itc | ||
273 | * @param itc the itc to use | ||
274 | * @param str one-symbol string, useful only for strace debug | ||
275 | * @return non-zero if succeeded, zero otherwise | ||
276 | */ | ||
277 | #define MHD_itc_activate_(itc, str) \ | ||
278 | ((MHD_send_((itc).sk[1], (str), 1) > 0) || \ | ||
279 | (MHD_SCKT_ERR_IS_EAGAIN_(MHD_socket_get_error_()))) | ||
280 | |||
281 | /** | ||
282 | * Return read FD of @a itc which can be used for poll(), select() etc. | ||
283 | * @param itc the itc to get FD | ||
284 | * @return FD of read side | ||
285 | */ | ||
286 | #define MHD_itc_r_fd_(itc) ((itc).sk[0]) | ||
287 | |||
288 | /** | ||
289 | * Return write FD of @a itc | ||
290 | * @param itc the itc to get FD | ||
291 | * @return FD of write side | ||
292 | */ | ||
293 | #define MHD_itc_w_fd_(itc) ((itc).sk[1]) | ||
294 | |||
295 | /** | ||
296 | * Clear signaled state on @a itc | ||
297 | * @param itc the itc to clear | ||
298 | */ | ||
299 | #define MHD_itc_clear_(itc) do \ | ||
300 | { long __b; \ | ||
301 | while(0 < recv((itc).sk[0], \ | ||
302 | (char*)&__b, \ | ||
303 | sizeof(__b), 0)) \ | ||
304 | {} } while(0) | ||
305 | |||
306 | /** | ||
307 | * Destroy previously initialised ITC | ||
308 | * @param itc the itc to destroy | ||
309 | * @return non-zero if succeeded, zero otherwise | ||
310 | */ | ||
311 | #define MHD_itc_destroy_(itc) \ | ||
312 | ( MHD_socket_close_((itc).sk[0]) ? \ | ||
313 | MHD_socket_close_((itc).sk[1]) : \ | ||
314 | ((void)MHD_socket_close_((itc).sk[1]), 0) ) | ||
315 | |||
316 | |||
317 | /** | ||
318 | * Check whether ITC has valid value. | ||
319 | * | ||
320 | * Macro check whether @a itc value is valid (allowed), | ||
321 | * macro does not check whether @a itc was really initialised. | ||
322 | * @param itc the itc to check | ||
323 | * @return boolean true if @a itc has valid value, | ||
324 | * boolean false otherwise. | ||
325 | */ | ||
326 | #define MHD_ITC_IS_VALID_(itc) (MHD_INVALID_SOCKET != (itc).sk[0]) | ||
327 | |||
328 | /** | ||
329 | * Set @a itc to invalid value. | ||
330 | * @param itc the itc to set | ||
331 | */ | ||
332 | #define MHD_itc_set_invalid_(itc) ((itc).sk[0] = (itc).sk[1] = MHD_INVALID_SOCKET) | ||
333 | |||
334 | #ifndef MHD_socket_pair_nblk_ | ||
335 | # define MHD_itc_nonblocking_(pip) (MHD_socket_nonblocking_((pip).sk[0]) && MHD_socket_nonblocking_((pip).sk[1])) | ||
336 | #endif /* ! MHD_socket_pair_nblk_ */ | ||
337 | |||
338 | #endif /* _MHD_ITC_SOCKETPAIR */ | ||
339 | |||
340 | /** | ||
341 | * Destroy previously initialised ITC and abort execution | ||
342 | * if error is detected. | ||
343 | * @param itc the itc to destroy | ||
344 | */ | ||
345 | #define MHD_itc_destroy_chk_(itc) do { \ | ||
346 | if (!MHD_itc_destroy_(itc)) \ | ||
347 | MHD_PANIC(_("Failed to destroy ITC.\n")); \ | ||
348 | } while(0) | ||
349 | |||
350 | /** | ||
351 | * Check whether ITC has invalid value. | ||
352 | * | ||
353 | * Macro check whether @a itc value is invalid, | ||
354 | * macro does not check whether @a itc was destroyed. | ||
355 | * @param itc the itc to check | ||
356 | * @return boolean true if @a itc has invalid value, | ||
357 | * boolean false otherwise. | ||
358 | */ | ||
359 | #define MHD_ITC_IS_INVALID_(itc) (! MHD_ITC_IS_VALID_(itc)) | ||
360 | |||
361 | #endif /* MHD_ITC_H */ | ||