aboutsummaryrefslogtreecommitdiff
path: root/src/lib/mhd_threads.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/mhd_threads.c')
-rw-r--r--src/lib/mhd_threads.c363
1 files changed, 363 insertions, 0 deletions
diff --git a/src/lib/mhd_threads.c b/src/lib/mhd_threads.c
new file mode 100644
index 00000000..6578e4b1
--- /dev/null
+++ b/src/lib/mhd_threads.c
@@ -0,0 +1,363 @@
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
21/**
22 * @file microhttpd/mhd_threads.c
23 * @brief Implementation for thread functions
24 * @author Karlson2k (Evgeny Grin)
25 */
26
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
56/**
57 * Set thread name
58 *
59 * @param thread_id ID of thread
60 * @param thread_name name to set
61 * @return non-zero on success, zero otherwise
62 */
63static int
64MHD_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/**
89 * Set current thread name
90 * @param n name to set
91 * @return non-zero on success, zero otherwise
92 */
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
100/**
101 * Set current thread name
102 * @param n name to set
103 * @return non-zero on success, zero otherwise
104 */
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/**
113 * Set thread name
114 *
115 * @param thread_id ID of thread, -1 for current thread
116 * @param thread_name name to set
117 * @return non-zero on success, zero otherwise
118 */
119static int
120MHD_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
156/**
157 * Set current thread name
158 * @param n name to set
159 * @return non-zero on success, zero otherwise
160 */
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
168/**
169 * Create a thread and set the attributes according to our options.
170 *
171 * @param thread handle to initialize
172 * @param stack_size size of stack for new thread, 0 for default
173 * @param start_routine main function of thread
174 * @param arg argument for start_routine
175 * @return non-zero on success; zero otherwise (with errno set)
176 */
177int
178MHD_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
239struct MHD_named_helper_param_
240{
241 /**
242 * Real thread start routine
243 */
244 MHD_THREAD_START_ROUTINE_ start_routine;
245
246 /**
247 * Argument for thread start routine
248 */
249 void *arg;
250
251 /**
252 * Name for thread
253 */
254 const char *name;
255};
256
257
258static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
259named_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
280/**
281 * Create a named thread and set the attributes according to our options.
282 *
283 * @param thread handle to initialize
284 * @param thread_name name for new thread
285 * @param stack_size size of stack for new thread, 0 for default
286 * @param start_routine main function of thread
287 * @param arg argument for start_routine
288 * @return non-zero on success; zero otherwise (with errno set)
289 */
290int
291MHD_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_ */