GNU libmicrohttpd  0.9.29
mhd_threads.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2016 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 #include <stdlib.h>
34 #ifdef HAVE_PTHREAD_NP_H
35 #include <pthread_np.h>
36 #endif /* HAVE_PTHREAD_NP_H */
37 #endif /* MHD_USE_THREAD_NAME_ */
38 #include <errno.h>
39 
40 
41 
42 #if defined(MHD_USE_POSIX_THREADS)
43 typedef pthread_t MHD_thread_ID_;
44 #elif defined(MHD_USE_W32_THREADS)
45 typedef DWORD MHD_thread_ID_;
46 #endif
47 
48 
49 #ifndef MHD_USE_THREAD_NAME_
50 
51 #define MHD_set_thread_name_(t, n) (void)
52 #define MHD_set_cur_thread_name_(n) (void)
53 
54 #else /* MHD_USE_THREAD_NAME_ */
55 
56 #if defined(MHD_USE_POSIX_THREADS)
57 #if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
58 # define MHD_USE_THREAD_ATTR_SETNAME 1
59 #endif /* HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD || HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI */
60 
61 #if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) \
62  || defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
63 
71 static int
72 MHD_set_thread_name_(const MHD_thread_ID_ thread_id,
73  const char *thread_name)
74 {
75  if (NULL == thread_name)
76  return 0;
77 
78 #if defined(HAVE_PTHREAD_SETNAME_NP_GNU)
79  return !pthread_setname_np (thread_id, thread_name);
80 #elif defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD)
81  /* FreeBSD and OpenBSD use different name and void return type */
82  pthread_set_name_np (thread_id, thread_name);
83  return !0;
84 #elif defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
85  /* NetBSD use 3 arguments: second argument is string in printf-like format,
86  * third argument is single argument for printf;
87  * OSF1 use 3 arguments too, but last one always must be zero (NULL).
88  * MHD doesn't use '%' in thread names, so both form are used in same way.
89  */
90  return !pthread_setname_np (thread_id, thread_name, 0);
91 #endif /* HAVE_PTHREAD_SETNAME_NP_NETBSD */
92 }
93 
94 
95 #ifndef __QNXNTO__
96 
101 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(pthread_self(),(n))
102 #else /* __QNXNTO__ */
103 /* Special case for QNX Neutrino - using zero for thread ID sets name faster. */
104 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(0,(n))
105 #endif /* __QNXNTO__ */
106 #elif defined(HAVE_PTHREAD_SETNAME_NP_DARWIN)
107 
113 #define MHD_set_cur_thread_name_(n) (!(pthread_setname_np((n))))
114 #endif /* HAVE_PTHREAD_SETNAME_NP_DARWIN */
115 
116 #elif defined(MHD_USE_W32_THREADS)
117 #ifndef _MSC_FULL_VER
118 /* Thread name available only for VC-compiler */
119 #else /* _MSC_FULL_VER */
120 
127 static int
128 MHD_set_thread_name_(const MHD_thread_ID_ thread_id,
129  const char *thread_name)
130 {
131  static const DWORD VC_SETNAME_EXC = 0x406D1388;
132 #pragma pack(push,8)
133  struct thread_info_struct
134  {
135  DWORD type; /* Must be 0x1000. */
136  LPCSTR name; /* Pointer to name (in user address space). */
137  DWORD ID; /* Thread ID (-1 = caller thread). */
138  DWORD flags; /* Reserved for future use, must be zero. */
139  } thread_info;
140 #pragma pack(pop)
141 
142  if (NULL == thread_name)
143  return 0;
144 
145  thread_info.type = 0x1000;
146  thread_info.name = thread_name;
147  thread_info.ID = thread_id;
148  thread_info.flags = 0;
149 
150  __try
151  { /* This exception is intercepted by debugger */
152  RaiseException (VC_SETNAME_EXC,
153  0,
154  sizeof (thread_info) / sizeof(ULONG_PTR),
155  (ULONG_PTR *) &thread_info);
156  }
157  __except (EXCEPTION_EXECUTE_HANDLER)
158  {}
159 
160  return !0;
161 }
162 
163 
169 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(-1,(n))
170 #endif /* _MSC_FULL_VER */
171 #endif /* MHD_USE_W32_THREADS */
172 
173 #endif /* MHD_USE_THREAD_NAME_ */
174 
175 
185 int
186 MHD_create_thread_ (MHD_thread_handle_ *thread,
187  size_t stack_size,
188  MHD_THREAD_START_ROUTINE_ start_routine,
189  void *arg)
190 {
191 #if defined(MHD_USE_POSIX_THREADS)
192  int res;
193 
194  if (0 != stack_size)
195  {
196  pthread_attr_t attr;
197  res = pthread_attr_init (&attr);
198  if (0 == res)
199  {
200  res = pthread_attr_setstacksize (&attr,
201  stack_size);
202  if (0 == res)
203  res = pthread_create (thread,
204  &attr,
205  start_routine,
206  arg);
207  pthread_attr_destroy (&attr);
208  }
209  }
210  else
211  res = pthread_create (thread,
212  NULL,
213  start_routine,
214  arg);
215 
216  if (0 != res)
217  errno = res;
218 
219  return !res;
220 #elif defined(MHD_USE_W32_THREADS)
221 #if SIZE_MAX != UINT_MAX
222  if (stack_size > UINT_MAX)
223  {
224  errno = EINVAL;
225  return 0;
226  }
227 #endif /* SIZE_MAX != UINT_MAX */
228 
229  *thread = (HANDLE) _beginthreadex (NULL,
230  (unsigned int) stack_size,
231  start_routine,
232  arg,
233  0,
234  NULL);
235  if ((MHD_thread_handle_)-1 == (*thread))
236  return 0;
237 
238  return !0;
239 #endif
240 }
241 
242 #ifdef MHD_USE_THREAD_NAME_
243 
244 #ifndef MHD_USE_THREAD_ATTR_SETNAME
245 struct MHD_named_helper_param_
246 {
250  MHD_THREAD_START_ROUTINE_ start_routine;
251 
255  void *arg;
256 
260  const char *name;
261 };
262 
263 
264 static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
265 named_thread_starter (void *data)
266 {
267  struct MHD_named_helper_param_ * const param =
268  (struct MHD_named_helper_param_ *) data;
269  void * arg;
270  MHD_THREAD_START_ROUTINE_ thr_func;
271 
272  if (NULL == data)
273  return (MHD_THRD_RTRN_TYPE_)0;
274 
275  MHD_set_cur_thread_name_ (param->name);
276 
277  arg = param->arg;
278  thr_func = param->start_routine;
279  free(data);
280 
281  return thr_func(arg);
282 }
283 #endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
284 
285 
296 int
297 MHD_create_named_thread_ (MHD_thread_handle_ *thread,
298  const char* thread_name,
299  size_t stack_size,
300  MHD_THREAD_START_ROUTINE_ start_routine,
301  void *arg)
302 {
303 #if defined(MHD_USE_THREAD_ATTR_SETNAME)
304  int res;
305  pthread_attr_t attr;
306 
307  res = pthread_attr_init (&attr);
308  if (0 == res)
309  {
310 #if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD)
311  /* NetBSD use 3 arguments: second argument is string in printf-like format,
312  * third argument is single argument for printf;
313  * OSF1 use 3 arguments too, but last one always must be zero (NULL).
314  * MHD doesn't use '%' in thread names, so both form are used in same way.
315  */
316  res = pthread_attr_setname_np (&attr, thread_name, 0);
317 #elif defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
318  res = pthread_attr_setname_np (&attr, thread_name);
319 #else
320 #error No pthread_attr_setname_np() function.
321 #endif
322  if (res == 0 && 0 != stack_size)
323  res = pthread_attr_setstacksize (&attr,
324  stack_size);
325  if (0 == res)
326  res = pthread_create (thread,
327  &attr,
328  start_routine,
329  arg);
330  pthread_attr_destroy (&attr);
331  }
332  if (0 != res)
333  errno = res;
334 
335  return !res;
336 #else /* ! MHD_USE_THREAD_ATTR_SETNAME */
337  struct MHD_named_helper_param_ *param;
338 
339  if (NULL == thread_name)
340  {
341  errno = EINVAL;
342  return 0;
343  }
344 
345  param = malloc (sizeof (struct MHD_named_helper_param_));
346  if (NULL == param)
347  return 0;
348 
349  param->start_routine = start_routine;
350  param->arg = arg;
351  param->name = thread_name;
352 
353  /* Set thread name in thread itself to avoid problems with
354  * threads which terminated before name is set in other thread.
355  */
356  if (! MHD_create_thread_(thread,
357  stack_size,
358  &named_thread_starter,
359  (void*)param))
360  {
361  free (param);
362  return 0;
363  }
364 
365  return !0;
366 #endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
367 }
368 
369 #endif /* MHD_USE_THREAD_NAME_ */
#define MHD_set_thread_name_(t, n)
Definition: mhd_threads.c:51
#define NULL
Definition: reason_phrase.c:31
int MHD_create_thread_(MHD_thread_handle_ *thread, size_t stack_size, MHD_THREAD_START_ROUTINE_ start_routine, void *arg)
Definition: mhd_threads.c:186
#define MHD_create_named_thread_(t, n, s, r, a)
Definition: mhd_threads.h:132
#define MHD_set_cur_thread_name_(n)
Definition: mhd_threads.c:52
limits values definitions
Header for platform-independent threads abstraction.
MHD_THRD_RTRN_TYPE_(MHD_THRD_CALL_SPEC_ * MHD_THREAD_START_ROUTINE_)(void *cls)
Definition: mhd_threads.h:111
#define UINT_MAX
Definition: mhd_limits.h:39