3 /* xbt_thread -- portability layer over the pthread API */
5 /* Copyright 2006,2007 Malek Cherier, Martin Quinson
6 * All right reserved. */
8 /* This program is free software; you can redistribute it and/or modify it
9 * under the terms of the license (GNU LGPL) which comes with this package. */
11 #include "xbt/sysdep.h"
14 #include "xbt/xbt_thread.h" /* This module */
15 #include "xbt_modinter.h" /* Initialization/finalization of this module */
19 /* ********************************* PTHREAD IMPLEMENTATION ************************************ */
23 typedef struct xbt_thread_ {
27 /* thread-specific data containing the xbt_thread_t structure */
28 static pthread_key_t xbt_self_thread_key;
30 /* frees the xbt_thread_t corresponding to the current thread */
31 static void xbt_thread_free_thread_data(void*d){
35 void xbt_thread_mod_init(void) {
38 if ((errcode=pthread_key_create(&xbt_self_thread_key, NULL)))
39 THROW0(system_error,errcode,"pthread_key_create failed for xbt_self_thread_key");
41 void xbt_thread_mod_exit(void) {
42 /* FIXME: don't try to free our key on shutdown. Valgrind detects no leak if we don't, and whine if we try to */
45 // if ((errcode=pthread_key_delete(xbt_self_thread_key)))
46 // THROW0(system_error,errcode,"pthread_key_delete failed for xbt_self_thread_key");
49 typedef struct s_xbt_thread_wrapper_for_restart__ {
50 pvoid_f_pvoid_t *start_routine;
53 } s_xbt_thread_wrapper_for_restart_t, *xbt_thread_wrapper_for_restart_t;
55 static void * wrapper_start_routine(void *s) {
56 xbt_thread_wrapper_for_restart_t stub = s;
59 if ((errcode=pthread_setspecific(xbt_self_thread_key,stub->res)))
60 THROW0(system_error,errcode,"pthread_setspecific failed for xbt_self_thread_key");
61 return stub->start_routine(stub->param);
64 xbt_thread_t xbt_thread_create(pvoid_f_pvoid_t start_routine,
67 xbt_thread_wrapper_for_restart_t stub = xbt_new0(s_xbt_thread_wrapper_for_restart_t,1);
69 stub->start_routine = start_routine ;
71 stub->res = xbt_new(s_xbt_thread_t,1);
74 if ((errcode = pthread_create(&(stub->res->t), NULL, wrapper_start_routine, stub)))
75 THROW0(system_error,errcode, "pthread_create failed");
80 void xbt_thread_exit(int *retval) {
84 xbt_thread_t xbt_thread_self(void) {
85 return pthread_getspecific(xbt_self_thread_key);
89 void xbt_thread_yield(void) {
92 /****** mutex related functions ******/
93 typedef struct xbt_mutex_ {
97 xbt_mutex_t xbt_mutex_init(void) {
98 xbt_mutex_t res = xbt_new(s_xbt_mutex_t,1);
101 if ((errcode = pthread_mutex_init(&(res->m),NULL)))
102 THROW0(system_error,errcode,"pthread_mutex_init() failed");
107 void xbt_mutex_lock(xbt_mutex_t mutex) {
110 if ((errcode=pthread_mutex_lock(&(mutex->m))))
111 THROW1(system_error,errcode,"pthread_mutex_lock(%p) failed",mutex);
114 void xbt_mutex_unlock(xbt_mutex_t mutex) {
117 if ((errcode=pthread_mutex_unlock(&(mutex->m))))
118 THROW1(system_error,errcode,"pthread_mutex_unlock(%p) failed",mutex);
121 void xbt_mutex_destroy(xbt_mutex_t mutex) {
126 if ((errcode=pthread_mutex_destroy(&(mutex->m))))
127 THROW1(system_error,errcode,"pthread_mutex_destroy(%p) failed",mutex);
131 /***** condition related functions *****/
132 typedef struct xbt_thcond_ {
136 xbt_thcond_t xbt_thcond_init(void) {
137 xbt_thcond_t res = xbt_new(s_xbt_thcond_t,1);
139 if ((errcode=pthread_cond_init(&(res->c),NULL)))
140 THROW0(system_error,errcode,"pthread_cond_init() failed");
145 void xbt_thcond_wait(xbt_thcond_t cond, xbt_mutex_t mutex) {
147 if ((errcode=pthread_cond_wait(&(cond->c),&(mutex->m))))
148 THROW2(system_error,errcode,"pthread_cond_wait(%p,%p) failed",cond,mutex);
151 void xbt_thcond_signal(xbt_thcond_t cond) {
153 if ((errcode=pthread_cond_signal(&(cond->c))))
154 THROW1(system_error,errcode,"pthread_cond_signal(%p) failed",cond);
157 void xbt_thcond_broadcast(xbt_thcond_t cond){
159 if ((errcode=pthread_cond_broadcast(&(cond->c))))
160 THROW1(system_error,errcode,"pthread_cond_broadcast(%p) failed",cond);
162 void xbt_thcond_destroy(xbt_thcond_t cond){
167 if ((errcode=pthread_cond_destroy(&(cond->c))))
168 THROW1(system_error,errcode,"pthread_cond_destroy(%p) failed",cond);
172 /* ********************************* WINDOWS IMPLEMENTATION ************************************ */
176 typedef struct xbt_thread_ {
177 HANDLE handle; /* the win thread handle */
178 unsigned long id; /* the win thread id */
181 /* key to the TLS containing the xbt_thread_t structure */
182 static unsigned long xbt_self_thread_key;
184 void xbt_thread_mod_init(void) {
185 xbt_self_thread_key = TlsAlloc();
187 void xbt_thread_mod_exit(void) {
189 if (!(errcode = TlsFree(xbt_self_thread_key)))
190 THROW0(system_error,errcode,"TlsFree() failed to cleanup the thread submodule");
193 xbt_thread_t xbt_thread_create(pvoid_f_pvoid_t start_routine,
196 xbt_thread_t res = xbt_new(s_xbt_thread_t,1);
198 res->handle = CreateThread(NULL,0,
199 (LPTHREAD_START_ROUTINE)start_routine,
204 THROW0(system_error,0,"CreateThread failed");
207 if(!TlsSetValue(xbt_self_thread_key,res))
208 THROW0(system_error,0,"TlsSetValue of data describing the created thread failed");
213 void xbt_thread_exit(int *retval) {
214 xbt_thread_t self = xbt_thread_self();
216 CloseHandle(self->handle);
222 xbt_thread_t xbt_thread_self(void) {
223 return TlsGetValue(xbt_self_thread_key);
226 void xbt_thread_yield(void) {
230 /****** mutex related functions ******/
231 typedef struct xbt_mutex_ {
232 CRITICAL_SECTION lock;
235 xbt_mutex_t xbt_mutex_init(void) {
236 xbt_mutex_t res = xbt_new(s_xbt_mutex_t,1);
238 /* initialize the critical section object */
239 InitializeCriticalSection(&(res->lock));
244 void xbt_mutex_lock(xbt_mutex_t mutex) {
246 EnterCriticalSection(& mutex->lock);
249 void xbt_mutex_unlock(xbt_mutex_t mutex) {
251 LeaveCriticalSection (& mutex->lock);
255 void xbt_mutex_destroy(xbt_mutex_t mutex) {
259 DeleteCriticalSection(& mutex->lock);
263 /***** condition related functions *****/
270 typedef struct xbt_thcond_ {
271 HANDLE events[MAX_EVENTS];
273 unsigned int waiters_count; /* the number of waiters */
274 CRITICAL_SECTION waiters_count_lock; /* protect access to waiters_count */
277 xbt_thcond_t xbt_thcond_init(void) {
279 xbt_thcond_t res = xbt_new0(s_xbt_thcond_t,1);
281 memset(& res->waiters_count_lock,0,sizeof(CRITICAL_SECTION));
283 /* initialize the critical section object */
284 InitializeCriticalSection(& res->waiters_count_lock);
286 res->waiters_count = 0;
288 /* Create an auto-reset event */
289 res->events[SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL);
291 if(!res->events[SIGNAL]){
292 DeleteCriticalSection(& res->waiters_count_lock);
294 THROW0(system_error,0,"CreateEvent failed for the signals");
297 /* Create a manual-reset event. */
298 res->events[BROADCAST] = CreateEvent (NULL, TRUE, FALSE,NULL);
300 if(!res->events[BROADCAST]){
302 DeleteCriticalSection(& res->waiters_count_lock);
303 CloseHandle(res->events[SIGNAL]);
305 THROW0(system_error,0,"CreateEvent failed for the broadcasts");
311 void xbt_thcond_wait(xbt_thcond_t cond, xbt_mutex_t mutex) {
313 unsigned long wait_result;
316 /* lock the threads counter and increment it */
317 EnterCriticalSection (& cond->waiters_count_lock);
318 cond->waiters_count++;
319 LeaveCriticalSection (& cond->waiters_count_lock);
321 /* unlock the mutex associate with the condition */
322 LeaveCriticalSection (& mutex->lock);
324 /* wait for a signal (broadcast or no) */
325 wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
327 if(wait_result == WAIT_FAILED)
328 THROW0(system_error,0,"WaitForMultipleObjects failed, so we cannot wait on the condition");
330 /* we have a signal lock the condition */
331 EnterCriticalSection (& cond->waiters_count_lock);
332 cond->waiters_count--;
334 /* it's the last waiter or it's a broadcast ? */
335 is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1) && (cond->waiters_count == 0));
337 LeaveCriticalSection (& cond->waiters_count_lock);
339 /* yes it's the last waiter or it's a broadcast
340 * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
344 if(!ResetEvent (cond->events[BROADCAST]))
345 THROW0(system_error,0,"ResetEvent failed");
347 /* relock the mutex associated with the condition in accordance with the posix thread specification */
348 EnterCriticalSection (& mutex->lock);
351 void xbt_thcond_signal(xbt_thcond_t cond) {
354 EnterCriticalSection (& cond->waiters_count_lock);
355 have_waiters = cond->waiters_count > 0;
356 LeaveCriticalSection (& cond->waiters_count_lock);
359 if(!SetEvent(cond->events[SIGNAL]))
360 THROW0(system_error,0,"SetEvent failed");
363 void xbt_thcond_broadcast(xbt_thcond_t cond){
366 EnterCriticalSection (& cond->waiters_count_lock);
367 have_waiters = cond->waiters_count > 0;
368 LeaveCriticalSection (& cond->waiters_count_lock);
371 SetEvent(cond->events[BROADCAST]);
374 void xbt_thcond_destroy(xbt_thcond_t cond){
379 if(!CloseHandle(cond->events[SIGNAL]))
382 if(!CloseHandle(cond->events[BROADCAST]))
385 DeleteCriticalSection(& cond->waiters_count_lock);
390 THROW0(system_error,0,"Error while destroying the condition");