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