3 /* xbt_os_thread -- portability layer over the pthread API */
4 /* Used in RL to get win/lin portability, and in SG when CONTEXT_THREAD */
5 /* in SG, when using CONTEXT_UCONTEXT, xbt_os_thread_stub is used instead */
7 /* Copyright 2006,2007 Malek Cherier, Martin Quinson
8 * All right reserved. */
10 /* This program is free software; you can redistribute it and/or modify it
11 * under the terms of the license (GNU LGPL) which comes with this package. */
13 #include "xbt/sysdep.h"
15 #include "xbt/ex_interface.h" /* We play crude games with exceptions */
17 #include "xbt/xbt_os_time.h" /* Portable time facilities */
18 #include "xbt/xbt_os_thread.h" /* This module */
19 #include "xbt_modinter.h" /* Initialization/finalization of this module */
21 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_sync_os,xbt,"Synchronization mechanism (OS-level)");
23 /* ********************************* PTHREAD IMPLEMENTATION ************************************ */
28 typedef struct xbt_os_thread_ {
32 pvoid_f_pvoid_t *start_routine;
35 static xbt_os_thread_t main_thread = NULL;
37 /* thread-specific data containing the xbt_os_thread_t structure */
38 static pthread_key_t xbt_self_thread_key;
39 static int thread_mod_inited = 0;
41 /* frees the xbt_os_thread_t corresponding to the current thread */
42 static void xbt_os_thread_free_thread_data(void*d){
46 /* callback: context fetching */
47 static ex_ctx_t *_os_thread_ex_ctx(void) {
48 return xbt_os_thread_self()->exception;
51 /* callback: termination */
52 static void _os_thread_ex_terminate(xbt_ex_t * e) {
56 /* FIXME: there should be a configuration variable to choose to kill everyone or only this one */
59 void xbt_os_thread_mod_init(void) {
62 if (thread_mod_inited)
65 if ((errcode=pthread_key_create(&xbt_self_thread_key, NULL)))
66 THROW0(system_error,errcode,"pthread_key_create failed for xbt_self_thread_key");
68 main_thread=xbt_new(s_xbt_os_thread_t,1);
69 main_thread->start_routine = NULL;
70 main_thread->param = NULL;
71 main_thread->exception = xbt_new(ex_ctx_t, 1);
72 XBT_CTX_INITIALIZE(main_thread->exception);
74 thread_mod_inited = 1;
76 void xbt_os_thread_mod_exit(void) {
77 /* FIXME: don't try to free our key on shutdown.
78 Valgrind detects no leak if we don't, and whine if we try to */
81 // if ((errcode=pthread_key_delete(xbt_self_thread_key)))
82 // THROW0(system_error,errcode,"pthread_key_delete failed for xbt_self_thread_key");
85 static void * wrapper_start_routine(void *s) {
86 xbt_os_thread_t t = s;
89 if ((errcode=pthread_setspecific(xbt_self_thread_key,t)))
90 THROW0(system_error,errcode,
91 "pthread_setspecific failed for xbt_self_thread_key");
92 return t->start_routine(t->param);
94 xbt_os_thread_t xbt_os_thread_create(const char*name,
95 pvoid_f_pvoid_t start_routine,
99 xbt_os_thread_t res_thread=xbt_new(s_xbt_os_thread_t,1);
100 res_thread->name = xbt_strdup(name);
101 res_thread->start_routine = start_routine;
102 res_thread->param = param;
103 res_thread->exception = xbt_new(ex_ctx_t, 1);
104 XBT_CTX_INITIALIZE(res_thread->exception);
106 if ((errcode = pthread_create(&(res_thread->t), NULL,
107 wrapper_start_routine, res_thread)))
108 THROW1(system_error,errcode,
109 "pthread_create failed: %s",strerror(errcode));
115 xbt_os_thread_join(xbt_os_thread_t thread,void ** thread_return) {
119 if ((errcode = pthread_join(thread->t,thread_return)))
120 THROW1(system_error,errcode, "pthread_join failed: %s",
122 if (thread->exception)
123 free(thread->exception);
125 if (thread == main_thread) /* just killed main thread */
131 void xbt_os_thread_exit(int *retval) {
132 pthread_exit(retval);
135 xbt_os_thread_t xbt_os_thread_self(void) {
138 if (!thread_mod_inited)
141 res = pthread_getspecific(xbt_self_thread_key);
149 void xbt_os_thread_yield(void) {
152 void xbt_os_thread_cancel(xbt_os_thread_t t) {
153 pthread_cancel(t->t);
155 /****** mutex related functions ******/
156 typedef struct xbt_os_mutex_ {
157 /* KEEP IT IN SYNC WITH xbt_thread.c */
161 xbt_os_mutex_t xbt_os_mutex_init(void) {
162 xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t,1);
165 if ((errcode = pthread_mutex_init(&(res->m),NULL)))
166 THROW1(system_error,errcode,"pthread_mutex_init() failed: %s",
172 void xbt_os_mutex_lock(xbt_os_mutex_t mutex) {
175 if ((errcode=pthread_mutex_lock(&(mutex->m))))
176 THROW2(system_error,errcode,"pthread_mutex_lock(%p) failed: %s",
177 mutex, strerror(errcode));
180 void xbt_os_mutex_unlock(xbt_os_mutex_t mutex) {
183 if ((errcode=pthread_mutex_unlock(&(mutex->m))))
184 THROW2(system_error,errcode,"pthread_mutex_unlock(%p) failed: %s",
185 mutex, strerror(errcode));
188 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex) {
193 if ((errcode=pthread_mutex_destroy(&(mutex->m))))
194 THROW2(system_error,errcode,"pthread_mutex_destroy(%p) failed: %s",
195 mutex, strerror(errcode));
199 /***** condition related functions *****/
200 typedef struct xbt_os_cond_ {
201 /* KEEP IT IN SYNC WITH xbt_thread.c */
205 xbt_os_cond_t xbt_os_cond_init(void) {
206 xbt_os_cond_t res = xbt_new(s_xbt_os_cond_t,1);
208 if ((errcode=pthread_cond_init(&(res->c),NULL)))
209 THROW1(system_error,errcode,"pthread_cond_init() failed: %s",
215 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex) {
217 if ((errcode=pthread_cond_wait(&(cond->c),&(mutex->m))))
218 THROW3(system_error,errcode,"pthread_cond_wait(%p,%p) failed: %s",
219 cond,mutex, strerror(errcode));
224 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex, double delay) {
226 struct timespec ts_end;
227 double end = delay + xbt_os_time();
228 ts_end.tv_sec = (time_t) floor(end);
229 ts_end.tv_nsec = (long) ( ( end - ts_end.tv_sec) * 1000000000);
230 DEBUG3("pthread_cond_timedwait(%p,%p,%p)",&(cond->c),&(mutex->m), &ts_end);
231 switch ( (errcode=pthread_cond_timedwait(&(cond->c),&(mutex->m), &ts_end)) ) {
233 THROW3(timeout_error,errcode,"condition %p (mutex %p) wasn't signaled before timeout (%f)",
236 THROW4(system_error,errcode,"pthread_cond_timedwait(%p,%p,%f) failed: %s",
237 cond,mutex, delay, strerror(errcode));
241 void xbt_os_cond_signal(xbt_os_cond_t cond) {
243 if ((errcode=pthread_cond_signal(&(cond->c))))
244 THROW2(system_error,errcode,"pthread_cond_signal(%p) failed: %s",
245 cond, strerror(errcode));
248 void xbt_os_cond_broadcast(xbt_os_cond_t cond){
250 if ((errcode=pthread_cond_broadcast(&(cond->c))))
251 THROW2(system_error,errcode,"pthread_cond_broadcast(%p) failed: %s",
252 cond, strerror(errcode));
254 void xbt_os_cond_destroy(xbt_os_cond_t cond){
259 if ((errcode=pthread_cond_destroy(&(cond->c))))
260 THROW2(system_error,errcode,"pthread_cond_destroy(%p) failed: %s",
261 cond, strerror(errcode));
265 void *xbt_os_thread_getparam(void) {
266 xbt_os_thread_t t = xbt_os_thread_self();
267 return t?t->param:NULL;
270 /* ********************************* WINDOWS IMPLEMENTATION ************************************ */
274 typedef struct xbt_os_thread_ {
276 HANDLE handle; /* the win thread handle */
277 unsigned long id; /* the win thread id */
278 pvoid_f_pvoid_t *start_routine;
280 } s_xbt_os_thread_t ;
282 /* key to the TLS containing the xbt_os_thread_t structure */
283 static unsigned long xbt_self_thread_key;
285 void xbt_os_thread_mod_init(void) {
286 xbt_self_thread_key = TlsAlloc();
288 void xbt_os_thread_mod_exit(void) {
290 if (!TlsFree(xbt_self_thread_key))
291 THROW0(system_error,(int)GetLastError(),"TlsFree() failed to cleanup the thread submodule");
294 static DWORD WINAPI wrapper_start_routine(void *s) {
295 xbt_os_thread_t t = (xbt_os_thread_t)s;
297 if(!TlsSetValue(xbt_self_thread_key,t))
298 THROW0(system_error,(int)GetLastError(),"TlsSetValue of data describing the created thread failed");
300 return (DWORD)t->start_routine(t->param);
304 xbt_os_thread_t xbt_os_thread_create(const char *name,pvoid_f_pvoid_t start_routine,
307 xbt_os_thread_t t = xbt_new(s_xbt_os_thread_t,1);
309 t->name = xbt_strdup(name);
310 t->start_routine = start_routine ;
313 t->handle = CreateThread(NULL,0,
314 (LPTHREAD_START_ROUTINE)wrapper_start_routine,
319 THROW0(system_error,(int)GetLastError(),"CreateThread failed");
326 xbt_os_thread_join(xbt_os_thread_t thread,void ** thread_return) {
328 if(WAIT_OBJECT_0 != WaitForSingleObject(thread->handle,INFINITE))
329 THROW0(system_error,(int)GetLastError(), "WaitForSingleObject failed");
333 if(!GetExitCodeThread(thread->handle,(DWORD*)(*thread_return)))
334 THROW0(system_error,(int)GetLastError(), "GetExitCodeThread failed");
337 CloseHandle(thread->handle);
342 void xbt_os_thread_exit(int *retval) {
349 xbt_os_thread_t xbt_os_thread_self(void) {
350 return TlsGetValue(xbt_self_thread_key);
353 void *xbt_os_thread_getparam(void) {
354 xbt_os_thread_t t = xbt_os_thread_self();
359 void xbt_os_thread_yield(void) {
362 void xbt_os_thread_cancel(xbt_os_thread_t t) {
366 /****** mutex related functions ******/
367 typedef struct xbt_os_mutex_ {
368 /* KEEP IT IN SYNC WITH xbt_thread.c */
369 CRITICAL_SECTION lock;
372 xbt_os_mutex_t xbt_os_mutex_init(void) {
373 xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t,1);
375 /* initialize the critical section object */
376 InitializeCriticalSection(&(res->lock));
381 void xbt_os_mutex_lock(xbt_os_mutex_t mutex) {
383 EnterCriticalSection(& mutex->lock);
386 void xbt_os_mutex_unlock(xbt_os_mutex_t mutex) {
388 LeaveCriticalSection (& mutex->lock);
392 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex) {
396 DeleteCriticalSection(& mutex->lock);
400 /***** condition related functions *****/
401 enum { /* KEEP IT IN SYNC WITH xbt_thread.c */
407 typedef struct xbt_os_cond_ {
408 /* KEEP IT IN SYNC WITH xbt_thread.c */
409 HANDLE events[MAX_EVENTS];
411 unsigned int waiters_count; /* the number of waiters */
412 CRITICAL_SECTION waiters_count_lock; /* protect access to waiters_count */
415 xbt_os_cond_t xbt_os_cond_init(void) {
417 xbt_os_cond_t res = xbt_new0(s_xbt_os_cond_t,1);
419 memset(& res->waiters_count_lock,0,sizeof(CRITICAL_SECTION));
421 /* initialize the critical section object */
422 InitializeCriticalSection(& res->waiters_count_lock);
424 res->waiters_count = 0;
426 /* Create an auto-reset event */
427 res->events[SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL);
429 if(!res->events[SIGNAL]){
430 DeleteCriticalSection(& res->waiters_count_lock);
432 THROW0(system_error,0,"CreateEvent failed for the signals");
435 /* Create a manual-reset event. */
436 res->events[BROADCAST] = CreateEvent (NULL, TRUE, FALSE,NULL);
438 if(!res->events[BROADCAST]){
440 DeleteCriticalSection(& res->waiters_count_lock);
441 CloseHandle(res->events[SIGNAL]);
443 THROW0(system_error,0,"CreateEvent failed for the broadcasts");
449 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex) {
451 unsigned long wait_result;
454 /* lock the threads counter and increment it */
455 EnterCriticalSection (& cond->waiters_count_lock);
456 cond->waiters_count++;
457 LeaveCriticalSection (& cond->waiters_count_lock);
459 /* unlock the mutex associate with the condition */
460 LeaveCriticalSection (& mutex->lock);
462 /* wait for a signal (broadcast or no) */
463 wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
465 if(wait_result == WAIT_FAILED)
466 THROW0(system_error,0,"WaitForMultipleObjects failed, so we cannot wait on the condition");
468 /* we have a signal lock the condition */
469 EnterCriticalSection (& cond->waiters_count_lock);
470 cond->waiters_count--;
472 /* it's the last waiter or it's a broadcast ? */
473 is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1) && (cond->waiters_count == 0));
475 LeaveCriticalSection (& cond->waiters_count_lock);
477 /* yes it's the last waiter or it's a broadcast
478 * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
482 if(!ResetEvent (cond->events[BROADCAST]))
483 THROW0(system_error,0,"ResetEvent failed");
485 /* relock the mutex associated with the condition in accordance with the posix thread specification */
486 EnterCriticalSection (& mutex->lock);
488 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex, double delay) {
492 void xbt_os_cond_signal(xbt_os_cond_t cond) {
495 EnterCriticalSection (& cond->waiters_count_lock);
496 have_waiters = cond->waiters_count > 0;
497 LeaveCriticalSection (& cond->waiters_count_lock);
500 if(!SetEvent(cond->events[SIGNAL]))
501 THROW0(system_error,0,"SetEvent failed");
503 xbt_os_thread_yield();
506 void xbt_os_cond_broadcast(xbt_os_cond_t cond){
509 EnterCriticalSection (& cond->waiters_count_lock);
510 have_waiters = cond->waiters_count > 0;
511 LeaveCriticalSection (& cond->waiters_count_lock);
514 SetEvent(cond->events[BROADCAST]);
517 void xbt_os_cond_destroy(xbt_os_cond_t cond){
522 if(!CloseHandle(cond->events[SIGNAL]))
525 if(!CloseHandle(cond->events[BROADCAST]))
528 DeleteCriticalSection(& cond->waiters_count_lock);
533 THROW0(system_error,0,"Error while destroying the condition");