Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
2ca9e911e09c005c150aab4a52d0aaf9f0cbbfcc
[simgrid.git] / src / xbt / xbt_thread.c
1 /* $Id$ */
2
3 /* xbt_thread -- portability layer over the pthread API                     */
4
5 /* Copyright 2006,2007 Malek Cherier, Martin Quinson          
6  * All right reserved.                                                      */
7
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. */
10
11 #include "xbt/sysdep.h"
12 #include "xbt/ex.h"
13 #include "portable.h"
14 #include "xbt/xbt_thread.h" /* This module */
15 #include "xbt_modinter.h" /* Initialization/finalization of this module */
16
17 #ifdef HAVE_PTHREAD_H
18 #include <pthread.h>
19
20 typedef struct xbt_thread_ {
21    pthread_t t;
22 } s_xbt_thread_t ;
23
24 /* frees the xbt_thread_t corresponding to the current thread */
25 static void xbt_thread_free_thread_data(void*d){
26    free(d);
27 }
28
29 pthread_key_t thread_data; /* thread-specific data containing the xbt_thread_t structure */
30 void xbt_thread_mod_init(void) {
31    int errcode;
32    
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");
35 }
36 void xbt_thread_mod_exit(void) {
37    int errcode;
38    
39    if ((errcode=pthread_key_delete(thread_data)))
40      THROW0(system_error,errcode,"pthread_key_delete failed for thread_data");
41 }
42
43
44 xbt_thread_t xbt_thread_create(pvoid_f_pvoid_t start_routine,
45                                void* param)  {
46    xbt_thread_t res = xbt_new(s_xbt_thread_t,1);
47    int errcode;
48
49    if ((errcode=pthread_setspecific(thread_data,res)))
50      THROW0(system_error,errcode,"pthread_setspecific failed for thread_data");
51       
52    if ((errcode = pthread_create(&(res->t), NULL, start_routine, param)))
53      THROW0(system_error,errcode, "pthread_create failed");
54    
55    return res;
56 }                      
57 void xbt_thread_exit(int *retval) {
58    pthread_exit(retval);
59 }
60 xbt_thread_t xbt_thread_self(void) {
61    return pthread_getspecific(thread_data);
62 }
63
64 #include <sched.h>
65 void xbt_thread_yield(void) {
66    sched_yield();
67 }
68 /****** mutex related functions ******/
69 typedef struct xbt_mutex_ {
70    pthread_mutex_t m;
71 } s_xbt_mutex_t;
72
73 xbt_mutex_t xbt_mutex_init(void) {
74    xbt_mutex_t res = xbt_new(s_xbt_mutex_t,1);
75    int errcode;
76    
77    if ((errcode = pthread_mutex_init(&(res->m),NULL)))
78      THROW0(system_error,errcode,"pthread_mutex_init() failed");
79    
80    return res;
81 }
82
83 void xbt_mutex_lock(xbt_mutex_t mutex) {
84    int errcode;
85    
86    if ((errcode=pthread_mutex_lock(&(mutex->m))))
87      THROW1(system_error,errcode,"pthread_mutex_lock(%p) failed",mutex);
88 }
89
90 void xbt_mutex_unlock(xbt_mutex_t mutex) {
91    int errcode;
92    
93    if ((errcode=pthread_mutex_unlock(&(mutex->m))))
94      THROW1(system_error,errcode,"pthread_mutex_unlock(%p) failed",mutex);
95 }
96
97 void xbt_mutex_destroy(xbt_mutex_t mutex) {
98    int errcode;
99    
100    if ((errcode=pthread_mutex_destroy(&(mutex->m))))
101      THROW1(system_error,errcode,"pthread_mutex_destroy(%p) failed",mutex);
102    free(mutex);
103 }
104
105 /***** condition related functions *****/
106 typedef struct xbt_thcond_ {
107    pthread_cond_t c;
108 } s_xbt_thcond_t;
109
110 xbt_thcond_t xbt_thcond_init(void) {
111    xbt_thcond_t res = xbt_new(s_xbt_thcond_t,1);
112    int errcode;
113    if ((errcode=pthread_cond_init(&(res->c),NULL)))
114      THROW0(system_error,errcode,"pthread_cond_init() failed");
115
116    return res;
117 }
118
119 void xbt_thcond_wait(xbt_thcond_t cond, xbt_mutex_t mutex) {
120    int errcode;
121    if ((errcode=pthread_cond_wait(&(cond->c),&(mutex->m))))
122      THROW2(system_error,errcode,"pthread_cond_wait(%p,%p) failed",cond,mutex);
123 }
124
125 void xbt_thcond_signal(xbt_thcond_t cond) {
126    int errcode;
127    if ((errcode=pthread_cond_signal(&(cond->c))))
128      THROW1(system_error,errcode,"pthread_cond_signal(%p) failed",cond);
129 }
130          
131 void xbt_thcond_broadcast(xbt_thcond_t cond){
132    int errcode;
133    if ((errcode=pthread_cond_broadcast(&(cond->c))))
134      THROW1(system_error,errcode,"pthread_cond_broadcast(%p) failed",cond);
135 }
136 void xbt_thcond_destroy(xbt_thcond_t cond){
137    int errcode;
138    if ((errcode=pthread_cond_destroy(&(cond->c))))
139      THROW1(system_error,errcode,"pthread_cond_destroy(%p) failed",cond);
140    free(cond);
141 }
142
143
144 #elif defined(WIN32)
145 typedef struct xbt_thread_ {
146    HANDLE handle;                  /* the win thread handle        */
147    unsigned long id;               /* the win thread id            */
148 } s_xbt_thread_t ;
149
150 void xbt_thread_mod_init(void) {}
151 void xbt_thread_mod_exit(void) {}
152
153 xbt_thread_t xbt_thread_create(pvoid_f_pvoid_t start_routine,
154                                void* param)  {
155    
156    xbt_thread_t res = xbt_new(s_xbt_thread_t,1);
157    
158    res->handle = CreateThread(NULL,NULL,start_routine,param,0,&((*thread)->id));
159         
160    if(!res->handle) {
161      xbt_free(res);
162      THROW0(system_error,errcode,"CreateThread failed");
163    }
164    
165    return res;
166 }
167
168 void xbt_thread_exit(int *retval) {
169    xbt_thread_t self = xbt_thread_self();
170    
171    CloseHandle(self->handle);
172    free(self);
173    
174    ExitThread(*retval);
175 }
176
177 xbt_thread_t xbt_thread_self(void) {
178    return GetCurrentThreadId();
179 }
180
181 void xbt_thread_yield(void) {
182     Sleep(0);
183 }
184
185 /****** mutex related functions ******/
186 typedef struct xbt_mutex_ {
187    CRITICAL_SECTION lock;   
188 } s_xbt_mutex_t;
189
190 xbt_mutex_t xbt_mutex_init(void) {
191    xbt_mutex_t res = xbt_new(s_xbt_mutex_t,1);
192
193    /* initialize the critical section object */
194    InitializeCriticalSection(&(res->lock));
195    
196    return res;
197 }
198
199 void xbt_mutex_lock(xbt_mutex_t mutex) {
200
201    EnterCriticalSection(& mutex->lock);
202 }
203
204 void xbt_mutex_unlock(xbt_mutex_t mutex) {
205
206    LeaveCriticalSection (& mutex->lock);
207
208 }
209
210 void xbt_mutex_destroy(xbt_mutex_t mutex) {
211
212    DeleteCriticalSection(& mutex->lock);
213                 
214    free(mutex);
215 }
216
217 /***** condition related functions *****/
218 typedef struct xbt_thcond_ {
219    HANDLE events[MAX_EVENTS];
220    
221    unsigned int waiters_count;           /* the number of waiters                        */
222    CRITICAL_SECTION waiters_count_lock;  /* protect access to waiters_count  */
223 } s_xbt_thcond_t;
224
225 xbt_thcond_t xbt_thcond_init(void) {
226
227    xbt_thcond_t res = xbt_new0(s_xbt_thcond_t,1);
228         
229    memset(& res->waiters_count_lock,0,sizeof(CRITICAL_SECTION));
230         
231    /* initialize the critical section object */
232    InitializeCriticalSection(& res->waiters_count_lock);
233         
234    res->waiters_count = 0;
235         
236    /* Create an auto-reset event */
237    res->events[SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL); 
238         
239    if(!res->events[SIGNAL]){
240       DeleteCriticalSection(&((*cond)->waiters_count_lock));
241       free(res);
242       THROW0(system_error,0,"CreateEvent failed for the signals");
243    }
244         
245    /* Create a manual-reset event. */
246    res->events[BROADCAST] = CreateEvent (NULL, TRUE, FALSE,NULL);
247         
248    if(!res->events[BROADCAST]){
249                 
250       DeleteCriticalSection(& res->waiters_count_lock);         
251       CloseHandle(res->events[SIGNAL]);
252       free(res); 
253       THROW0(system_error,0,"CreateEvent failed for the broadcasts");
254    }
255
256    return res;
257 }
258
259 void xbt_thcond_wait(xbt_thcond_t cond, xbt_mutex_t mutex) {
260         
261    unsigned long wait_result;
262    int is_last_waiter;
263
264    /* lock the threads counter and increment it */
265    EnterCriticalSection (& cond->waiters_count_lock);
266    cond->waiters_count++;
267    LeaveCriticalSection (& cond->waiters_count_lock);
268                 
269    /* unlock the mutex associate with the condition */
270    LeaveCriticalSection (& mutex->lock);
271         
272    /* wait for a signal (broadcast or no) */
273    wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
274         
275    if(wait_result == WAIT_FAILED)
276      THROW0(system_error,0,"WaitForMultipleObjects failed, so we cannot wait on the condition");
277         
278    /* we have a signal lock the condition */
279    EnterCriticalSection (& cond->waiters_count_lock);
280    cond->waiters_count--;
281         
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));
284         
285    LeaveCriticalSection (& cond->waiters_count_lock);
286         
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
289     * by the system. 
290     */
291    if (is_last_waiter)
292       if(!ResetEvent (cond->events[BROADCAST]))
293         THROW0(system_error,0,"ResetEvent failed");
294         
295    /* relock the mutex associated with the condition in accordance with the posix thread specification */
296    EnterCriticalSection (& mutex->lock);
297 }
298
299 void xbt_thcond_signal(xbt_thcond_t cond) {
300    int have_waiters;
301
302    EnterCriticalSection (& cond->waiters_count_lock);
303    have_waiters = cond->waiters_count > 0;
304    LeaveCriticalSection (& cond->waiters_count_lock);
305         
306    if (have_waiters)
307      if(!SetEvent(cond->events[SIGNAL]))
308        THROW0(system_error,0,"SetEvent failed");
309 }
310
311 void xbt_thcond_broadcast(xbt_thcond_t cond){
312    int have_waiters;
313
314    EnterCriticalSection (& cond->waiters_count_lock);
315    have_waiters = cond->waiters_count > 0;
316    LeaveCriticalSection (& cond->waiters_count_lock);
317         
318    if (have_waiters)
319      SetEvent(cond->events[BROADCAST]);
320 }
321
322 void xbt_thcond_destroy(xbt_thcond_t cond){
323    int error = 0;
324    
325    if(!CloseHandle(cond->events[SIGNAL]))
326      error = 1;
327         
328    if(!CloseHandle(cond->events[BROADCAST]))
329      error = 1;
330         
331    DeleteCriticalSection(& cond->waiters_count_lock);
332         
333    xbt_free(cond);
334    
335    if (error)
336      THROW0(system_error,0,"Error while destroying the condition");
337 }
338
339 #endif