diff options
Diffstat (limited to 'src/lib/mhd_threads.c')
-rw-r--r-- | src/lib/mhd_threads.c | 363 |
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 | */ | ||
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 | /** | ||
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 | */ | ||
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 | |||
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 | */ | ||
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 | { | ||
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 | |||
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 | |||
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 | */ | ||
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_ */ | ||