libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

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 */