1 #include "config.h"
2
3 #include <razorback/debug.h>
4 #include <razorback/thread.h>
5 #include <razorback/ntlv.h>
6 #include <razorback/list.h>
7 #include <razorback/log.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <errno.h>
11 #include "runtime_config.h"
12
13
14 static struct List *sg_threadList;
15
16 #ifdef _MSC_VER
17 static volatile int initialized = 0;
18
19 static void initThreading_win32(void);
20 #else //_MSC_VER
21
22 #include <pthread.h>
23 #include <signal.h>
24
25 static pthread_attr_t g_attr;
26 static pthread_once_t g_once_control = PTHREAD_ONCE_INIT;
27
28 static void initThreading_pthreads(void);
29
30
31 static void handler(int sig);
32 #endif //_MSC_VER
33 static void Thread_Lock(void *);
34 static void Thread_Unlock(void *);
35
36 static void
initThreading(void)37 initThreading (void)
38 {
39 sg_threadList = List_Create(LIST_MODE_GENERIC,
40 Thread_Cmp,
41 Thread_KeyCmp,
42 NULL, NULL,
43 Thread_Lock,
44 Thread_Unlock);
45 #ifdef _MSC_VER
46 initThreading_win32();
47 #else
48 initThreading_pthreads();
49 #endif
50 }
51
52 #ifdef _MSC_VER
53 static DWORD WINAPI
Thread_MainWrapper(void * arg)54 Thread_MainWrapper (void *arg)
55 #else
56 static void *
57 Thread_MainWrapper (void *arg)
58 #endif
59 {
60 struct Thread *l_pThread = (struct Thread *) arg;
61 List_Lock(sg_threadList);
62 Thread_Lock (l_pThread);
63
64 l_pThread->bRunning = true;
65
66 Thread_Unlock (l_pThread);
67 List_Unlock(sg_threadList);
68
69 l_pThread->mainFunction (l_pThread);
70
71 List_Lock(sg_threadList);
72 Thread_Lock (l_pThread);
73
74 l_pThread->bRunning = false;
75
76 Thread_Unlock (l_pThread);
77 List_Unlock(sg_threadList);
78
79 // Don't destroy the thread structure, it may still be referenced
80 // We should probably ref count this struct
81 Thread_Destroy(l_pThread);
82
83 #ifdef _MSC_VER
84 return 0;
85 #else //_MSC_VER
86 return NULL; // Implicit pthread_exit()
87 #endif //_MSC_VER
88 }
89
90 SO_PUBLIC struct Thread *
Thread_Launch(void (* fpFunction)(struct Thread *),void * userData,char * name,struct RazorbackContext * context)91 Thread_Launch (void (*fpFunction) (struct Thread *), void *userData,
92 char *name, struct RazorbackContext *context)
93 {
94 struct Thread *thread;
95
96 ASSERT (fpFunction != NULL);
97 if (fpFunction == NULL)
98 return NULL;
99
100 #ifdef _MSC_VER
101 if (initialized == 0)
102 initThreading();
103
104 #else //_MSC_VER
105 pthread_once (&g_once_control, initThreading);
106 #endif //_MSC_VER
107
108 // Racy
109 if (sg_threadList->length == Config_getThreadLimit ())
110 return NULL;
111
112 // allocate memory for thread structure
113 thread = (struct Thread *)calloc (1, sizeof (struct Thread));
114 if (thread == NULL)
115 {
116 rzb_log (LOG_ERR,
117 "%s: Failed to launch thread in Thread_Launch due to out of memory for Thread", __func__);
118 return NULL;
119 }
120
121 // initialize running indicator
122 thread->bRunning = false;
123 thread->pContext = context;
124 thread->pUserData = userData;
125 thread->sName = name;
126 thread->bShutdown = false;
127 // Init ref count, once for the list, once for the caller.
128 thread->refs =2;
129
130 thread->mainFunction = fpFunction;
131 // initialize running mutex
132 if ((thread->mMutex = Mutex_Create(MUTEX_MODE_RECURSIVE)) == NULL)
133 {
134 free(thread);
135 return NULL;
136 }
137
138 #ifdef _MSC_VER
139 thread->hThread = CreateThread(NULL, 0, Thread_MainWrapper, thread, 0, &thread->iThread);
140 #else //_MSC_VER
141 // start thread, check for error
142 if (pthread_create
143 (&thread->iThread, &g_attr, Thread_MainWrapper, thread) != 0)
144 {
145 free (thread);
146 rzb_log (LOG_ERR,
147 "%s: Failed to launch thread in Thread_Launch due to pthread_create error (%i)", __func__,
148 errno);
149 return NULL;
150 }
151 #endif //_MSC_VER
152 List_Push(sg_threadList, thread);
153
154 // done
155 return thread;
156 }
157
158 SO_PUBLIC void
Thread_Destroy(struct Thread * thread)159 Thread_Destroy (struct Thread *thread)
160 {
161 ASSERT(thread != NULL);
162 if (thread == NULL)
163 return;
164
165 List_Lock(sg_threadList);
166 Thread_Lock(thread);
167
168 // Reference count should not drop below 1 as the list holds a ref.
169 ASSERT(thread->refs >= 1);
170
171 if (thread->refs > 1)
172 {
173 thread->refs--;
174 Thread_Unlock(thread);
175 List_Unlock(sg_threadList);
176 return;
177 }
178
179 List_Remove(sg_threadList, thread);
180 // destroy running mutex
181 Thread_Unlock(thread);
182 List_Unlock(sg_threadList);
183
184 Mutex_Destroy (thread->mMutex);
185
186 free (thread);
187 }
188
189 SO_PUBLIC bool
Thread_IsRunning(struct Thread * thread)190 Thread_IsRunning (struct Thread *thread)
191 {
192 bool l_bRunning;
193 ASSERT (thread != NULL);
194 if (thread == NULL)
195 return false;
196
197 Thread_Lock (thread);
198
199 l_bRunning = thread->bRunning;
200
201 Thread_Unlock (thread);
202
203 return l_bRunning;
204 }
205
206 SO_PUBLIC bool
Thread_IsStopped(struct Thread * thread)207 Thread_IsStopped (struct Thread *thread)
208 {
209 bool l_bShutdown;
210
211 ASSERT (thread != NULL);
212 if (thread == NULL)
213 return false;
214
215 Thread_Lock (thread);
216
217 l_bShutdown = thread->bShutdown;
218
219 Thread_Unlock (thread);
220
221 return l_bShutdown;
222 }
223
224
225 SO_PUBLIC void
Thread_Stop(struct Thread * thread)226 Thread_Stop (struct Thread *thread)
227 {
228 ASSERT (thread != NULL);
229 if (thread == NULL)
230 return;
231
232 Thread_Lock (thread);
233
234 thread->bShutdown = true;
235
236 Thread_Unlock (thread);
237
238 }
239 SO_PUBLIC void
Thread_Interrupt(struct Thread * thread)240 Thread_Interrupt(struct Thread *thread)
241 {
242 ASSERT (thread != NULL);
243 if (thread == NULL)
244 return;
245
246 Thread_Lock(thread);
247 Thread_Stop(thread);
248 #ifdef _MSC_VER
249 //UNIMPLEMENTED();
250 #else //_MSC_VER
251 pthread_kill(thread->iThread, SIGUSR1);
252 #endif //_MSC_VER
253 //thread->interrupt(thread);
254 Thread_Unlock(thread);
255
256 }
257
258 SO_PUBLIC void
Thread_Join(struct Thread * thread)259 Thread_Join(struct Thread *thread)
260 {
261 ASSERT(thread != NULL);
262 if (thread == NULL)
263 return;
264
265 #ifdef _MSC_VER
266 WaitForSingleObject(thread->hThread,INFINITE);
267 #else //_MSC_VER
268 void *ret;
269 int res =0;
270 if ((res = pthread_join(thread->iThread, &ret)) != 0)
271 rzb_log(LOG_ERR, "%s: Failed to join: %i", __func__, res);
272 #endif //_MSC_VER
273 }
274
275 SO_PUBLIC void
Thread_StopAndJoin(struct Thread * thread)276 Thread_StopAndJoin(struct Thread *thread)
277 {
278 ASSERT (thread != NULL);
279 if (thread == NULL)
280 return;
281
282 Thread_Stop(thread);
283 Thread_Join(thread);
284 }
285
286 SO_PUBLIC void
Thread_InterruptAndJoin(struct Thread * thread)287 Thread_InterruptAndJoin(struct Thread *thread)
288 {
289 ASSERT (thread != NULL);
290 if (thread == NULL)
291 return;
292
293 Thread_Stop(thread);
294 Thread_Interrupt(thread);
295 Thread_Join(thread);
296 }
297
298
299 SO_PUBLIC struct RazorbackContext *
Thread_GetContext(struct Thread * thread)300 Thread_GetContext(struct Thread *thread)
301 {
302 struct RazorbackContext *l_pOldContext;
303
304 ASSERT(thread != NULL);
305 if (thread == NULL)
306 return NULL;
307
308 Thread_Lock (thread);
309
310 l_pOldContext = thread->pContext;
311 Thread_Unlock (thread);
312
313 return l_pOldContext;
314 }
315
316 SO_PUBLIC struct RazorbackContext *
Thread_GetCurrentContext(void)317 Thread_GetCurrentContext(void)
318 {
319 struct Thread *thread;
320 struct RazorbackContext *cont;
321 thread = Thread_GetCurrent();
322 if (thread == NULL)
323 {
324 rzb_log(LOG_ERR, "%s: Failed to get current thread", __func__);
325 return NULL;
326 }
327 cont = Thread_GetContext(thread);
328 Thread_Destroy(thread);
329 return cont;
330 }
331
332 SO_PUBLIC struct RazorbackContext *
Thread_ChangeContext(struct Thread * thread,struct RazorbackContext * context)333 Thread_ChangeContext(struct Thread *thread, struct RazorbackContext *context)
334 {
335 struct RazorbackContext *l_pOldContext;
336
337 ASSERT(thread != NULL);
338 if (thread == NULL)
339 return NULL;
340
341 Thread_Lock (thread);
342
343 l_pOldContext = thread->pContext;
344 thread->pContext = context;
345
346 Thread_Unlock (thread);
347
348 return l_pOldContext;
349 }
350
351 SO_PUBLIC rzb_thread_t
Thread_GetCurrentId(void)352 Thread_GetCurrentId(void)
353 {
354 #ifdef _MSC_VER
355 return GetCurrentThreadId();
356 #else
357 return pthread_self();
358 #endif
359 }
360
361 SO_PUBLIC struct Thread *
Thread_GetCurrent(void)362 Thread_GetCurrent(void)
363 {
364 struct Thread *l_pRet = NULL;
365 rzb_thread_t l_tCurrent = Thread_GetCurrentId();
366 l_pRet = (struct Thread *)List_Find(sg_threadList, &l_tCurrent);
367 if (l_pRet == NULL)
368 return NULL;
369
370 Thread_Lock(l_pRet);
371 l_pRet->refs++;
372 Thread_Unlock(l_pRet);
373 return l_pRet;
374 }
375
376 SO_PUBLIC void
Thread_Yield(void)377 Thread_Yield(void)
378 {
379 #ifdef _MSC_VER
380 SwitchToThread();
381 #else
382 pthread_yield();
383 #endif
384 }
385
386 SO_PUBLIC uint32_t
Thread_getCount(void)387 Thread_getCount (void)
388 {
389 uint32_t num;
390 List_Lock(sg_threadList);
391 num = sg_threadList->length;
392 List_Unlock(sg_threadList);
393 return num;
394 }
395
396 SO_PUBLIC int
Thread_KeyCmp(void * a,void * id)397 Thread_KeyCmp(void *a, void *id)
398 {
399 struct Thread * cA = (struct Thread *)a;
400 rzb_thread_t cId = *(rzb_thread_t *)id;
401
402 if (cId == cA->iThread)
403 return 0;
404 else
405 return -1;
406 return -1;
407 }
408
409 SO_PUBLIC int
Thread_Cmp(void * a,void * b)410 Thread_Cmp(void *a, void *b)
411 {
412 struct Thread * cA = (struct Thread *)a;
413 struct Thread * cB = (struct Thread *)b;
414 if (a==b)
415 return 0;
416 if (cA->iThread == cB->iThread)
417 return 0;
418 else
419 return -1;
420 return -1;
421 }
422
423 static void
Thread_Lock(void * a)424 Thread_Lock(void *a)
425 {
426 struct Thread *t = (struct Thread *)a;
427 Mutex_Lock(t->mMutex);
428 }
429
430 static void
Thread_Unlock(void * a)431 Thread_Unlock(void *a)
432 {
433 struct Thread *t = (struct Thread *)a;
434 Mutex_Unlock(t->mMutex);
435 }
436
437
438 #ifdef _MSC_VER
439
440 static void
initThreading_win32(void)441 initThreading_win32(void)
442 {
443 initialized=1;
444 }
445
446 #else //_MSC_VER
447
448 static void
initThreading_pthreads(void)449 initThreading_pthreads (void)
450 {
451 struct sigaction act;
452 sigset_t mask;
453
454 pthread_attr_init (&g_attr);
455 pthread_attr_setdetachstate (&g_attr, PTHREAD_CREATE_JOINABLE);
456
457 sigemptyset(&mask);
458 sigaddset(&mask, SIGUSR1);
459 act.sa_handler = handler;
460 act.sa_flags = 0;
461 sigemptyset(&act.sa_mask);
462 if (sigaction(SIGUSR1, &act, NULL) < 0)
463 rzb_log(LOG_ERR, "%s: Failed to install signal handler", __func__);
464 }
465
handler(int sig)466 static void handler(int sig)
467 {
468 rzb_log(LOG_DEBUG, "Thread Got Signal");
469 return;
470 }
471
472 SO_PUBLIC void
Thread_Interrupt_pthread(struct Thread * thread)473 Thread_Interrupt_pthread(struct Thread *thread)
474 {
475 pthread_kill(thread->iThread, SIGUSR1);
476 }
477
478 #endif //_MSC_VER
479