libmicrohttpd

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

mhd_threads.c (12105B)


      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.c
     23  * @brief  Implementation for thread functions
     24  * @author Karlson2k (Evgeny Grin)
     25  */
     26 
     27 #include "mhd_threads.h"
     28 #ifdef MHD_USE_W32_THREADS
     29 #include "mhd_limits.h"
     30 #include <process.h>
     31 #endif
     32 #ifdef MHD_USE_THREAD_NAME_
     33 #ifdef HAVE_STDLIB_H
     34 #include <stdlib.h>
     35 #endif /* HAVE_STDLIB_H */
     36 #ifdef HAVE_PTHREAD_NP_H
     37 #include <pthread_np.h>
     38 #endif /* HAVE_PTHREAD_NP_H */
     39 #endif /* MHD_USE_THREAD_NAME_ */
     40 #include <errno.h>
     41 #include "mhd_assert.h"
     42 
     43 
     44 #ifndef MHD_USE_THREAD_NAME_
     45 
     46 #define MHD_set_thread_name_(t, n) (void)
     47 #define MHD_set_cur_thread_name_(n) (void)
     48 
     49 #else  /* MHD_USE_THREAD_NAME_ */
     50 
     51 #if defined(MHD_USE_POSIX_THREADS)
     52 #if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || \
     53   defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
     54 #  define MHD_USE_THREAD_ATTR_SETNAME 1
     55 #endif /* HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD || \
     56           HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI */
     57 
     58 #if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || \
     59   defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) \
     60   || defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
     61 
     62 /**
     63  * Set thread name
     64  *
     65  * @param thread_id ID of thread
     66  * @param thread_name name to set
     67  * @return non-zero on success, zero otherwise
     68  */
     69 static int
     70 MHD_set_thread_name_ (const MHD_thread_ID_native_ thread_id,
     71                       const char *thread_name)
     72 {
     73   if (NULL == thread_name)
     74     return 0;
     75 
     76 #if defined(HAVE_PTHREAD_SETNAME_NP_GNU)
     77   return ! pthread_setname_np (thread_id, thread_name);
     78 #elif defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD)
     79   /* FreeBSD and OpenBSD use different function name and void return type */
     80   pthread_set_name_np (thread_id, thread_name);
     81   return ! 0;
     82 #elif defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
     83   /* NetBSD use 3 arguments: second argument is string in printf-like format,
     84    *                         third argument is a single argument for printf();
     85    * OSF1 use 3 arguments too, but last one always must be zero (NULL).
     86    * MHD doesn't use '%' in thread names, so both form are used in same way.
     87    */
     88   return ! pthread_setname_np (thread_id, thread_name, 0);
     89 #endif /* HAVE_PTHREAD_SETNAME_NP_NETBSD */
     90 }
     91 
     92 
     93 #ifndef __QNXNTO__
     94 /**
     95  * Set current thread name
     96  * @param n name to set
     97  * @return non-zero on success, zero otherwise
     98  */
     99 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (pthread_self (),(n))
    100 #else  /* __QNXNTO__ */
    101 /* Special case for QNX Neutrino - using zero for thread ID sets name faster. */
    102 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (0,(n))
    103 #endif /* __QNXNTO__ */
    104 #elif defined(HAVE_PTHREAD_SETNAME_NP_DARWIN)
    105 
    106 /**
    107  * Set current thread name
    108  * @param n name to set
    109  * @return non-zero on success, zero otherwise
    110  */
    111 #define MHD_set_cur_thread_name_(n) (! (pthread_setname_np ((n))))
    112 #endif /* HAVE_PTHREAD_SETNAME_NP_DARWIN */
    113 
    114 #elif defined(MHD_USE_W32_THREADS)
    115 #ifndef _MSC_FULL_VER
    116 /* Thread name available only for VC-compiler */
    117 #else  /* _MSC_FULL_VER */
    118 /**
    119  * Set thread name
    120  *
    121  * @param thread_id ID of thread, -1 for current thread
    122  * @param thread_name name to set
    123  * @return non-zero on success, zero otherwise
    124  */
    125 static int
    126 MHD_set_thread_name_ (const MHD_thread_ID_native_ thread_id,
    127                       const char *thread_name)
    128 {
    129   static const DWORD VC_SETNAME_EXC = 0x406D1388;
    130 #pragma pack(push,8)
    131   struct thread_info_struct
    132   {
    133     DWORD type;   /* Must be 0x1000. */
    134     LPCSTR name;  /* Pointer to name (in user address space). */
    135     DWORD ID;     /* Thread ID (-1 = caller thread). */
    136     DWORD flags;  /* Reserved for future use, must be zero. */
    137   } thread_info;
    138 #pragma pack(pop)
    139 
    140   if (NULL == thread_name)
    141     return 0;
    142 
    143   thread_info.type  = 0x1000;
    144   thread_info.name  = thread_name;
    145   thread_info.ID    = thread_id;
    146   thread_info.flags = 0;
    147 
    148   __try
    149   { /* This exception is intercepted by debugger */
    150     RaiseException (VC_SETNAME_EXC,
    151                     0,
    152                     sizeof (thread_info) / sizeof(ULONG_PTR),
    153                     (ULONG_PTR *) &thread_info);
    154   }
    155   __except (EXCEPTION_EXECUTE_HANDLER)
    156   {}
    157 
    158   return ! 0;
    159 }
    160 
    161 
    162 /**
    163  * Set current thread name
    164  * @param n name to set
    165  * @return non-zero on success, zero otherwise
    166  */
    167 #define MHD_set_cur_thread_name_(n) \
    168   MHD_set_thread_name_ ((MHD_thread_ID_native_) -1,(n))
    169 #endif /* _MSC_FULL_VER */
    170 #endif /* MHD_USE_W32_THREADS */
    171 
    172 #endif /* MHD_USE_THREAD_NAME_ */
    173 
    174 
    175 /**
    176  * Create a thread and set the attributes according to our options.
    177  *
    178  * If thread is created, thread handle must be freed by MHD_join_thread_().
    179  *
    180  * @param handle_id     handle to initialise
    181  * @param stack_size    size of stack for new thread, 0 for default
    182  * @param start_routine main function of thread
    183  * @param arg argument  for start_routine
    184  * @return non-zero on success; zero otherwise (with errno set)
    185  */
    186 int
    187 MHD_create_thread_ (MHD_thread_handle_ID_ *handle_id,
    188                     size_t stack_size,
    189                     MHD_THREAD_START_ROUTINE_ start_routine,
    190                     void *arg)
    191 {
    192 #if defined(MHD_USE_POSIX_THREADS)
    193   int res;
    194 #if defined(MHD_thread_handle_ID_get_native_handle_ptr_)
    195   pthread_t *const new_tid_ptr =
    196     MHD_thread_handle_ID_get_native_handle_ptr_ (handle_id);
    197 #else  /* ! MHD_thread_handle_ID_get_native_handle_ptr_ */
    198   pthread_t new_tid;
    199   pthread_t *const new_tid_ptr = &new_tid;
    200 #endif /* ! MHD_thread_handle_ID_get_native_handle_ptr_ */
    201 
    202   mhd_assert (! MHD_thread_handle_ID_is_valid_handle_ (*handle_id));
    203 
    204   if (0 != stack_size)
    205   {
    206     pthread_attr_t attr;
    207     res = pthread_attr_init (&attr);
    208     if (0 == res)
    209     {
    210       res = pthread_attr_setstacksize (&attr,
    211                                        stack_size);
    212       if (0 == res)
    213         res = pthread_create (new_tid_ptr,
    214                               &attr,
    215                               start_routine,
    216                               arg);
    217       pthread_attr_destroy (&attr);
    218     }
    219   }
    220   else
    221     res = pthread_create (new_tid_ptr,
    222                           NULL,
    223                           start_routine,
    224                           arg);
    225 
    226   if (0 != res)
    227   {
    228     errno = res;
    229     MHD_thread_handle_ID_set_invalid_ (handle_id);
    230   }
    231 #if ! defined(MHD_thread_handle_ID_get_native_handle_ptr_)
    232   else
    233     MHD_thread_handle_ID_set_native_handle_ (handle_id, new_tid);
    234 #endif /* ! MHD_thread_handle_ID_set_current_thread_ID_ */
    235 
    236   return ! res;
    237 #elif defined(MHD_USE_W32_THREADS)
    238   uintptr_t thr_handle;
    239 #if SIZEOF_SIZE_T != SIZEOF_UNSIGNED_INT
    240 
    241   mhd_assert (! MHD_thread_handle_ID_is_valid_handle_ (*handle_id));
    242 
    243   if (stack_size > UINT_MAX)
    244   {
    245     errno = EINVAL;
    246     return 0;
    247   }
    248 #endif /* SIZEOF_SIZE_T != SIZEOF_UNSIGNED_INT */
    249   thr_handle = (uintptr_t) _beginthreadex (NULL,
    250                                            (unsigned int) stack_size,
    251                                            start_routine,
    252                                            arg,
    253                                            0,
    254                                            NULL);
    255   if ((MHD_thread_handle_native_) 0 == (MHD_thread_handle_native_) thr_handle)
    256     return 0;
    257 
    258   MHD_thread_handle_ID_set_native_handle_ (handle_id, \
    259                                            (MHD_thread_handle_native_) \
    260                                            thr_handle);
    261 
    262   return ! 0;
    263 #endif
    264 }
    265 
    266 
    267 #ifdef MHD_USE_THREAD_NAME_
    268 
    269 #ifndef MHD_USE_THREAD_ATTR_SETNAME
    270 struct MHD_named_helper_param_
    271 {
    272   /**
    273    * Real thread start routine
    274    */
    275   MHD_THREAD_START_ROUTINE_ start_routine;
    276 
    277   /**
    278    * Argument for thread start routine
    279    */
    280   void *arg;
    281 
    282   /**
    283    * Name for thread
    284    */
    285   const char *name;
    286 };
    287 
    288 
    289 static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
    290 named_thread_starter (void *data)
    291 {
    292   struct MHD_named_helper_param_ *const param =
    293     (struct MHD_named_helper_param_ *) data;
    294   void *arg;
    295   MHD_THREAD_START_ROUTINE_ thr_func;
    296 
    297   if (NULL == data)
    298     return (MHD_THRD_RTRN_TYPE_) 0;
    299 
    300   MHD_set_cur_thread_name_ (param->name);
    301 
    302   arg = param->arg;
    303   thr_func = param->start_routine;
    304   free (data);
    305 
    306   return thr_func (arg);
    307 }
    308 
    309 
    310 #endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
    311 
    312 
    313 /**
    314  * Create a named thread and set the attributes according to our options.
    315  *
    316  * @param handle_id     handle to initialise
    317  * @param thread_name   name for new thread
    318  * @param stack_size    size of stack for new thread, 0 for default
    319  * @param start_routine main function of thread
    320  * @param arg argument  for start_routine
    321  * @return non-zero on success; zero otherwise (with errno set)
    322  */
    323 int
    324 MHD_create_named_thread_ (MHD_thread_handle_ID_ *handle_id,
    325                           const char *thread_name,
    326                           size_t stack_size,
    327                           MHD_THREAD_START_ROUTINE_ start_routine,
    328                           void *arg)
    329 {
    330 #if defined(MHD_USE_THREAD_ATTR_SETNAME)
    331   int res;
    332   pthread_attr_t attr;
    333 #if defined(MHD_thread_handle_ID_get_native_handle_ptr_)
    334   pthread_t *const new_tid_ptr =
    335     MHD_thread_handle_ID_get_native_handle_ptr_ (handle_id);
    336 #else  /* ! MHD_thread_handle_ID_get_native_handle_ptr_ */
    337   pthread_t new_tid;
    338   pthread_t *const new_tid_ptr = &new_tid;
    339 #endif /* ! MHD_thread_handle_ID_get_native_handle_ptr_ */
    340 
    341   res = pthread_attr_init (&attr);
    342   if (0 == res)
    343   {
    344 #if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD)
    345     /* NetBSD uses 3 arguments: second argument is string in printf-like format,
    346      *                          third argument is single argument for printf;
    347      * OSF1 uses 3 arguments too, but last one always must be zero (NULL).
    348      * MHD doesn't use '%' in thread names, so both forms are used in same way.
    349      */
    350     res = pthread_attr_setname_np (&attr,
    351                                    thread_name,
    352                                    0);
    353 #elif defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
    354     res = pthread_attr_setname_np (&attr,
    355                                    thread_name);
    356 #else
    357 #error No pthread_attr_setname_np() function.
    358 #endif
    359     if ((res == 0) && (0 != stack_size) )
    360       res = pthread_attr_setstacksize (&attr,
    361                                        stack_size);
    362     if (0 == res)
    363       res = pthread_create (new_tid_ptr,
    364                             &attr,
    365                             start_routine,
    366                             arg);
    367     pthread_attr_destroy (&attr);
    368   }
    369   if (0 != res)
    370   {
    371     errno = res;
    372     MHD_thread_handle_ID_set_invalid_ (handle_id);
    373   }
    374 #if ! defined(MHD_thread_handle_ID_get_native_handle_ptr_)
    375   else
    376     MHD_thread_handle_ID_set_native_handle_ (handle_id, new_tid);
    377 #endif /* ! MHD_thread_handle_ID_set_current_thread_ID_ */
    378 
    379   return ! res;
    380 #else  /* ! MHD_USE_THREAD_ATTR_SETNAME */
    381   struct MHD_named_helper_param_ *param;
    382 
    383   if (NULL == thread_name)
    384   {
    385     errno = EINVAL;
    386     return 0;
    387   }
    388 
    389   param = malloc (sizeof (struct MHD_named_helper_param_));
    390   if (NULL == param)
    391     return 0;
    392 
    393   param->start_routine = start_routine;
    394   param->arg = arg;
    395   param->name = thread_name;
    396 
    397   /* Set thread name in thread itself to avoid problems with
    398    * threads which terminated before name is set in other thread.
    399    */
    400   if (! MHD_create_thread_ (handle_id,
    401                             stack_size,
    402                             &named_thread_starter,
    403                             (void *) param))
    404   {
    405     int err_num;
    406 
    407     err_num = errno;
    408     free (param);
    409     errno = err_num;
    410     return 0;
    411   }
    412 
    413   return ! 0;
    414 #endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
    415 }
    416 
    417 
    418 #endif /* MHD_USE_THREAD_NAME_ */