1 krisbash 1.1 #include "thread.h"
2 #include "atomic.h"
3 #include <pal/palcommon.h>
4
5 #if defined(PAL_HAVE_PTHREADS)
6 # include <sched.h>
7 #endif
8
9 /*
10 **==============================================================================
11 **
12 ** Windows version
13 **
14 **==============================================================================
15 */
16
17 #if defined(_MSC_VER)
18
19 #pragma warning(disable:4057)
20
21 typedef struct _ThreadWork
22 krisbash 1.1 {
23 ThreadProc threadProcCallback;
24 ThreadProc threadProcDestructor;
25 void* threadProcParam;
26 TP_WORK *tpWork;
27 PAL_Uint32 returnCode;
28 ptrdiff_t refcount;
29 }
30 ThreadWork;
31
32 VOID CALLBACK PAL_ThreadPoolCallback(
33 _Inout_ PTP_CALLBACK_INSTANCE tpInstance,
34 _In_ PVOID context,
35 _Inout_ PTP_WORK tpWork
36 )
37 {
38 ThreadWork* self = (ThreadWork*) context;
39 HMODULE newHModule;
40
41 GetModuleHandleExW(
42 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS ,
43 krisbash 1.1 (LPCWSTR) self->threadProcCallback,
44 &newHModule);
45
46 CallbackMayRunLong(tpInstance);
47 FreeLibraryWhenCallbackReturns(tpInstance, newHModule);
48
49 self->returnCode = self->threadProcCallback(self->threadProcParam);
50
51 if (self->threadProcDestructor)
52 self->threadProcDestructor(self->threadProcParam);
53
54 if (Atomic_Dec(&self->refcount) == 0)
55 {
56 CloseThreadpoolWork(tpWork);
57 PAL_Free(self);
58 }
59 }
60
61
62 _Return_type_success_(return == 0) int Thread_CreateDetached_Injected(
63 _In_ ThreadProc threadProcCallback,
64 krisbash 1.1 _In_opt_ ThreadProc threadProcDestructor,
65 _In_ void* threadProcParam,
66 _In_ NitsCallSite cs)
67 {
68 ThreadWork *thread = NULL;
69
70 #if !defined(USE_ALLOCATOR)
71 if (NitsShouldFault(cs, NitsAutomatic))
72 return -1;
73
74 thread = PAL_Calloc(1, sizeof(ThreadWork));
75 #else
76 thread = __PAL_Calloc(cs.file, cs.line, cs.function, 1, sizeof(ThreadWork));
77 #endif
78
79 if (thread == NULL)
80 return -1;
81
82 thread->threadProcCallback = threadProcCallback;
83 thread->threadProcDestructor = threadProcDestructor;
84 thread->threadProcParam = threadProcParam;
85 krisbash 1.1 thread->refcount = 1;
86
87 /* Create the thread */
88 thread->tpWork = CreateThreadpoolWork(PAL_ThreadPoolCallback, thread, NULL);
89 if (thread->tpWork == NULL)
90 {
91 PAL_Free(thread);
92 return -1;
93 }
94
95 SubmitThreadpoolWork(thread->tpWork);
96
97 return 0;
98 }
99
100 _Return_type_success_(return == 0) int Thread_CreateJoinable_Injected(
101 _Out_ Thread* self,
102 _In_ ThreadProc threadProcCallback,
103 _In_opt_ ThreadProc threadProcDestructor,
104 _In_ void* threadProcParam,
105 NitsCallSite cs)
106 krisbash 1.1 {
107 ThreadWork *thread = NULL;
108
109 #if !defined(USE_ALLOCATOR)
110 if (NitsShouldFault(cs, NitsAutomatic))
111 return -1;
112
113 thread = PAL_Calloc(1, sizeof(ThreadWork));
114 #else
115 thread = __PAL_Calloc(
116 cs.file, cs.line, cs.function, 1, sizeof(ThreadWork));
117 #endif
118
119 if (thread == NULL)
120 return -1;
121
122 thread->threadProcCallback = threadProcCallback;
123 thread->threadProcDestructor = threadProcDestructor;
124 thread->threadProcParam = threadProcParam;
125 thread->refcount = 2;
126
127 krisbash 1.1 /* Create the thread */
128 thread->tpWork = CreateThreadpoolWork(PAL_ThreadPoolCallback, thread, NULL);
129 if (thread->tpWork == NULL)
130 {
131 PAL_Free(thread);
132 return -1;
133 }
134
135 self->__impl = (ptrdiff_t) thread;
136
137 SubmitThreadpoolWork(thread->tpWork);
138
139 return 0;
140 }
141
142 _Return_type_success_(return == 0) int Thread_Join(
143 _In_ Thread* self,
144 _Out_ PAL_Uint32* returnValue)
145 {
146 ThreadWork *thread;
147 if (self->__impl == 0)
148 krisbash 1.1 {
149 *returnValue = 0;
150 return 0;
151 }
152
153 thread = (ThreadWork*) self->__impl;
154
155 /* Wait for thread to exit */
156 WaitForThreadpoolWorkCallbacks(thread->tpWork,FALSE);
157
158 /* return code from called thread */
159 *returnValue = thread->returnCode;
160
161 return 0;
162 }
163
164 void Thread_Destroy(
165 _Inout_ Thread* self)
166 {
167 ThreadWork *thread;
168 if (self->__impl == 0)
169 krisbash 1.1 return;
170 thread = (ThreadWork*) self->__impl;
171
172 if (Atomic_Dec(&thread->refcount) == 0)
173 {
174 CloseThreadpoolWork(thread->tpWork);
175 PAL_Free(thread);
176 }
177
178 memset(self, 0, sizeof(*self));
179 }
180
181 void Thread_Yield()
182 {
183 SwitchToThread();
184 }
185
186
187 #endif /* defined(_MSC_VER) */
188
189 /*
190 krisbash 1.1 **==============================================================================
191 **
192 ** POSIX threads version
193 **
194 **==============================================================================
195 */
196
197 #if defined(PAL_HAVE_PTHREADS)
198
199 typedef struct _ThreadData
200 {
201 ThreadProc proc;
202 ThreadProc destructor;
203 void* param;
204 }
205 ThreadData;
206
207 static void* _Wrapper(void* param)
208 {
209 ThreadData* data = (ThreadData*)param;
210 void* result;
211 krisbash 1.1
212 result = (void*)(ptrdiff_t)(*data->proc)(data->param);
213
214 if (data->destructor)
215 data->destructor(data->param);
216
217 PAL_Free(data);
218
219 return result;
220 }
221
222 int Thread_CreateDetached_Injected(
223 _In_ ThreadProc threadProcCallback,
224 _In_opt_ ThreadProc threadProcDestructor,
225 _In_ void* threadProcParam,
226 NitsCallSite cs)
227 {
228 pthread_attr_t attr;
229 pthread_t thread;
230 int r;
231
232 krisbash 1.1 #if !defined(USE_ALLOCATOR)
233 if (NitsShouldFault(cs, NitsAutomatic))
234 return -1;
235 #endif
236
237 /* Create the thread attributes and set the detached flag */
238
239 pthread_attr_init(&attr);
240 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
241
242 /* Create the thread */
243 {
244 #if !defined(USE_ALLOCATOR)
245 ThreadData* data = (ThreadData*)PAL_Malloc(sizeof(ThreadData));
246 #else
247 ThreadData* data = (ThreadData*)__PAL_Malloc(
248 cs.file, cs.line, cs.function, sizeof(ThreadData));
249 #endif
250
251
252 if (!data)
253 krisbash 1.1 {
254 pthread_attr_destroy(&attr);
255 return -1;
256 }
257
258 data->proc = threadProcCallback;
259 data->destructor = threadProcDestructor;
260 data->param = threadProcParam;
261 r = pthread_create(&thread, &attr, _Wrapper, data);
262 if (r != 0)
263 {
264 PAL_Free(data);
265 }
266 }
267
268 /* Destroy thread attributes */
269 pthread_attr_destroy(&attr);
270
271 return r == 0 ? 0 : -1;
272 }
273
274 krisbash 1.1 int Thread_CreateJoinable_Injected(
275 _Out_ Thread* self,
276 _In_ ThreadProc threadProcCallback,
277 _In_opt_ ThreadProc threadProcDestructor,
278 _In_ void* threadProcParam,
279 NitsCallSite cs)
280 {
281 int r;
282
283 #if !defined(USE_ALLOCATOR)
284 if (NitsShouldFault(cs, NitsAutomatic))
285 return -1;
286 #endif
287
288 /* Create the thread */
289 {
290 #if !defined(USE_ALLOCATOR)
291 ThreadData* data = (ThreadData*)PAL_Malloc(sizeof(ThreadData));
292 #else
293 ThreadData* data = (ThreadData*)__PAL_Malloc(
294 cs.file, cs.line, cs.function, sizeof(ThreadData));
295 krisbash 1.1 #endif
296
297 if (!data)
298 return -1;
299
300 data->proc = threadProcCallback;
301 data->destructor = threadProcDestructor;
302 data->param = threadProcParam;
303 r = pthread_create(&self->__impl, NULL, _Wrapper, data);
304 if (r != 0)
305 {
306 PAL_Free(data);
307 }
308 }
309
310 return r == 0 ? 0 : -1;
311 }
312
313 int Thread_Join(
314 _In_ Thread* self,
315 _Out_ PAL_Uint32* returnValue)
316 krisbash 1.1 {
317 int r;
318 void* returnValuePtr;
319
320 r = pthread_join(self->__impl, &returnValuePtr);
321
322 if (r == 0 && returnValue)
323 {
324 *returnValue = (PAL_Uint32)(ptrdiff_t)returnValuePtr;
325 return 0;
326 }
327
328 return -1;
329 }
330
331 int Thread_Equal(
332 _In_ ThreadID* thread1,
333 _In_ ThreadID* thread2)
334 {
335 return pthread_equal(thread1->__impl, thread2->__impl) == 0 ? 0 : -1;
336 }
337 krisbash 1.1
338 ThreadID Thread_ID()
339 {
340 ThreadID self;
341 self.__impl = pthread_self();
342 return self;
343 }
344
345 void Thread_Yield()
346 {
347 sched_yield();
348 }
349
350
351 #endif /* defined(PAL_HAVE_PTHREADS) */
|