Logo AND Algorithmique Numérique Distribuée

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