aboutsummaryrefslogtreecommitdiff
path: root/src/lib/mhd_itc.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/mhd_itc.h')
-rw-r--r--src/lib/mhd_itc.h361
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 */
76static 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 */