GNU libmicrohttpd  0.9.70
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 #ifndef MHD_USE_THREAD_NAME_
42 
43 #define MHD_set_thread_name_(t, n) (void)
44 #define MHD_set_cur_thread_name_(n) (void)
45 
46 #else /* MHD_USE_THREAD_NAME_ */
47 
48 #if defined(MHD_USE_POSIX_THREADS)
49 #if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || \
50  defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
51 # define MHD_USE_THREAD_ATTR_SETNAME 1
52 #endif /* HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD || HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI */
53 
54 #if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || \
55  defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) \
56  || defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
57 
65 static int
66 MHD_set_thread_name_ (const MHD_thread_ID_ thread_id,
67  const char *thread_name)
68 {
69  if (NULL == thread_name)
70  return 0;
71 
72 #if defined(HAVE_PTHREAD_SETNAME_NP_GNU)
73  return ! pthread_setname_np (thread_id, thread_name);
74 #elif defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD)
75  /* FreeBSD and OpenBSD use different name and void return type */
76  pthread_set_name_np (thread_id, thread_name);
77  return ! 0;
78 #elif defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
79  /* NetBSD use 3 arguments: second argument is string in printf-like format,
80  * third argument is single argument for printf;
81  * OSF1 use 3 arguments too, but last one always must be zero (NULL).
82  * MHD doesn't use '%' in thread names, so both form are used in same way.
83  */return ! pthread_setname_np (thread_id, thread_name, 0);
84 #endif /* HAVE_PTHREAD_SETNAME_NP_NETBSD */
85 }
86 
87 
88 #ifndef __QNXNTO__
89 
94 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (pthread_self (),(n))
95 #else /* __QNXNTO__ */
96 /* Special case for QNX Neutrino - using zero for thread ID sets name faster. */
97 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (0,(n))
98 #endif /* __QNXNTO__ */
99 #elif defined(HAVE_PTHREAD_SETNAME_NP_DARWIN)
100 
106 #define MHD_set_cur_thread_name_(n) (! (pthread_setname_np ((n))))
107 #endif /* HAVE_PTHREAD_SETNAME_NP_DARWIN */
108 
109 #elif defined(MHD_USE_W32_THREADS)
110 #ifndef _MSC_FULL_VER
111 /* Thread name available only for VC-compiler */
112 #else /* _MSC_FULL_VER */
113 
120 static int
121 MHD_set_thread_name_ (const MHD_thread_ID_ thread_id,
122  const char *thread_name)
123 {
124  static const DWORD VC_SETNAME_EXC = 0x406D1388;
125 #pragma pack(push,8)
126  struct thread_info_struct
127  {
128  DWORD type; /* Must be 0x1000. */
129  LPCSTR name; /* Pointer to name (in user address space). */
130  DWORD ID; /* Thread ID (-1 = caller thread). */
131  DWORD flags; /* Reserved for future use, must be zero. */
132  } thread_info;
133 #pragma pack(pop)
134 
135  if (NULL == thread_name)
136  return 0;
137 
138  thread_info.type = 0x1000;
139  thread_info.name = thread_name;
140  thread_info.ID = thread_id;
141  thread_info.flags = 0;
142 
143  __try
144  { /* This exception is intercepted by debugger */
145  RaiseException (VC_SETNAME_EXC,
146  0,
147  sizeof (thread_info) / sizeof(ULONG_PTR),
148  (ULONG_PTR *) &thread_info);
149  }
150  __except (EXCEPTION_EXECUTE_HANDLER)
151  {}
152 
153  return ! 0;
154 }
155 
156 
162 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (-1,(n))
163 #endif /* _MSC_FULL_VER */
164 #endif /* MHD_USE_W32_THREADS */
165 
166 #endif /* MHD_USE_THREAD_NAME_ */
167 
168 
178 int
179 MHD_create_thread_ (MHD_thread_handle_ID_ *thread,
180  size_t stack_size,
181  MHD_THREAD_START_ROUTINE_ start_routine,
182  void *arg)
183 {
184 #if defined(MHD_USE_POSIX_THREADS)
185  int res;
186 
187  if (0 != stack_size)
188  {
189  pthread_attr_t attr;
190  res = pthread_attr_init (&attr);
191  if (0 == res)
192  {
193  res = pthread_attr_setstacksize (&attr,
194  stack_size);
195  if (0 == res)
196  res = pthread_create (&(thread->handle),
197  &attr,
198  start_routine,
199  arg);
200  pthread_attr_destroy (&attr);
201  }
202  }
203  else
204  res = pthread_create (&(thread->handle),
205  NULL,
206  start_routine,
207  arg);
208 
209  if (0 != res)
210  errno = res;
211 
212  return ! res;
213 #elif defined(MHD_USE_W32_THREADS)
214 #if SIZE_MAX != UINT_MAX
215  if (stack_size > UINT_MAX)
216  {
217  errno = EINVAL;
218  return 0;
219  }
220 #endif /* SIZE_MAX != UINT_MAX */
221 
222  thread->handle = (MHD_thread_handle_)
223  _beginthreadex (NULL,
224  (unsigned int) stack_size,
225  start_routine,
226  arg,
227  0,
228  NULL);
229 
230  if ((MHD_thread_handle_) - 1 == thread->handle)
231  return 0;
232 
233  return ! 0;
234 #endif
235 }
236 
237 
238 #ifdef MHD_USE_THREAD_NAME_
239 
240 #ifndef MHD_USE_THREAD_ATTR_SETNAME
241 struct MHD_named_helper_param_
242 {
246  MHD_THREAD_START_ROUTINE_ start_routine;
247 
251  void *arg;
252 
256  const char *name;
257 };
258 
259 
260 static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
261 named_thread_starter (void *data)
262 {
263  struct MHD_named_helper_param_ *const param =
264  (struct MHD_named_helper_param_ *) data;
265  void *arg;
266  MHD_THREAD_START_ROUTINE_ thr_func;
267 
268  if (NULL == data)
269  return (MHD_THRD_RTRN_TYPE_) 0;
270 
271  MHD_set_cur_thread_name_ (param->name);
272 
273  arg = param->arg;
274  thr_func = param->start_routine;
275  free (data);
276 
277  return thr_func (arg);
278 }
279 
280 
281 #endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
282 
283 
294 int
295 MHD_create_named_thread_ (MHD_thread_handle_ID_ *thread,
296  const char*thread_name,
297  size_t stack_size,
298  MHD_THREAD_START_ROUTINE_ start_routine,
299  void *arg)
300 {
301 #if defined(MHD_USE_THREAD_ATTR_SETNAME)
302  int res;
303  pthread_attr_t attr;
304 
305  res = pthread_attr_init (&attr);
306  if (0 == res)
307  {
308 #if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD)
309  /* NetBSD use 3 arguments: second argument is string in printf-like format,
310  * third argument is single argument for printf;
311  * OSF1 use 3 arguments too, but last one always must be zero (NULL).
312  * MHD doesn't use '%' in thread names, so both form are used in same way.
313  */res = pthread_attr_setname_np (&attr,
314  thread_name,
315  0);
316 #elif defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
317  res = pthread_attr_setname_np (&attr,
318  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->handle),
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 
370 #endif /* MHD_USE_THREAD_NAME_ */
#define UINT_MAX
Definition: mhd_limits.h:45
void * data
Definition: microhttpd.h:3029
#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)
Definition: mhd_threads.h:195
#define NULL
Definition: reason_phrase.c:30
#define MHD_set_cur_thread_name_(n)
Definition: mhd_threads.c:44
#define MHD_create_named_thread_(t, n, s, r, a)
Definition: mhd_threads.h:216
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:179
Header for platform-independent threads abstraction.