libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

mhd_threads.h (19189B)


      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_threads.h
     23  * @brief  Header for platform-independent threads abstraction
     24  * @author Karlson2k (Evgeny Grin)
     25  *
     26  * Provides basic abstraction for threads.
     27  * Any functions can be implemented as macro on some platforms
     28  * unless explicitly marked otherwise.
     29  * Any function argument can be skipped in macro, so avoid
     30  * variable modification in function parameters.
     31  *
     32  * @warning Unlike pthread functions, most of functions return
     33  *          nonzero on success.
     34  */
     35 
     36 #ifndef MHD_THREADS_H
     37 #define MHD_THREADS_H 1
     38 
     39 #include "mhd_options.h"
     40 #ifdef HAVE_STDDEF_H
     41 #  include <stddef.h> /* for size_t */
     42 #elif defined(HAVE_STDLIB_H)
     43 #  include <stdlib.h> /* for size_t */
     44 #else /* ! HAVE_STDLIB_H */
     45 #  include <stdio.h>  /* for size_t */
     46 #endif /* ! HAVE_STDLIB_H */
     47 
     48 #if defined(MHD_USE_POSIX_THREADS)
     49 #  undef HAVE_CONFIG_H
     50 #  include <pthread.h>
     51 #  define HAVE_CONFIG_H 1
     52 #  ifndef MHD_USE_THREADS
     53 #    define MHD_USE_THREADS 1
     54 #  endif
     55 #elif defined(MHD_USE_W32_THREADS)
     56 #  ifndef WIN32_LEAN_AND_MEAN
     57 #    define WIN32_LEAN_AND_MEAN 1
     58 #  endif /* !WIN32_LEAN_AND_MEAN */
     59 #  include <windows.h>
     60 #  ifndef MHD_USE_THREADS
     61 #    define MHD_USE_THREADS 1
     62 #  endif
     63 #else
     64 #  error No threading API is available.
     65 #endif
     66 
     67 #ifdef HAVE_STDBOOL_H
     68 #  include <stdbool.h>
     69 #endif /* HAVE_STDBOOL_H */
     70 
     71 #if defined(MHD_USE_POSIX_THREADS) && defined(MHD_USE_W32_THREADS)
     72 #  error Both MHD_USE_POSIX_THREADS and MHD_USE_W32_THREADS are defined
     73 #endif /* MHD_USE_POSIX_THREADS && MHD_USE_W32_THREADS */
     74 
     75 #ifndef MHD_NO_THREAD_NAMES
     76 #  if defined(MHD_USE_POSIX_THREADS)
     77 #    if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || \
     78   defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) || \
     79   defined(HAVE_PTHREAD_SETNAME_NP_DARWIN) || \
     80   defined(HAVE_PTHREAD_SETNAME_NP_NETBSD) || \
     81   defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || \
     82   defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
     83 #      define MHD_USE_THREAD_NAME_
     84 #    endif /* HAVE_PTHREAD_SETNAME_NP */
     85 #  elif defined(MHD_USE_W32_THREADS)
     86 #    ifdef _MSC_FULL_VER
     87 /* Thread names only available with VC compiler */
     88 #      define MHD_USE_THREAD_NAME_
     89 #    endif /* _MSC_FULL_VER */
     90 #  endif
     91 #endif
     92 
     93 /* ** Thread handle - used to control the thread ** */
     94 
     95 #if defined(MHD_USE_POSIX_THREADS)
     96 /**
     97  * Wait until specified thread is ended and free thread handle on success.
     98  * @param thread handle to watch
     99  * @return nonzero on success, zero otherwise
    100  */
    101 #  define MHD_join_thread_(native_handle) \
    102   (! pthread_join ((native_handle), NULL))
    103 #elif defined(MHD_USE_W32_THREADS)
    104 /**
    105  * Wait until specified thread is ended and free thread handle on success.
    106  * @param thread handle to watch
    107  * @return nonzero on success, zero otherwise
    108  */
    109 #  define MHD_join_thread_(native_handle) \
    110   ( (WAIT_OBJECT_0 == WaitForSingleObject ( (native_handle), INFINITE)) ? \
    111     (CloseHandle ( (native_handle)), ! 0) : 0 )
    112 #endif
    113 
    114 #if defined(MHD_USE_POSIX_THREADS)
    115 /**
    116  * The native type to control the thread from other threads
    117  */
    118 typedef pthread_t MHD_thread_handle_native_;
    119 #elif defined(MHD_USE_W32_THREADS)
    120 /**
    121  * The native type to control the thread from other threads
    122  */
    123 typedef HANDLE MHD_thread_handle_native_;
    124 #endif
    125 
    126 #if defined(MHD_USE_POSIX_THREADS)
    127 #  if defined(__gnu_linux__) || \
    128   (defined(__linux__) && defined(__GLIBC__))
    129 /* The next part of code is disabled because it relies on undocumented
    130    behaviour.
    131    It could be enabled for neglectable performance and size improvements. */
    132 #  if 0 /* Disabled code */
    133 /**
    134  * The native invalid value for native thread handle
    135  */
    136 #    define MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_ \
    137      ((MHD_thread_handle_native_) 0)
    138 #  endif /* Disabled code */
    139 #  endif /* __gnu_linux__ || (__linux__ && __GLIBC__) */
    140 #elif defined(MHD_USE_W32_THREADS)
    141 /**
    142  * The native invalid value for native thread handle
    143  */
    144 #  define MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_ \
    145   ((MHD_thread_handle_native_) NULL)
    146 #endif /* MHD_USE_W32_THREADS */
    147 
    148 #if ! defined(MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_)
    149 /**
    150  * Structure with thread handle and validity flag
    151  */
    152 struct MHD_thread_handle_struct_
    153 {
    154   bool valid;                       /**< true if native handle is set */
    155   MHD_thread_handle_native_ native; /**< the native thread handle */
    156 };
    157 /**
    158  * Type with thread handle that can be set to invalid value
    159  */
    160 typedef struct MHD_thread_handle_struct_ MHD_thread_handle_;
    161 
    162 /**
    163  * Set variable pointed by @a handle_ptr to invalid (unset) value
    164  */
    165 #  define MHD_thread_handle_set_invalid_(handle_ptr) \
    166    ((handle_ptr)->valid = false)
    167 /**
    168  * Set native handle in variable pointed by @a handle_ptr
    169  * to @a native_val value
    170  */
    171 #  define MHD_thread_handle_set_native_(handle_ptr,native_val) \
    172    ((handle_ptr)->valid = true, (handle_ptr)->native = native_val)
    173 /**
    174  * Check whether native handle value is set in @a handle_var variable
    175  */
    176 #  define MHD_thread_handle_is_valid_(handle_var) \
    177    ((handle_var).valid)
    178 /**
    179  * Get native handle value from @a handle_var variable
    180  */
    181 #  define MHD_thread_handle_get_native_(handle_var) \
    182    ((handle_var).native)
    183 #else  /* MHD_THREAD_HANDLE_NATIVE_INVALID_ */
    184 /**
    185  * Type with thread handle that can be set to invalid value
    186  */
    187 typedef MHD_thread_handle_native_ MHD_thread_handle_;
    188 
    189 /**
    190  * Set variable pointed by @a handle_ptr to invalid (unset) value
    191  */
    192 #  define MHD_thread_handle_set_invalid_(handle_ptr) \
    193     ((*(handle_ptr)) = MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_)
    194 /**
    195  * Set native handle in the variable pointed by @a handle_ptr
    196  * to @a native_val value
    197  */
    198 #  define MHD_thread_handle_set_native_(handle_ptr,native_val) \
    199     ((*(handle_ptr)) = native_val)
    200 /**
    201  * Check whether native handle value is set in @a handle_var variable
    202  */
    203 #  define MHD_thread_handle_is_valid_(handle_var) \
    204     (MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_ != handle_var)
    205 /**
    206  * Get native handle value from @a handle_var variable
    207  */
    208 #  define MHD_thread_handle_get_native_(handle_var) \
    209     (handle_var)
    210 /**
    211  * Get pointer to native handle stored the variable pointed by @a handle_ptr
    212  * @note This macro could not available if direct manipulation of
    213  *       the native handle is not possible
    214  */
    215 #  define MHD_thread_handle_get_native_ptr_(handle_ptr) \
    216     (handle_ptr)
    217 #endif /* MHD_THREAD_HANDLE_NATIVE_INVALID_ */
    218 
    219 
    220 /* ** Thread ID - used to check threads match ** */
    221 
    222 #if defined(MHD_USE_POSIX_THREADS)
    223 /**
    224  * The native type used to check whether current thread matches expected thread
    225  */
    226 typedef pthread_t MHD_thread_ID_native_;
    227 
    228 /**
    229  * Function to get the current thread native ID.
    230  */
    231 #  define MHD_thread_ID_native_current_ pthread_self
    232 
    233 /**
    234  * Check whether two native thread IDs are equal.
    235  * @return non-zero if equal, zero if not equal
    236  */
    237 #  define MHD_thread_ID_native_equal_(id1,id2) \
    238   (pthread_equal(id1,id2))
    239 #elif defined(MHD_USE_W32_THREADS)
    240 /**
    241  * The native type used to check whether current thread matches expected thread
    242  */
    243 typedef DWORD MHD_thread_ID_native_;
    244 
    245 /**
    246  * Function to get the current thread native ID.
    247  */
    248 #  define MHD_thread_ID_native_current_ GetCurrentThreadId
    249 
    250 /**
    251  * Check whether two native thread IDs are equal.
    252  * @return non-zero if equal, zero if not equal
    253  */
    254 #  define MHD_thread_ID_native_equal_(id1,id2) \
    255   ((id1) == (id2))
    256 #endif
    257 
    258 /**
    259  * Check whether specified thread ID matches current thread.
    260  * @param id the thread ID to match
    261  * @return nonzero on match, zero otherwise
    262  */
    263 #define MHD_thread_ID_native_is_current_thread_(id) \
    264     MHD_thread_ID_native_equal_(id, MHD_thread_ID_native_current_())
    265 
    266 
    267 #if defined(MHD_USE_POSIX_THREADS)
    268 #  if defined(MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_)
    269 /**
    270  * The native invalid value for native thread ID
    271  */
    272 #    define MHD_THREAD_ID_NATIVE_VALUE_INVALID_ \
    273             MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_
    274 #  endif /* MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_ */
    275 #elif defined(MHD_USE_W32_THREADS)
    276 /**
    277  * The native invalid value for native thread ID
    278  */
    279  #  define MHD_THREAD_ID_NATIVE_VALUE_INVALID_ \
    280    ((MHD_thread_ID_native_) 0)
    281 #endif /* MHD_USE_W32_THREADS */
    282 
    283 #if ! defined(MHD_THREAD_ID_NATIVE_VALUE_INVALID_)
    284 /**
    285  * Structure with thread id and validity flag
    286  */
    287 struct MHD_thread_ID_struct_
    288 {
    289   bool valid;                   /**< true if native ID is set */
    290   MHD_thread_ID_native_ native; /**< the native thread ID */
    291 };
    292 /**
    293  * Type with thread ID that can be set to invalid value
    294  */
    295 typedef struct MHD_thread_ID_struct_ MHD_thread_ID_;
    296 
    297 /**
    298  * Set variable pointed by @a ID_ptr to invalid (unset) value
    299  */
    300 #  define MHD_thread_ID_set_invalid_(ID_ptr) \
    301    ((ID_ptr)->valid = false)
    302 /**
    303  * Set native ID in variable pointed by @a ID_ptr
    304  * to @a native_val value
    305  */
    306 #  define MHD_thread_ID_set_native_(ID_ptr,native_val) \
    307    ((ID_ptr)->valid = true, (ID_ptr)->native = native_val)
    308 /**
    309  * Check whether native ID value is set in @a ID_var variable
    310  */
    311 #  define MHD_thread_ID_is_valid_(ID_var) \
    312    ((ID_var).valid)
    313 /**
    314  * Get native ID value from @a ID_var variable
    315  */
    316 #  define MHD_thread_ID_get_native_(ID_var) \
    317     ((ID_var).native)
    318 /**
    319  * Check whether @a ID_var variable is equal current thread
    320  */
    321 #  define MHD_thread_ID_is_current_thread_(ID_var) \
    322     (MHD_thread_ID_is_valid_(ID_var) && \
    323      MHD_thread_ID_native_is_current_thread_((ID_var).native))
    324 #else  /* MHD_THREAD_ID_NATIVE_INVALID_ */
    325 /**
    326  * Type with thread ID that can be set to invalid value
    327  */
    328 typedef MHD_thread_ID_native_ MHD_thread_ID_;
    329 
    330 /**
    331  * Set variable pointed by @a ID_ptr to invalid (unset) value
    332  */
    333 #  define MHD_thread_ID_set_invalid_(ID_ptr) \
    334     ((*(ID_ptr)) = MHD_THREAD_ID_NATIVE_VALUE_INVALID_)
    335 /**
    336  * Set native ID in variable pointed by @a ID_ptr
    337  * to @a native_val value
    338  */
    339 #  define MHD_thread_ID_set_native_(ID_ptr,native_val) \
    340     ((*(ID_ptr)) = native_val)
    341 /**
    342  * Check whether native ID value is set in @a ID_var variable
    343  */
    344 #  define MHD_thread_ID_is_valid_(ID_var) \
    345     (MHD_THREAD_ID_NATIVE_VALUE_INVALID_ != ID_var)
    346 /**
    347  * Get native ID value from @a ID_var variable
    348  */
    349 #  define MHD_thread_ID_get_native_(ID_var) \
    350     (ID_var)
    351 /**
    352  * Check whether @a ID_var variable is equal current thread
    353  */
    354 #  define MHD_thread_ID_is_current_thread_(ID_var) \
    355     MHD_thread_ID_native_is_current_thread_(ID_var)
    356 #endif /* MHD_THREAD_ID_NATIVE_INVALID_ */
    357 
    358 /**
    359  * Set current thread ID in variable pointed by @a ID_ptr
    360  */
    361 #  define MHD_thread_ID_set_current_thread_(ID_ptr) \
    362     MHD_thread_ID_set_native_(ID_ptr,MHD_thread_ID_native_current_())
    363 
    364 
    365 #if defined(MHD_USE_POSIX_THREADS)
    366 #  if defined(MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_) && \
    367   ! defined(MHD_THREAD_ID_NATIVE_VALUE_INVALID_)
    368 #    error \
    369   MHD_THREAD_ID_NATIVE_VALUE_INVALID_ is defined, but MHD_THREAD_ID_NATIVE_VALUE_INVALID_ is not defined
    370 #  elif ! defined(MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_) && \
    371   defined(MHD_THREAD_ID_NATIVE_VALUE_INVALID_)
    372 #    error \
    373   MHD_THREAD_ID_NATIVE_VALUE_INVALID_ is not defined, but MHD_THREAD_ID_NATIVE_VALUE_INVALID_ is defined
    374 #  endif
    375 #endif /* MHD_USE_POSIX_THREADS */
    376 
    377 /* When staring a new thread, the kernel (and thread implementation) may
    378  * pause the calling (initial) thread and start the new thread.
    379  * If thread identifier is assigned to variable in the initial thread then
    380  * the value of the identifier variable will be undefined in the new thread
    381  * until the initial thread continue processing.
    382  * However, it is also possible that the new thread created, but not executed
    383  * for some time while the initial thread continue execution. In this case any
    384  * variable assigned in the new thread will be undefined for some time until
    385  * they really processed by the new thread.
    386  * To avoid data races, a special structure MHD_thread_handle_ID_ is used.
    387  * The "handle" is assigned by calling (initial) thread and should be always
    388  * defined when checked in the initial thread.
    389  * The "ID" is assigned by the new thread and should be always defined when
    390  * checked inside the new thread.
    391  */
    392 /* Depending on implementation, pthread_create() MAY set thread ID into
    393  * provided pointer and after it start thread OR start thread and after
    394  * it set thread ID. In the latter case, to avoid data races, additional
    395  * pthread_self() call is required in thread routine. If some platform
    396  * is known for setting thread ID BEFORE starting thread macro
    397  * MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD could be defined
    398  * to save some resources. */
    399 /* #define MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD 1 */
    400 
    401 /* * handle - must be valid when other thread knows that particular thread
    402      is started.
    403    * ID     - must be valid when code is executed inside thread */
    404 #if defined(MHD_USE_POSIX_THREADS) && \
    405   defined(MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD) && \
    406   defined(MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_) && \
    407   defined(MHD_THREAD_ID_NATIVE_VALUE_INVALID_) && \
    408   defined(MHD_thread_handle_get_native_ptr_)
    409 union _MHD_thread_handle_ID_
    410 {
    411   MHD_thread_handle_ handle;    /**< To be used in other threads */
    412   MHD_thread_ID_ ID;            /**< To be used in the thread itself */
    413 };
    414 typedef union _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
    415 #  define MHD_THREAD_HANDLE_ID_IS_UNION 1
    416 #else  /* !MHD_USE_POSIX_THREADS
    417           || !MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD
    418           || !MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_
    419           || !MHD_THREAD_ID_NATIVE_VALUE_INVALID_
    420           || !MHD_thread_handle_get_native_ptr_ */
    421 struct _MHD_thread_handle_ID_
    422 {
    423   MHD_thread_handle_ handle;    /**< To be used in other threads */
    424   MHD_thread_ID_ ID;            /**< To be used in the thread itself */
    425 };
    426 typedef struct _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
    427 #endif /* !MHD_USE_POSIX_THREADS
    428           || !MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD
    429           || !MHD_THREAD_HANDLE_NATIVE_VALUE_INVALID_
    430           || !MHD_THREAD_ID_NATIVE_VALUE_INVALID_
    431           || !MHD_thread_handle_get_native_ptr_ */
    432 
    433 /**
    434  * Set MHD_thread_handle_ID_ to invalid value
    435  */
    436 #define MHD_thread_handle_ID_set_invalid_(hndl_id_ptr) \
    437   (MHD_thread_handle_set_invalid_(&((hndl_id_ptr)->handle)), \
    438    MHD_thread_ID_set_invalid_(&((hndl_id_ptr)->ID)))
    439 
    440 /**
    441  * Check whether thread handle is valid.
    442  * To be used in threads other then the thread specified by @a hndl_id.
    443  */
    444 #define MHD_thread_handle_ID_is_valid_handle_(hndl_id) \
    445     MHD_thread_handle_is_valid_((hndl_id).handle)
    446 
    447 /**
    448  * Set native handle in variable pointed by @a hndl_id_ptr
    449  * to @a native_val value
    450  */
    451 #define MHD_thread_handle_ID_set_native_handle_(hndl_id_ptr,native_val) \
    452     MHD_thread_handle_set_native_(&((hndl_id_ptr)->handle),native_val)
    453 
    454 #if defined(MHD_thread_handle_get_native_ptr_)
    455 /**
    456  * Get pointer to native handle stored the variable pointed by @a hndl_id_ptr
    457  * @note This macro could not available if direct manipulation of
    458  *       the native handle is not possible
    459  */
    460 #  define MHD_thread_handle_ID_get_native_handle_ptr_(hndl_id_ptr) \
    461     MHD_thread_handle_get_native_ptr_(&((hndl_id_ptr)->handle))
    462 #endif /* MHD_thread_handle_get_native_ptr_ */
    463 
    464 /**
    465  * Get native thread handle from MHD_thread_handle_ID_ variable.
    466  */
    467 #define MHD_thread_handle_ID_get_native_handle_(hndl_id) \
    468     MHD_thread_handle_get_native_((hndl_id).handle)
    469 
    470 /**
    471  * Check whether thread ID is valid.
    472  * To be used in the thread itself.
    473  */
    474 #define MHD_thread_handle_ID_is_valid_ID_(hndl_id) \
    475     MHD_thread_ID_is_valid_((hndl_id).ID)
    476 
    477 #if defined(MHD_THREAD_HANDLE_ID_IS_UNION)
    478 #  if defined(MHD_USE_W32_THREADS)
    479 #    error MHD_thread_handle_ID_ cannot be a union with W32 threads
    480 #  endif /* MHD_USE_W32_THREADS */
    481 /**
    482  * Set current thread ID in the variable pointed by @a hndl_id_ptr
    483  */
    484 #  define MHD_thread_handle_ID_set_current_thread_ID_(hndl_id_ptr) (void) 0
    485 #else  /* ! MHD_THREAD_HANDLE_ID_IS_UNION */
    486 /**
    487  * Set current thread ID in the variable pointed by @a hndl_id_ptr
    488  */
    489 #  define MHD_thread_handle_ID_set_current_thread_ID_(hndl_id_ptr) \
    490     MHD_thread_ID_set_current_thread_(&((hndl_id_ptr)->ID))
    491 #endif /* ! MHD_THREAD_HANDLE_ID_IS_UNION */
    492 
    493 /**
    494  * Check whether provided thread ID matches current thread.
    495  * @param ID thread ID to match
    496  * @return nonzero on match, zero otherwise
    497  */
    498 #define MHD_thread_handle_ID_is_current_thread_(hndl_id) \
    499      MHD_thread_ID_is_current_thread_((hndl_id).ID)
    500 
    501 /**
    502  * Wait until specified thread is ended and free thread handle on success.
    503  * @param hndl_id_ handle with ID to watch
    504  * @return nonzero on success, zero otherwise
    505  */
    506 #define MHD_thread_handle_ID_join_thread_(hndl_id) \
    507   MHD_join_thread_(MHD_thread_handle_ID_get_native_handle_(hndl_id))
    508 
    509 #if defined(MHD_USE_POSIX_THREADS)
    510 #  define MHD_THRD_RTRN_TYPE_ void*
    511 #  define MHD_THRD_CALL_SPEC_
    512 #elif defined(MHD_USE_W32_THREADS)
    513 #  define MHD_THRD_RTRN_TYPE_ unsigned
    514 #  define MHD_THRD_CALL_SPEC_ __stdcall
    515 #endif
    516 
    517 /**
    518  * Signature of main function for a thread.
    519  *
    520  * @param cls closure argument for the function
    521  * @return termination code from the thread
    522  */
    523 typedef MHD_THRD_RTRN_TYPE_
    524 (MHD_THRD_CALL_SPEC_ *MHD_THREAD_START_ROUTINE_)(void *cls);
    525 
    526 
    527 /**
    528  * Create a thread and set the attributes according to our options.
    529  *
    530  * If thread is created, thread handle must be freed by MHD_join_thread_().
    531  *
    532  * @param handle_id     handle to initialise
    533  * @param stack_size    size of stack for new thread, 0 for default
    534  * @param start_routine main function of thread
    535  * @param arg argument  for start_routine
    536  * @return non-zero on success; zero otherwise (with errno set)
    537  */
    538 int
    539 MHD_create_thread_ (MHD_thread_handle_ID_ *handle_id,
    540                     size_t stack_size,
    541                     MHD_THREAD_START_ROUTINE_ start_routine,
    542                     void *arg);
    543 
    544 #ifndef MHD_USE_THREAD_NAME_
    545 #define MHD_create_named_thread_(t,n,s,r,a) MHD_create_thread_ ((t),(s),(r),(a))
    546 #else  /* MHD_USE_THREAD_NAME_ */
    547 /**
    548  * Create a named thread and set the attributes according to our options.
    549  *
    550  * @param handle_id     handle to initialise
    551  * @param thread_name   name for new thread
    552  * @param stack_size    size of stack for new thread, 0 for default
    553  * @param start_routine main function of thread
    554  * @param arg argument  for start_routine
    555  * @return non-zero on success; zero otherwise
    556  */
    557 int
    558 MHD_create_named_thread_ (MHD_thread_handle_ID_ *handle_id,
    559                           const char *thread_name,
    560                           size_t stack_size,
    561                           MHD_THREAD_START_ROUTINE_ start_routine,
    562                           void *arg);
    563 
    564 #endif /* MHD_USE_THREAD_NAME_ */
    565 
    566 #endif /* ! MHD_THREADS_H */