diff options
Diffstat (limited to 'src/microhttpd/mhd_threads.c')
-rw-r--r-- | src/microhttpd/mhd_threads.c | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/src/microhttpd/mhd_threads.c b/src/microhttpd/mhd_threads.c new file mode 100644 index 00000000..07da4960 --- /dev/null +++ b/src/microhttpd/mhd_threads.c | |||
@@ -0,0 +1,274 @@ | |||
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 | #endif /* MHD_USE_THREAD_NAME_ */ | ||
35 | #include <errno.h> | ||
36 | |||
37 | |||
38 | |||
39 | #if defined(MHD_USE_POSIX_THREADS) | ||
40 | typedef pthread_t MHD_thread_ID_; | ||
41 | #elif defined(MHD_USE_W32_THREADS) | ||
42 | typedef DWORD MHD_thread_ID_; | ||
43 | #endif | ||
44 | |||
45 | |||
46 | #ifndef MHD_USE_THREAD_NAME_ | ||
47 | |||
48 | #define MHD_set_thread_name_(t, n) (void) | ||
49 | #define MHD_set_cur_thread_name_(n) (void) | ||
50 | |||
51 | #else /* MHD_USE_THREAD_NAME_ */ | ||
52 | |||
53 | #if defined(MHD_USE_POSIX_THREADS) | ||
54 | #ifdef HAVE_PTHREAD_SETNAME_NP | ||
55 | /** | ||
56 | * Set thread name | ||
57 | * @param thread_id ID of thread | ||
58 | * @param thread_name name to set | ||
59 | * @return non-zero on success, zero otherwise | ||
60 | */ | ||
61 | static int MHD_set_thread_name_(const MHD_thread_ID_ thread_id, const char *thread_name) | ||
62 | { | ||
63 | if (NULL == thread_name) | ||
64 | return 0; | ||
65 | |||
66 | return !pthread_setname_np (thread_id, thread_name); | ||
67 | } | ||
68 | |||
69 | /** | ||
70 | * Set current thread name | ||
71 | * @param n name to set | ||
72 | * @return non-zero on success, zero otherwise | ||
73 | */ | ||
74 | #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(pthread_self(),(n)) | ||
75 | #endif /* HAVE_PTHREAD_SETNAME_NP */ | ||
76 | |||
77 | #elif defined(MHD_USE_W32_THREADS) | ||
78 | #ifndef _MSC_FULL_VER | ||
79 | /* Thread name available only for VC-compiler */ | ||
80 | #else /* _MSC_FULL_VER */ | ||
81 | /** | ||
82 | * Set thread name | ||
83 | * @param thread_id ID of thread, -1 for current thread | ||
84 | * @param thread_name name to set | ||
85 | * @return non-zero on success, zero otherwise | ||
86 | */ | ||
87 | static int MHD_set_thread_name_(const MHD_thread_ID_ thread_id, const char *thread_name) | ||
88 | { | ||
89 | static const DWORD VC_SETNAME_EXC = 0x406D1388; | ||
90 | #pragma pack(push,8) | ||
91 | struct thread_info_struct | ||
92 | { | ||
93 | DWORD type; /* Must be 0x1000. */ | ||
94 | LPCSTR name; /* Pointer to name (in user address space). */ | ||
95 | DWORD ID; /* Thread ID (-1 = caller thread). */ | ||
96 | DWORD flags; /* Reserved for future use, must be zero. */ | ||
97 | } thread_info; | ||
98 | #pragma pack(pop) | ||
99 | |||
100 | if (NULL == thread_name) | ||
101 | return 0; | ||
102 | |||
103 | thread_info.type = 0x1000; | ||
104 | thread_info.name = thread_name; | ||
105 | thread_info.ID = thread_id; | ||
106 | thread_info.flags = 0; | ||
107 | |||
108 | __try | ||
109 | { /* This exception is intercepted by debugger */ | ||
110 | RaiseException(VC_SETNAME_EXC, 0, sizeof(thread_info) / sizeof(ULONG_PTR), (ULONG_PTR*)&thread_info); | ||
111 | } | ||
112 | __except (EXCEPTION_EXECUTE_HANDLER) | ||
113 | {} | ||
114 | |||
115 | return !0; | ||
116 | } | ||
117 | |||
118 | |||
119 | /** | ||
120 | * Set current thread name | ||
121 | * @param n name to set | ||
122 | * @return non-zero on success, zero otherwise | ||
123 | */ | ||
124 | #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(-1,(n)) | ||
125 | #endif /* _MSC_FULL_VER */ | ||
126 | #endif /* MHD_USE_W32_THREADS */ | ||
127 | |||
128 | #endif /* MHD_USE_THREAD_NAME_ */ | ||
129 | |||
130 | |||
131 | /** | ||
132 | * Create a thread and set the attributes according to our options. | ||
133 | * | ||
134 | * @param thread handle to initialize | ||
135 | * @param stack_size size of stack for new thread, 0 for default | ||
136 | * @param start_routine main function of thread | ||
137 | * @param arg argument for start_routine | ||
138 | * @return non-zero on success; zero otherwise (with errno set) | ||
139 | */ | ||
140 | int | ||
141 | MHD_create_thread_ (MHD_thread_handle_ *thread, | ||
142 | size_t stack_size, | ||
143 | MHD_THREAD_START_ROUTINE_ start_routine, | ||
144 | void *arg) | ||
145 | { | ||
146 | #if defined(MHD_USE_POSIX_THREADS) | ||
147 | int res; | ||
148 | |||
149 | if (0 != stack_size) | ||
150 | { | ||
151 | pthread_attr_t attr; | ||
152 | res = pthread_attr_init (&attr); | ||
153 | if (0 == res) | ||
154 | { | ||
155 | res = pthread_attr_setstacksize (&attr, stack_size); | ||
156 | if (0 == res) | ||
157 | res = pthread_create (thread, &attr, | ||
158 | start_routine, arg); | ||
159 | pthread_attr_destroy (&attr); | ||
160 | } | ||
161 | } | ||
162 | else | ||
163 | res = pthread_create (thread, NULL, start_routine, arg); | ||
164 | |||
165 | if (0 != res) | ||
166 | errno = res; | ||
167 | |||
168 | return !res; | ||
169 | #elif defined(MHD_USE_W32_THREADS) | ||
170 | #if SIZE_MAX != UINT_MAX | ||
171 | if (stack_size > UINT_MAX) | ||
172 | { | ||
173 | errno = EINVAL; | ||
174 | return 0; | ||
175 | } | ||
176 | #endif /* SIZE_MAX != UINT_MAX */ | ||
177 | |||
178 | *thread = (HANDLE)_beginthreadex(NULL, (unsigned)stack_size, start_routine, | ||
179 | arg, 0, NULL); | ||
180 | if ((MHD_thread_handle_)-1 == (*thread)) | ||
181 | return 0; | ||
182 | |||
183 | return !0; | ||
184 | #endif | ||
185 | } | ||
186 | |||
187 | #ifdef MHD_USE_THREAD_NAME_ | ||
188 | |||
189 | struct MHD_named_helper_param_ | ||
190 | { | ||
191 | /** | ||
192 | * Real thread start routine | ||
193 | */ | ||
194 | MHD_THREAD_START_ROUTINE_ start_routine; | ||
195 | |||
196 | /** | ||
197 | * Argument for thread start routine | ||
198 | */ | ||
199 | void *arg; | ||
200 | |||
201 | /** | ||
202 | * Name for thread | ||
203 | */ | ||
204 | const char *name; | ||
205 | }; | ||
206 | |||
207 | static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_ | ||
208 | named_thread_starter (void *data) | ||
209 | { | ||
210 | struct MHD_named_helper_param_ * const param = | ||
211 | (struct MHD_named_helper_param_ *) data; | ||
212 | void * arg; | ||
213 | MHD_THREAD_START_ROUTINE_ thr_func; | ||
214 | |||
215 | if (NULL == data) | ||
216 | return (MHD_THRD_RTRN_TYPE_)0; | ||
217 | |||
218 | MHD_set_cur_thread_name_(param->name); | ||
219 | |||
220 | arg = param->arg; | ||
221 | thr_func = param->start_routine; | ||
222 | free(data); | ||
223 | |||
224 | return thr_func(arg); | ||
225 | } | ||
226 | |||
227 | |||
228 | |||
229 | /** | ||
230 | * Create a named thread and set the attributes according to our options. | ||
231 | * | ||
232 | * @param thread handle to initialize | ||
233 | * @param thread_name name for new thread | ||
234 | * @param stack_size size of stack for new thread, 0 for default | ||
235 | * @param start_routine main function of thread | ||
236 | * @param arg argument for start_routine | ||
237 | * @return non-zero on success; zero otherwise (with errno set) | ||
238 | */ | ||
239 | int | ||
240 | MHD_create_named_thread_ (MHD_thread_handle_ *thread, | ||
241 | const char* thread_name, | ||
242 | size_t stack_size, | ||
243 | MHD_THREAD_START_ROUTINE_ start_routine, | ||
244 | void *arg) | ||
245 | { | ||
246 | struct MHD_named_helper_param_ * param; | ||
247 | |||
248 | if (NULL == thread_name) | ||
249 | { | ||
250 | errno = EINVAL; | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | param = malloc(sizeof(struct MHD_named_helper_param_)); | ||
255 | if (NULL == param) | ||
256 | return 0; | ||
257 | |||
258 | param->start_routine = start_routine; | ||
259 | param->arg = arg; | ||
260 | param->name = thread_name; | ||
261 | |||
262 | /* Set thread name in thread itself to avoid problems with | ||
263 | * threads which terminated before name is set in other thread. | ||
264 | */ | ||
265 | if (!MHD_create_thread_(thread, stack_size, &named_thread_starter, (void*)param)) | ||
266 | { | ||
267 | free(param); | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | return !0; | ||
272 | } | ||
273 | |||
274 | #endif /* MHD_USE_THREAD_NAME_ */ | ||