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