GNU libmicrohttpd  0.9.72
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 \
53  /* HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD || HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI */
54 
55 #if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || \
56  defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) \
57  || defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
58 
66 static int
67 MHD_set_thread_name_ (const MHD_thread_ID_ thread_id,
68  const char *thread_name)
69 {
70  if (NULL == thread_name)
71  return 0;
72 
73 #if defined(HAVE_PTHREAD_SETNAME_NP_GNU)
74  return ! pthread_setname_np (thread_id, thread_name);
75 #elif defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD)
76  /* FreeBSD and OpenBSD use different name and void return type */
77  pthread_set_name_np (thread_id, thread_name);
78  return ! 0;
79 #elif defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
80  /* NetBSD use 3 arguments: second argument is string in printf-like format,
81  * third argument is single argument for printf;
82  * OSF1 use 3 arguments too, but last one always must be zero (NULL).
83  * MHD doesn't use '%' in thread names, so both form are used in same way.
84  */return ! pthread_setname_np (thread_id, thread_name, 0);
85 #endif /* HAVE_PTHREAD_SETNAME_NP_NETBSD */
86 }
87 
88 
89 #ifndef __QNXNTO__
95 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (pthread_self (),(n))
96 #else /* __QNXNTO__ */
97 /* Special case for QNX Neutrino - using zero for thread ID sets name faster. */
98 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (0,(n))
99 #endif /* __QNXNTO__ */
100 #elif defined(HAVE_PTHREAD_SETNAME_NP_DARWIN)
101 
107 #define MHD_set_cur_thread_name_(n) (! (pthread_setname_np ((n))))
108 #endif /* HAVE_PTHREAD_SETNAME_NP_DARWIN */
109 
110 #elif defined(MHD_USE_W32_THREADS)
111 #ifndef _MSC_FULL_VER
112 /* Thread name available only for VC-compiler */
113 #else /* _MSC_FULL_VER */
121 static int
122 MHD_set_thread_name_ (const MHD_thread_ID_ thread_id,
123  const char *thread_name)
124 {
125  static const DWORD VC_SETNAME_EXC = 0x406D1388;
126 #pragma pack(push,8)
127  struct thread_info_struct
128  {
129  DWORD type; /* Must be 0x1000. */
130  LPCSTR name; /* Pointer to name (in user address space). */
131  DWORD ID; /* Thread ID (-1 = caller thread). */
132  DWORD flags; /* Reserved for future use, must be zero. */
133  } thread_info;
134 #pragma pack(pop)
135 
136  if (NULL == thread_name)
137  return 0;
138 
139  thread_info.type = 0x1000;
140  thread_info.name = thread_name;
141  thread_info.ID = thread_id;
142  thread_info.flags = 0;
143 
144  __try
145  { /* This exception is intercepted by debugger */
146  RaiseException (VC_SETNAME_EXC,
147  0,
148  sizeof (thread_info) / sizeof(ULONG_PTR),
149  (ULONG_PTR *) &thread_info);
150  }
151  __except (EXCEPTION_EXECUTE_HANDLER)
152  {}
153 
154  return ! 0;
155 }
156 
157 
163 #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (-1,(n))
164 #endif /* _MSC_FULL_VER */
165 #endif /* MHD_USE_W32_THREADS */
166 
167 #endif /* MHD_USE_THREAD_NAME_ */
168 
169 
179 int
180 MHD_create_thread_ (MHD_thread_handle_ID_ *thread,
181  size_t stack_size,
182  MHD_THREAD_START_ROUTINE_ start_routine,
183  void *arg)
184 {
185 #if defined(MHD_USE_POSIX_THREADS)
186  int res;
187 
188  if (0 != stack_size)
189  {
190  pthread_attr_t attr;
191  res = pthread_attr_init (&attr);
192  if (0 == res)
193  {
194  res = pthread_attr_setstacksize (&attr,
195  stack_size);
196  if (0 == res)
197  res = pthread_create (&(thread->handle),
198  &attr,
199  start_routine,
200  arg);
201  pthread_attr_destroy (&attr);
202  }
203  }
204  else
205  res = pthread_create (&(thread->handle),
206  NULL,
207  start_routine,
208  arg);
209 
210  if (0 != res)
211  errno = res;
212 
213  return ! res;
214 #elif defined(MHD_USE_W32_THREADS)
215 #if SIZE_MAX != UINT_MAX
216  if (stack_size > UINT_MAX)
217  {
218  errno = EINVAL;
219  return 0;
220  }
221 #endif /* SIZE_MAX != UINT_MAX */
222 
223  thread->handle = (MHD_thread_handle_)
224  _beginthreadex (NULL,
225  (unsigned int) stack_size,
226  start_routine,
227  arg,
228  0,
229  NULL);
230 
231  if ((MHD_thread_handle_) - 1 == thread->handle)
232  return 0;
233 
234  return ! 0;
235 #endif
236 }
237 
238 
239 #ifdef MHD_USE_THREAD_NAME_
240 
241 #ifndef MHD_USE_THREAD_ATTR_SETNAME
242 struct MHD_named_helper_param_
243 {
247  MHD_THREAD_START_ROUTINE_ start_routine;
248 
252  void *arg;
253 
257  const char *name;
258 };
259 
260 
261 static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
262 named_thread_starter (void *data)
263 {
264  struct MHD_named_helper_param_ *const param =
265  (struct MHD_named_helper_param_ *) data;
266  void *arg;
267  MHD_THREAD_START_ROUTINE_ thr_func;
268 
269  if (NULL == data)
270  return (MHD_THRD_RTRN_TYPE_) 0;
271 
272  MHD_set_cur_thread_name_ (param->name);
273 
274  arg = param->arg;
275  thr_func = param->start_routine;
276  free (data);
277 
278  return thr_func (arg);
279 }
280 
281 
282 #endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
283 
284 
295 int
296 MHD_create_named_thread_ (MHD_thread_handle_ID_ *thread,
297  const char*thread_name,
298  size_t stack_size,
299  MHD_THREAD_START_ROUTINE_ start_routine,
300  void *arg)
301 {
302 #if defined(MHD_USE_THREAD_ATTR_SETNAME)
303  int res;
304  pthread_attr_t attr;
305 
306  res = pthread_attr_init (&attr);
307  if (0 == res)
308  {
309 #if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD)
310  /* NetBSD use 3 arguments: second argument is string in printf-like format,
311  * third argument is single argument for printf;
312  * OSF1 use 3 arguments too, but last one always must be zero (NULL).
313  * MHD doesn't use '%' in thread names, so both form are used in same way.
314  */res = pthread_attr_setname_np (&attr, thread_name, 0);
315 #elif defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
316  res = pthread_attr_setname_np (&attr, thread_name);
317 #else
318 #error No pthread_attr_setname_np() function.
319 #endif
320  if ((res == 0) && (0 != stack_size) )
321  res = pthread_attr_setstacksize (&attr,
322  stack_size);
323  if (0 == res)
324  res = pthread_create (&(thread->handle),
325  &attr,
326  start_routine,
327  arg);
328  pthread_attr_destroy (&attr);
329  }
330  if (0 != res)
331  errno = res;
332 
333  return ! res;
334 #else /* ! MHD_USE_THREAD_ATTR_SETNAME */
335  struct MHD_named_helper_param_ *param;
336 
337  if (NULL == thread_name)
338  {
339  errno = EINVAL;
340  return 0;
341  }
342 
343  param = malloc (sizeof (struct MHD_named_helper_param_));
344  if (NULL == param)
345  return 0;
346 
347  param->start_routine = start_routine;
348  param->arg = arg;
349  param->name = thread_name;
350 
351  /* Set thread name in thread itself to avoid problems with
352  * threads which terminated before name is set in other thread.
353  */
354  if (! MHD_create_thread_ (thread,
355  stack_size,
356  &named_thread_starter,
357  (void*) param))
358  {
359  free (param);
360  return 0;
361  }
362 
363  return ! 0;
364 #endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
365 }
366 
367 
368 #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
#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)
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
Header for platform-independent threads abstraction.
void * data
Definition: microhttpd.h:3053