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