GNU libmicrohttpd  0.9.76
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 #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 
42 
43 #ifndef MHD_USE_THREAD_NAME_
44 
45 #define MHD_set_thread_name_(t, n) (void)
46 #define MHD_set_cur_thread_name_(n) (void)
47 
48 #else /* MHD_USE_THREAD_NAME_ */
49 
50 #if defined(MHD_USE_POSIX_THREADS)
51 #if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || \
52  defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
53 # define MHD_USE_THREAD_ATTR_SETNAME 1
54 #endif /* HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD || \
55  HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI */
56 
57 #if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || \
58  defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) \
59  || defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
60 
68 static int
69 MHD_set_thread_name_ (const MHD_thread_ID_ thread_id,
70  const char *thread_name)
71 {
72  if (NULL == thread_name)
73  return 0;
74 
75 #if defined(HAVE_PTHREAD_SETNAME_NP_GNU)
76  return ! pthread_setname_np (thread_id, thread_name);
77 #elif defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD)
78  /* FreeBSD and OpenBSD use different function name and void return type */
79  pthread_set_name_np (thread_id, thread_name);
80  return ! 0;
81 #elif defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
82  /* NetBSD use 3 arguments: second argument is string in printf-like format,
83  * third argument is a single argument for printf();
84  * OSF1 use 3 arguments too, but last one always must be zero (NULL).
85  * MHD doesn't use '%' in thread names, so both form are used in same way.
86  */
87  return ! pthread_setname_np (thread_id, thread_name, 0);
88 #endif /* HAVE_PTHREAD_SETNAME_NP_NETBSD */
89 }
90 
91 
92 #ifndef __QNXNTO__
98 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (pthread_self (),(n))
99 #else /* __QNXNTO__ */
100 /* Special case for QNX Neutrino - using zero for thread ID sets name faster. */
101 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (0,(n))
102 #endif /* __QNXNTO__ */
103 #elif defined(HAVE_PTHREAD_SETNAME_NP_DARWIN)
104 
110 #define MHD_set_cur_thread_name_(n) (! (pthread_setname_np ((n))))
111 #endif /* HAVE_PTHREAD_SETNAME_NP_DARWIN */
112 
113 #elif defined(MHD_USE_W32_THREADS)
114 #ifndef _MSC_FULL_VER
115 /* Thread name available only for VC-compiler */
116 #else /* _MSC_FULL_VER */
124 static int
125 MHD_set_thread_name_ (const MHD_thread_ID_ thread_id,
126  const char *thread_name)
127 {
128  static const DWORD VC_SETNAME_EXC = 0x406D1388;
129 #pragma pack(push,8)
130  struct thread_info_struct
131  {
132  DWORD type; /* Must be 0x1000. */
133  LPCSTR name; /* Pointer to name (in user address space). */
134  DWORD ID; /* Thread ID (-1 = caller thread). */
135  DWORD flags; /* Reserved for future use, must be zero. */
136  } thread_info;
137 #pragma pack(pop)
138 
139  if (NULL == thread_name)
140  return 0;
141 
142  thread_info.type = 0x1000;
143  thread_info.name = thread_name;
144  thread_info.ID = thread_id;
145  thread_info.flags = 0;
146 
147  __try
148  { /* This exception is intercepted by debugger */
149  RaiseException (VC_SETNAME_EXC,
150  0,
151  sizeof (thread_info) / sizeof(ULONG_PTR),
152  (ULONG_PTR *) &thread_info);
153  }
154  __except (EXCEPTION_EXECUTE_HANDLER)
155  {}
156 
157  return ! 0;
158 }
159 
160 
166 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (-1,(n))
167 #endif /* _MSC_FULL_VER */
168 #endif /* MHD_USE_W32_THREADS */
169 
170 #endif /* MHD_USE_THREAD_NAME_ */
171 
172 
182 int
183 MHD_create_thread_ (MHD_thread_handle_ID_ *thread,
184  size_t stack_size,
185  MHD_THREAD_START_ROUTINE_ start_routine,
186  void *arg)
187 {
188 #if defined(MHD_USE_POSIX_THREADS)
189  int res;
190 
191  if (0 != stack_size)
192  {
193  pthread_attr_t attr;
194  res = pthread_attr_init (&attr);
195  if (0 == res)
196  {
197  res = pthread_attr_setstacksize (&attr,
198  stack_size);
199  if (0 == res)
200  res = pthread_create (&(thread->handle),
201  &attr,
202  start_routine,
203  arg);
204  pthread_attr_destroy (&attr);
205  }
206  }
207  else
208  res = pthread_create (&(thread->handle),
209  NULL,
210  start_routine,
211  arg);
212 
213  if (0 != res)
214  errno = res;
215 
216  return ! res;
217 #elif defined(MHD_USE_W32_THREADS)
218 #if SIZEOF_SIZE_T != SIZEOF_UNSIGNED_INT
219  if (stack_size > UINT_MAX)
220  {
221  errno = EINVAL;
222  return 0;
223  }
224 #endif /* SIZEOF_SIZE_T != SIZEOF_UNSIGNED_INT */
225 
226  thread->handle = (MHD_thread_handle_)
227  _beginthreadex (NULL,
228  (unsigned int) stack_size,
229  start_routine,
230  arg,
231  0,
232  NULL);
233 
234  if ((MHD_thread_handle_) - 1 == thread->handle)
235  return 0;
236 
237  return ! 0;
238 #endif
239 }
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 
284 
285 #endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
286 
287 
298 int
299 MHD_create_named_thread_ (MHD_thread_handle_ID_ *thread,
300  const char *thread_name,
301  size_t stack_size,
302  MHD_THREAD_START_ROUTINE_ start_routine,
303  void *arg)
304 {
305 #if defined(MHD_USE_THREAD_ATTR_SETNAME)
306  int res;
307  pthread_attr_t attr;
308 
309  res = pthread_attr_init (&attr);
310  if (0 == res)
311  {
312 #if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD)
313  /* NetBSD use 3 arguments: second argument is string in printf-like format,
314  * third argument is single argument for printf;
315  * OSF1 use 3 arguments too, but last one always must be zero (NULL).
316  * MHD doesn't use '%' in thread names, so both form are used in same way.
317  */
318  res = pthread_attr_setname_np (&attr,
319  thread_name,
320  0);
321 #elif defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
322  res = pthread_attr_setname_np (&attr,
323  thread_name);
324 #else
325 #error No pthread_attr_setname_np() function.
326 #endif
327  if ((res == 0) && (0 != stack_size) )
328  res = pthread_attr_setstacksize (&attr,
329  stack_size);
330  if (0 == res)
331  res = pthread_create (&(thread->handle),
332  &attr,
333  start_routine,
334  arg);
335  pthread_attr_destroy (&attr);
336  }
337  if (0 != res)
338  errno = res;
339 
340  return ! res;
341 #else /* ! MHD_USE_THREAD_ATTR_SETNAME */
342  struct MHD_named_helper_param_ *param;
343 
344  if (NULL == thread_name)
345  {
346  errno = EINVAL;
347  return 0;
348  }
349 
350  param = malloc (sizeof (struct MHD_named_helper_param_));
351  if (NULL == param)
352  return 0;
353 
354  param->start_routine = start_routine;
355  param->arg = arg;
356  param->name = thread_name;
357 
358  /* Set thread name in thread itself to avoid problems with
359  * threads which terminated before name is set in other thread.
360  */
361  if (! MHD_create_thread_ (thread,
362  stack_size,
363  &named_thread_starter,
364  (void *) param))
365  {
366  free (param);
367  return 0;
368  }
369 
370  return ! 0;
371 #endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
372 }
373 
374 
375 #endif /* MHD_USE_THREAD_NAME_ */
#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
#define MHD_set_cur_thread_name_(n)
Definition: mhd_threads.c:46
#define MHD_set_thread_name_(t, n)
Definition: mhd_threads.c:45
Header for platform-independent threads abstraction.
void * data
Definition: microhttpd.h:3428