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 */
20 typedef struct xbt_thread_ {
24 /* frees the xbt_thread_t corresponding to the current thread */
25 static void xbt_thread_free_thread_data(void*d){
29 pthread_key_t thread_data; /* thread-specific data containing the xbt_thread_t structure */
30 void xbt_thread_mod_init(void) {
33 if ((errcode=pthread_key_create(&thread_data, &xbt_thread_free_thread_data)))
34 THROW0(system_error,errcode,"pthread_key_create failed for thread_data");
36 void xbt_thread_mod_exit(void) {
39 if ((errcode=pthread_key_delete(thread_data)))
40 THROW0(system_error,errcode,"pthread_key_delete failed for thread_data");
44 xbt_thread_t xbt_thread_create(pvoid_f_pvoid_t start_routine,
46 xbt_thread_t res = xbt_new(s_xbt_thread_t,1);
49 if ((errcode=pthread_setspecific(thread_data,res)))
50 THROW0(system_error,errcode,"pthread_setspecific failed for thread_data");
52 if ((errcode = pthread_create(&(res->t), NULL, start_routine, param)))
53 THROW0(system_error,errcode, "pthread_create failed");
57 void xbt_thread_exit(int *retval) {
60 xbt_thread_t xbt_thread_self(void) {
61 return pthread_getspecific(thread_data);
65 void xbt_thread_yield(void) {
68 /****** mutex related functions ******/
69 typedef struct xbt_mutex_ {
73 xbt_mutex_t xbt_mutex_init(void) {
74 xbt_mutex_t res = xbt_new(s_xbt_mutex_t,1);
77 if ((errcode = pthread_mutex_init(&(res->m),NULL)))
78 THROW0(system_error,errcode,"pthread_mutex_init() failed");
83 void xbt_mutex_lock(xbt_mutex_t mutex) {
86 if ((errcode=pthread_mutex_lock(&(mutex->m))))
87 THROW1(system_error,errcode,"pthread_mutex_lock(%p) failed",mutex);
90 void xbt_mutex_unlock(xbt_mutex_t mutex) {
93 if ((errcode=pthread_mutex_unlock(&(mutex->m))))
94 THROW1(system_error,errcode,"pthread_mutex_unlock(%p) failed",mutex);
97 void xbt_mutex_destroy(xbt_mutex_t mutex) {
100 if ((errcode=pthread_mutex_destroy(&(mutex->m))))
101 THROW1(system_error,errcode,"pthread_mutex_destroy(%p) failed",mutex);
105 /***** condition related functions *****/
106 typedef struct xbt_thcond_ {
110 xbt_thcond_t xbt_thcond_init(void) {
111 xbt_thcond_t res = xbt_new(s_xbt_thcond_t,1);
113 if ((errcode=pthread_cond_init(&(res->c),NULL)))
114 THROW0(system_error,errcode,"pthread_cond_init() failed");
119 void xbt_thcond_wait(xbt_thcond_t cond, xbt_mutex_t mutex) {
121 if ((errcode=pthread_cond_wait(&(cond->c),&(mutex->m))))
122 THROW2(system_error,errcode,"pthread_cond_wait(%p,%p) failed",cond,mutex);
125 void xbt_thcond_signal(xbt_thcond_t cond) {
127 if ((errcode=pthread_cond_signal(&(cond->c))))
128 THROW1(system_error,errcode,"pthread_cond_signal(%p) failed",cond);
131 void xbt_thcond_broadcast(xbt_thcond_t cond){
133 if ((errcode=pthread_cond_broadcast(&(cond->c))))
134 THROW1(system_error,errcode,"pthread_cond_broadcast(%p) failed",cond);
136 void xbt_thcond_destroy(xbt_thcond_t cond){
138 if ((errcode=pthread_cond_destroy(&(cond->c))))
139 THROW1(system_error,errcode,"pthread_cond_destroy(%p) failed",cond);
145 typedef struct xbt_thread_ {
146 HANDLE handle; /* the win thread handle */
147 unsigned long id; /* the win thread id */
150 void xbt_thread_mod_init(void) {}
151 void xbt_thread_mod_exit(void) {}
153 xbt_thread_t xbt_thread_create(pvoid_f_pvoid_t start_routine,
156 xbt_thread_t res = xbt_new(s_xbt_thread_t,1);
158 res->handle = CreateThread(NULL,NULL,start_routine,param,0,&((*thread)->id));
162 THROW0(system_error,errcode,"CreateThread failed");
168 void xbt_thread_exit(int *retval) {
169 xbt_thread_t self = xbt_thread_self();
171 CloseHandle(self->handle);
177 xbt_thread_t xbt_thread_self(void) {
178 return GetCurrentThreadId();
181 void xbt_thread_yield(void) {
185 /****** mutex related functions ******/
186 typedef struct xbt_mutex_ {
187 CRITICAL_SECTION lock;
190 xbt_mutex_t xbt_mutex_init(void) {
191 xbt_mutex_t res = xbt_new(s_xbt_mutex_t,1);
193 /* initialize the critical section object */
194 InitializeCriticalSection(&(res->lock));
199 void xbt_mutex_lock(xbt_mutex_t mutex) {
201 EnterCriticalSection(& mutex->lock);
204 void xbt_mutex_unlock(xbt_mutex_t mutex) {
206 LeaveCriticalSection (& mutex->lock);
210 void xbt_mutex_destroy(xbt_mutex_t mutex) {
212 DeleteCriticalSection(& mutex->lock);
217 /***** condition related functions *****/
218 typedef struct xbt_thcond_ {
219 HANDLE events[MAX_EVENTS];
221 unsigned int waiters_count; /* the number of waiters */
222 CRITICAL_SECTION waiters_count_lock; /* protect access to waiters_count */
225 xbt_thcond_t xbt_thcond_init(void) {
227 xbt_thcond_t res = xbt_new0(s_xbt_thcond_t,1);
229 memset(& res->waiters_count_lock,0,sizeof(CRITICAL_SECTION));
231 /* initialize the critical section object */
232 InitializeCriticalSection(& res->waiters_count_lock);
234 res->waiters_count = 0;
236 /* Create an auto-reset event */
237 res->events[SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL);
239 if(!res->events[SIGNAL]){
240 DeleteCriticalSection(&((*cond)->waiters_count_lock));
242 THROW0(system_error,0,"CreateEvent failed for the signals");
245 /* Create a manual-reset event. */
246 res->events[BROADCAST] = CreateEvent (NULL, TRUE, FALSE,NULL);
248 if(!res->events[BROADCAST]){
250 DeleteCriticalSection(& res->waiters_count_lock);
251 CloseHandle(res->events[SIGNAL]);
253 THROW0(system_error,0,"CreateEvent failed for the broadcasts");
259 void xbt_thcond_wait(xbt_thcond_t cond, xbt_mutex_t mutex) {
261 unsigned long wait_result;
264 /* lock the threads counter and increment it */
265 EnterCriticalSection (& cond->waiters_count_lock);
266 cond->waiters_count++;
267 LeaveCriticalSection (& cond->waiters_count_lock);
269 /* unlock the mutex associate with the condition */
270 LeaveCriticalSection (& mutex->lock);
272 /* wait for a signal (broadcast or no) */
273 wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
275 if(wait_result == WAIT_FAILED)
276 THROW0(system_error,0,"WaitForMultipleObjects failed, so we cannot wait on the condition");
278 /* we have a signal lock the condition */
279 EnterCriticalSection (& cond->waiters_count_lock);
280 cond->waiters_count--;
282 /* it's the last waiter or it's a broadcast ? */
283 is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1) && (cond->waiters_count == 0));
285 LeaveCriticalSection (& cond->waiters_count_lock);
287 /* yes it's the last waiter or it's a broadcast
288 * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
292 if(!ResetEvent (cond->events[BROADCAST]))
293 THROW0(system_error,0,"ResetEvent failed");
295 /* relock the mutex associated with the condition in accordance with the posix thread specification */
296 EnterCriticalSection (& mutex->lock);
299 void xbt_thcond_signal(xbt_thcond_t cond) {
302 EnterCriticalSection (& cond->waiters_count_lock);
303 have_waiters = cond->waiters_count > 0;
304 LeaveCriticalSection (& cond->waiters_count_lock);
307 if(!SetEvent(cond->events[SIGNAL]))
308 THROW0(system_error,0,"SetEvent failed");
311 void xbt_thcond_broadcast(xbt_thcond_t cond){
314 EnterCriticalSection (& cond->waiters_count_lock);
315 have_waiters = cond->waiters_count > 0;
316 LeaveCriticalSection (& cond->waiters_count_lock);
319 SetEvent(cond->events[BROADCAST]);
322 void xbt_thcond_destroy(xbt_thcond_t cond){
325 if(!CloseHandle(cond->events[SIGNAL]))
328 if(!CloseHandle(cond->events[BROADCAST]))
331 DeleteCriticalSection(& cond->waiters_count_lock);
336 THROW0(system_error,0,"Error while destroying the condition");