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