mhd_itc.h (11275B)
1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ 2 /* 3 This file is part of GNU libmicrohttpd. 4 Copyright (C) 2016-2024 Evgeny Grin (Karlson2k), Christian Grothoff 5 6 GNU libmicrohttpd is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 GNU libmicrohttpd is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 Alternatively, you can redistribute GNU libmicrohttpd and/or 17 modify it under the terms of the GNU General Public License as 18 published by the Free Software Foundation; either version 2 of 19 the License, or (at your option) any later version, together 20 with the eCos exception, as follows: 21 22 As a special exception, if other files instantiate templates or 23 use macros or inline functions from this file, or you compile this 24 file and link it with other works to produce a work based on this 25 file, this file does not by itself cause the resulting work to be 26 covered by the GNU General Public License. However the source code 27 for this file must still be made available in accordance with 28 section (3) of the GNU General Public License v2. 29 30 This exception does not invalidate any other reasons why a work 31 based on this file might be covered by the GNU General Public 32 License. 33 34 You should have received copies of the GNU Lesser General Public 35 License and the GNU General Public License along with this library; 36 if not, see <https://www.gnu.org/licenses/>. 37 */ 38 39 /** 40 * @file src/mhd2/mhd_itc.h 41 * @brief Header for platform-independent inter-thread communication 42 * @author Karlson2k (Evgeny Grin) 43 * @author Christian Grothoff 44 * 45 * Provides basic abstraction for inter-thread communication. 46 * Any functions can be implemented as macro on some platforms 47 * unless explicitly marked otherwise. 48 * Any "function" argument can be unused in macro, so avoid 49 * variable modification in function parameters. 50 */ 51 #ifndef MHD_ITC_H 52 #define MHD_ITC_H 1 53 #include "mhd_sys_options.h" 54 55 #include "mhd_itc_types.h" 56 57 #include "mhd_panic.h" 58 59 #if defined(MHD_ITC_EVENTFD_) 60 61 /* **************** Optimised ITC implementation by eventfd ********** */ 62 # include <sys/eventfd.h> 63 # include <stdint.h> /* for uint_fast64_t */ 64 # ifdef HAVE_UNISTD_H 65 # include <unistd.h> /* for read(), write() */ 66 # else 67 # include <stdlib.h> 68 # endif /* HAVE_UNISTD_H */ 69 # include "sys_errno.h" 70 71 /** 72 * Number of FDs used by every ITC. 73 */ 74 # define mhd_ITC_NUM_FDS (1) 75 76 /** 77 * Set @a itc to the invalid value. 78 * @param pitc the pointer to the itc to set 79 */ 80 #define mhd_itc_set_invalid(pitc) ((pitc)->fd = -1) 81 82 /** 83 * Check whether ITC has valid value. 84 * 85 * Macro check whether @a itc value is valid (allowed), 86 * macro does not check whether @a itc was really initialised. 87 * @param itc the itc to check 88 * @return boolean true if @a itc has valid value, 89 * boolean false otherwise. 90 */ 91 #define mhd_ITC_IS_VALID(itc) (0 <= ((itc).fd)) 92 93 /** 94 * Initialise ITC by generating eventFD 95 * @param pitc the pointer to the ITC to initialise 96 * @return non-zero if succeeded, zero otherwise 97 */ 98 # define mhd_itc_init(pitc) \ 99 (-1 != ((pitc)->fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK))) 100 101 /** 102 * Helper for mhd_itc_activate() 103 */ 104 # ifdef HAVE_COMPOUND_LITERALS_LVALUES 105 # define mhd_ITC_WR_DATA ((uint_fast64_t){1}) 106 # else 107 /** 108 * Internal static const helper for mhd_itc_activate() 109 */ 110 static const uint_fast64_t mhd_ITC_WR_DATA = 1; 111 # endif 112 113 /** 114 * Activate signal on the @a itc 115 * @param itc the itc to use 116 * @return non-zero if succeeded, zero otherwise 117 */ 118 #define mhd_itc_activate(itc) \ 119 ((write ((itc).fd, (const void*) &mhd_ITC_WR_DATA, 8) > 0) \ 120 || (EAGAIN == errno)) 121 122 /** 123 * Return read FD of @a itc which can be used for poll(), select() etc. 124 * @param itc the itc to get FD 125 * @return FD of read side 126 */ 127 #define mhd_itc_r_fd(itc) ((itc).fd) 128 129 /** 130 * Clear signalled state on @a itc 131 * @param itc the itc to clear 132 */ 133 #define mhd_itc_clear(itc) \ 134 do { uint_fast64_t mhd__b; \ 135 (void) (0 > read ((itc).fd, (void*) &mhd__b, 8)); \ 136 } while (0) 137 138 /** 139 * Destroy previously initialised ITC. Note that close() 140 * on some platforms returns odd errors, so we ONLY fail 141 * if the errno is EBADF. 142 * @param itc the itc to destroy 143 * @return non-zero if succeeded, zero otherwise 144 */ 145 #define mhd_itc_destroy(itc) \ 146 ((0 == close ((itc).fd)) || (EBADF != errno)) 147 148 #elif defined(MHD_ITC_PIPE_) 149 150 /* **************** Standard UNIX ITC implementation by pipe ********** */ 151 152 # if defined(HAVE_PIPE2_FUNC) 153 # include <fcntl.h> /* for O_CLOEXEC, O_NONBLOCK */ 154 # endif /* HAVE_PIPE2_FUNC && HAVE_FCNTL_H */ 155 # ifdef HAVE_UNISTD_H 156 # include <unistd.h> /* for read(), write() */ 157 # else 158 # include <stdlib.h> 159 # endif /* HAVE_UNISTD_H */ 160 # include "sys_errno.h" 161 # if defined(HAVE_PIPE2_FUNC) && defined(O_CLOEXEC) && defined(O_NONBLOCK) 162 # define MHD_USE_PIPE2 1 163 # else 164 # include "sys_bool_type.h" 165 # endif 166 167 168 /** 169 * Number of FDs used by every ITC. 170 */ 171 # define mhd_ITC_NUM_FDS (2) 172 173 /** 174 * Set @a itc to the invalid value. 175 * @param pitc the pointer to the itc to set 176 */ 177 # define mhd_itc_set_invalid(pitc) ((pitc)->fd[0] = (pitc)->fd[1] = -1) 178 179 /** 180 * Check whether ITC has valid value. 181 * 182 * Macro check whether @a itc value is valid (allowed), 183 * macro does not check whether @a itc was really initialised. 184 * @param itc the itc to check 185 * @return boolean true if @a itc has valid value, 186 * boolean false otherwise. 187 */ 188 # define mhd_ITC_IS_VALID(itc) (0 <= (itc).fd[0]) 189 190 /** 191 * Initialise ITC by generating pipe 192 * @param pitc the pointer to the ITC to initialise 193 * @return non-zero if succeeded, zero otherwise 194 */ 195 # if defined(MHD_USE_PIPE2) 196 # define mhd_itc_init(pitc) (! pipe2 ((pitc)->fd, O_CLOEXEC | O_NONBLOCK)) 197 # else /* ! MHD_USE_PIPE2 */ 198 # define mhd_itc_init(pitc) \ 199 ( (! pipe ((pitc)->fd)) ? \ 200 (mhd_itc_nonblocking ((pitc)) ? \ 201 (! 0) : \ 202 ((void) mhd_itc_destroy (*(pitc)), 0) ) \ 203 : (0) ) 204 205 # define MHD_HAVE_MHD_ITC_NONBLOCKING 1 206 /** 207 * Change itc FD options to be non-blocking. 208 * 209 * @param pitc the pointer to ITC to manipulate 210 * @return true if succeeded, false otherwise 211 */ 212 MHD_INTERNAL bool 213 mhd_itc_nonblocking (struct mhd_itc *pitc); 214 215 # endif /* ! MHD_USE_PIPE2 */ 216 217 /** 218 * Activate signal on @a itc 219 * @param itc the itc to use 220 * @return non-zero if succeeded, zero otherwise 221 */ 222 # define mhd_itc_activate(itc) \ 223 ((write ((itc).fd[1], (const void*) "", 1) > 0) || (EAGAIN == errno)) 224 225 /** 226 * Return read FD of @a itc which can be used for poll(), select() etc. 227 * @param itc the itc to get FD 228 * @return FD of read side 229 */ 230 # define mhd_itc_r_fd(itc) ((itc).fd[0]) 231 232 /** 233 * Clear signaled state on @a itc 234 * @param itc the itc to clear 235 */ 236 # define mhd_itc_clear(itc) do \ 237 { long mhd__b; \ 238 while (0 < read ((itc).fd[0], (void*) &mhd__b, sizeof(mhd__b))) \ 239 {(void) 0;} } while (0) 240 241 /** 242 * Destroy previously initialised ITC 243 * @param itc the itc to destroy 244 * @return non-zero if succeeded, zero otherwise 245 */ 246 # define mhd_itc_destroy(itc) \ 247 (0 == (close ((itc).fd[0]) + close ((itc).fd[1]))) 248 249 #elif defined(MHD_ITC_SOCKETPAIR_) 250 251 /* **************** ITC implementation by socket pair ********** */ 252 253 # include "sys_sockets_headers.h" 254 # include "mhd_sockets_macros.h" 255 # if ! defined(mhd_socket_pair_nblk) 256 # include "mhd_sockets_funcs.h" 257 # endif 258 259 /** 260 * Number of FDs used by every ITC. 261 */ 262 # define mhd_ITC_NUM_FDS (2) 263 264 /** 265 * Set @a itc to the invalid value. 266 * @param pitc the pointer to the itc to set 267 */ 268 # define mhd_itc_set_invalid(pitc) \ 269 ((pitc)->sk[0] = (pitc)->sk[1] = MHD_INVALID_SOCKET) 270 271 /** 272 * Check whether ITC has valid value. 273 * 274 * Macro check whether @a itc value is valid (allowed), 275 * macro does not check whether @a itc was really initialised. 276 * @param itc the itc to check 277 * @return boolean true if @a itc has valid value, 278 * boolean false otherwise. 279 */ 280 # define mhd_ITC_IS_VALID(itc) (MHD_INVALID_SOCKET != (itc).sk[0]) 281 282 /** 283 * Initialise ITC by generating socketpair 284 * @param itc the itc to initialise 285 * @return non-zero if succeeded, zero otherwise 286 */ 287 # ifdef mhd_socket_pair_nblk 288 # define mhd_itc_init(pitc) mhd_socket_pair_nblk ((pitc)->sk) 289 # else /* ! mhd_socket_pair_nblk */ 290 # define mhd_itc_init(pitc) \ 291 ( (! mhd_socket_pair ((pitc)->sk)) ? \ 292 (0) : ( (! mhd_itc_nonblocking ((pitc))) ? \ 293 (mhd_itc_destroy (*(pitc)), 0) : (! 0) ) ) 294 295 /** 296 * Change itc FD options to be non-blocking. 297 * 298 * @param pitc the pointer to ITC to manipulate 299 * @return true if succeeded, false otherwise 300 */ 301 # define mhd_itc_nonblocking(pitc) \ 302 (mhd_socket_nonblocking ((pitc)->sk[0]) && \ 303 mhd_socket_nonblocking ((pitc)->sk[1])) 304 305 # endif /* ! mhd_socket_pair_nblk */ 306 307 /** 308 * Activate signal on @a itc 309 * @param itc the itc to use 310 * @return non-zero if succeeded, zero otherwise 311 */ 312 # define mhd_itc_activate(itc) \ 313 ((0 < mhd_sys_send ((itc).sk[1], "", 1)) || mhd_SCKT_LERR_IS_EAGAIN ()) 314 315 /** 316 * Return read FD of @a itc which can be used for poll(), select() etc. 317 * @param itc the itc to get FD 318 * @return FD of read side 319 */ 320 # define mhd_itc_r_fd(itc) ((itc).sk[0]) 321 322 /** 323 * Clear signaled state on @a itc 324 * @param itc the itc to clear 325 */ 326 # define mhd_itc_clear(itc) do \ 327 { long mhd__b; \ 328 while (0 < mhd_sys_recv ((itc).sk[0], &mhd__b, sizeof(mhd__b))) \ 329 {(void) 0;} } while (0) 330 331 /** 332 * Destroy previously initialised ITC 333 * @param itc the itc to destroy 334 * @return non-zero if succeeded, zero otherwise 335 */ 336 # define mhd_itc_destroy(itc) \ 337 (mhd_socket_close ((itc).sk[1]) ? \ 338 mhd_socket_close ((itc).sk[0]) : \ 339 ((void) mhd_socket_close ((itc).sk[0]), ! ! 0) ) 340 341 #endif /* MHD_ITC_SOCKETPAIR_ */ 342 343 /** 344 * Destroy previously initialised ITC and abort execution 345 * if error is detected. 346 * @param itc the itc to destroy 347 */ 348 #define mhd_itc_destroy_chk(itc) do { \ 349 if (! mhd_itc_destroy (itc)) \ 350 MHD_PANIC ("Failed to destroy ITC.\n"); \ 351 } while (0) 352 353 /** 354 * Check whether ITC has invalid value. 355 * 356 * Macro check whether @a itc value is invalid, 357 * macro does not check whether @a itc was destroyed. 358 * @param itc the itc to check 359 * @return boolean true if @a itc has invalid value, 360 * boolean false otherwise. 361 */ 362 #define mhd_ITC_IS_INVALID(itc) (! mhd_ITC_IS_VALID (itc)) 363 364 #endif /* ! MHD_ITC_H */