GNU libmicrohttpd 1.0.0
Loading...
Searching...
No Matches
mhd_threads.c
Go to the documentation of this file.
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
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
69static int
70MHD_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__
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
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 */
125static int
126MHD_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
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
186int
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
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;
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
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
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
270struct MHD_named_helper_param_
271{
275 MHD_THREAD_START_ROUTINE_ start_routine;
276
280 void *arg;
281
285 const char *name;
286};
287
288
289static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
290named_thread_starter (void *data)
291{
292 struct MHD_named_helper_param_ *const param =
293 (struct MHD_named_helper_param_ *) data;
294 void *arg;
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
323int
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;
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_ */
#define mhd_assert(CHK)
Definition mhd_assert.h:39
#define UINT_MAX
Definition mhd_limits.h:45
int MHD_create_thread_(MHD_thread_handle_ID_ *thread, size_t stack_size, MHD_THREAD_START_ROUTINE_ start_routine, void *arg)
#define MHD_set_cur_thread_name_(n)
Definition mhd_threads.c:44
#define MHD_set_thread_name_(t, n)
Definition mhd_threads.c:43
MHD_THRD_RTRN_TYPE_(MHD_THRD_CALL_SPEC_ * MHD_THREAD_START_ROUTINE_)(void *cls)
#define MHD_create_named_thread_(t, n, s, r, a)
#define NULL
macros for mhd_assert()
Header for platform-independent threads abstraction.
#define MHD_thread_handle_ID_is_valid_handle_(hndl_id)
#define MHD_thread_handle_ID_set_native_handle_(hndl_id_ptr, native_val)
#define MHD_thread_handle_ID_set_invalid_(hndl_id_ptr)
void * data