GNU libmicrohttpd  1.0.1
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 
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__
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 */
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 
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 
186 int
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
270 struct MHD_named_helper_param_
271 {
275  MHD_THREAD_START_ROUTINE_ start_routine;
276 
280  void *arg;
281 
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 
323 int
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)
Definition: mhd_threads.c:180
MHD_THRD_RTRN_TYPE_(MHD_THRD_CALL_SPEC_ * MHD_THREAD_START_ROUTINE_)(void *cls)
Definition: mhd_threads.h:195
#define MHD_create_named_thread_(t, n, s, r, a)
Definition: mhd_threads.h:216
#define NULL
Definition: reason_phrase.c:30
macros for mhd_assert()
#define MHD_set_cur_thread_name_(n)
Definition: mhd_threads.c:47
#define MHD_set_thread_name_(t, n)
Definition: mhd_threads.c:46
Header for platform-independent threads abstraction.
#define MHD_thread_handle_ID_is_valid_handle_(hndl_id)
Definition: mhd_threads.h:444
#define MHD_thread_handle_ID_set_native_handle_(hndl_id_ptr, native_val)
Definition: mhd_threads.h:451
#define MHD_thread_handle_ID_set_invalid_(hndl_id_ptr)
Definition: mhd_threads.h:436
void * data
Definition: microhttpd.h:3968