Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
73fe3a4fdca7e62f477944b4c8eed1a9facf7f82
[simgrid.git] / src / xbt / xbt_os_thread.c
1 /* $Id$ */
2
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   */
6
7 /* Copyright 2006,2007 Malek Cherier, Martin Quinson          
8  * All right reserved.                                                      */
9
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. */
12
13 #include "xbt/sysdep.h"
14 #include "xbt/ex.h"
15 #include "portable.h"
16 #include "xbt/xbt_os_thread.h" /* This module */
17 #include "xbt_modinter.h" /* Initialization/finalization of this module */
18
19
20
21 /* ********************************* PTHREAD IMPLEMENTATION ************************************ */
22 #ifdef HAVE_PTHREAD_H
23 #include <pthread.h>
24
25 typedef struct xbt_os_thread_ {
26   /* KEEP IT IN SYNC WITH xbt_thread.c */
27    pthread_t t;
28    void *param;
29    pvoid_f_pvoid_t *start_routine;
30 } s_xbt_os_thread_t ;
31
32 /* thread-specific data containing the xbt_os_thread_t structure */
33 static pthread_key_t xbt_self_thread_key;
34
35 /* frees the xbt_os_thread_t corresponding to the current thread */
36 static void xbt_os_thread_free_thread_data(void*d){
37    free(d);
38 }
39
40 void xbt_os_thread_mod_init(void) {
41    int errcode;
42    
43    if ((errcode=pthread_key_create(&xbt_self_thread_key, NULL)))
44      THROW0(system_error,errcode,"pthread_key_create failed for xbt_self_thread_key");
45 }
46 void xbt_os_thread_mod_exit(void) {
47    /* FIXME: don't try to free our key on shutdown. Valgrind detects no leak if we don't, and whine if we try to */
48 //   int errcode;
49    
50 //   if ((errcode=pthread_key_delete(xbt_self_thread_key)))
51 //     THROW0(system_error,errcode,"pthread_key_delete failed for xbt_self_thread_key");
52 }
53
54 static void * wrapper_start_routine(void *s) {
55   xbt_os_thread_t t = s;   
56   int errcode;
57
58   if ((errcode=pthread_setspecific(xbt_self_thread_key,t)))
59     THROW0(system_error,errcode,"pthread_setspecific failed for xbt_self_thread_key");   
60   return t->start_routine(t->param);
61 }
62
63 xbt_os_thread_t xbt_os_thread_create(pvoid_f_pvoid_t start_routine,
64                                      void* param)  {
65    int errcode;
66
67    xbt_os_thread_t res_thread=xbt_new(s_xbt_os_thread_t,1);
68    res_thread->start_routine = start_routine;
69    res_thread->param = param;
70
71    
72    if ((errcode = pthread_create(&(res_thread->t), NULL, wrapper_start_routine, res_thread)))
73      THROW1(system_error,errcode, "pthread_create failed: %s",strerror(errcode));
74
75    return res_thread;
76 }
77
78 void 
79 xbt_os_thread_join(xbt_os_thread_t thread,void ** thread_return) {
80         
81         int errcode;   
82         
83         if ((errcode = pthread_join(thread->t,thread_return)))
84                 THROW1(system_error,errcode, "pthread_join failed: %s",
85                        strerror(errcode));
86         free(thread);   
87 }                      
88
89 void xbt_os_thread_exit(int *retval) {
90    pthread_exit(retval);
91 }
92
93 xbt_os_thread_t xbt_os_thread_self(void) {
94    return pthread_getspecific(xbt_self_thread_key);
95 }
96
97 #include <sched.h>
98 void xbt_os_thread_yield(void) {
99    sched_yield();
100 }
101 /****** mutex related functions ******/
102 typedef struct xbt_os_mutex_ {
103   /* KEEP IT IN SYNC WITH xbt_thread.c */
104    pthread_mutex_t m;
105 } s_xbt_os_mutex_t;
106
107 xbt_os_mutex_t xbt_os_mutex_init(void) {
108    xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t,1);
109    int errcode;
110    
111    if ((errcode = pthread_mutex_init(&(res->m),NULL)))
112      THROW1(system_error,errcode,"pthread_mutex_init() failed: %s",
113             strerror(errcode));
114    
115    return res;
116 }
117
118 void xbt_os_mutex_lock(xbt_os_mutex_t mutex) {
119    int errcode;
120    
121    if ((errcode=pthread_mutex_lock(&(mutex->m))))
122      THROW2(system_error,errcode,"pthread_mutex_lock(%p) failed: %s",
123             mutex, strerror(errcode));
124 }
125
126 void xbt_os_mutex_unlock(xbt_os_mutex_t mutex) {
127    int errcode;
128    
129    if ((errcode=pthread_mutex_unlock(&(mutex->m))))
130      THROW2(system_error,errcode,"pthread_mutex_unlock(%p) failed: %s",
131             mutex, strerror(errcode));
132 }
133
134 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex) {
135    int errcode;
136    
137    if (!mutex) return;
138    
139    if ((errcode=pthread_mutex_destroy(&(mutex->m))))
140      THROW2(system_error,errcode,"pthread_mutex_destroy(%p) failed: %s",
141             mutex, strerror(errcode));
142    free(mutex);
143 }
144
145 /***** condition related functions *****/
146 typedef struct xbt_os_cond_ {
147   /* KEEP IT IN SYNC WITH xbt_thread.c */
148    pthread_cond_t c;
149 } s_xbt_os_cond_t;
150
151 xbt_os_cond_t xbt_os_cond_init(void) {
152    xbt_os_cond_t res = xbt_new(s_xbt_os_cond_t,1);
153    int errcode;
154    if ((errcode=pthread_cond_init(&(res->c),NULL)))
155      THROW1(system_error,errcode,"pthread_cond_init() failed: %s",
156             strerror(errcode));
157
158    return res;
159 }
160
161 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex) {
162    int errcode;
163    if ((errcode=pthread_cond_wait(&(cond->c),&(mutex->m))))
164      THROW3(system_error,errcode,"pthread_cond_wait(%p,%p) failed: %s",
165             cond,mutex, strerror(errcode));
166 }
167
168 void xbt_os_cond_signal(xbt_os_cond_t cond) {
169    int errcode;
170    if ((errcode=pthread_cond_signal(&(cond->c))))
171      THROW2(system_error,errcode,"pthread_cond_signal(%p) failed: %s",
172             cond, strerror(errcode));
173 }
174          
175 void xbt_os_cond_broadcast(xbt_os_cond_t cond){
176    int errcode;
177    if ((errcode=pthread_cond_broadcast(&(cond->c))))
178      THROW2(system_error,errcode,"pthread_cond_broadcast(%p) failed: %s",
179             cond, strerror(errcode));
180 }
181 void xbt_os_cond_destroy(xbt_os_cond_t cond){
182    int errcode;
183
184    if (!cond) return;
185
186    if ((errcode=pthread_cond_destroy(&(cond->c))))
187      THROW2(system_error,errcode,"pthread_cond_destroy(%p) failed: %s",
188             cond, strerror(errcode));
189    free(cond);
190 }
191
192 /* ********************************* WINDOWS IMPLEMENTATION ************************************ */
193
194 #elif defined(WIN32)
195
196 typedef struct xbt_os_thread_ {
197   /* KEEP IT IN SYNC WITH xbt_thread */
198   HANDLE handle;                  /* the win thread handle        */
199   unsigned long id;               /* the win thread id            */
200   pvoid_f_pvoid_t *start_routine;
201   void* param;
202 } s_xbt_os_thread_t ;
203
204 /* key to the TLS containing the xbt_os_thread_t structure */
205 static unsigned long xbt_self_thread_key;
206
207 void xbt_os_thread_mod_init(void) {
208    xbt_self_thread_key = TlsAlloc();
209 }
210 void xbt_os_thread_mod_exit(void) {
211    
212    if (!TlsFree(xbt_self_thread_key)) 
213      THROW0(system_error,(int)GetLastError(),"TlsFree() failed to cleanup the thread submodule");
214 }
215
216 static DWORD WINAPI  wrapper_start_routine(void *s) {
217   xbt_os_thread_t t = (xbt_os_thread_t)s;
218  
219     if(!TlsSetValue(xbt_self_thread_key,t))
220      THROW0(system_error,(int)GetLastError(),"TlsSetValue of data describing the created thread failed");
221    
222    return (DWORD)t->start_routine(t->param);
223 }
224
225
226 xbt_os_thread_t xbt_os_thread_create(pvoid_f_pvoid_t start_routine,
227                                void* param)  {
228    
229    xbt_os_thread_t t = xbt_new(s_xbt_os_thread_t,1);
230
231    t->start_routine = start_routine ;
232    t->param = param;
233    
234    t->handle = CreateThread(NULL,0,
235                             (LPTHREAD_START_ROUTINE)wrapper_start_routine,
236                             t,0,&(t->id));
237         
238    if(!t->handle) {
239      xbt_free(t);
240      THROW0(system_error,(int)GetLastError(),"CreateThread failed");
241    }
242    
243    return t;
244 }
245
246 void 
247 xbt_os_thread_join(xbt_os_thread_t thread,void ** thread_return) {
248
249         if(WAIT_OBJECT_0 != WaitForSingleObject(thread->handle,INFINITE))  
250                 THROW0(system_error,(int)GetLastError(), "WaitForSingleObject failed");
251                 
252         if(thread_return){
253                 
254                 if(!GetExitCodeThread(thread->handle,(DWORD*)(*thread_return)))
255                         THROW0(system_error,(int)GetLastError(), "GetExitCodeThread failed");
256         }
257         
258         CloseHandle(thread->handle);
259         free(thread);
260 }
261
262 void xbt_os_thread_exit(int *retval) {
263    if(retval)
264         ExitThread(*retval);
265    else
266         ExitThread(0);
267 }
268
269 xbt_os_thread_t xbt_os_thread_self(void) {
270    return TlsGetValue(xbt_self_thread_key);
271 }
272
273 void xbt_os_thread_yield(void) {
274     Sleep(0);
275 }
276
277 /****** mutex related functions ******/
278 typedef struct xbt_os_mutex_ {
279   /* KEEP IT IN SYNC WITH xbt_thread.c */
280    CRITICAL_SECTION lock;   
281 } s_xbt_os_mutex_t;
282
283 xbt_os_mutex_t xbt_os_mutex_init(void) {
284    xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t,1);
285
286    /* initialize the critical section object */
287    InitializeCriticalSection(&(res->lock));
288    
289    return res;
290 }
291
292 void xbt_os_mutex_lock(xbt_os_mutex_t mutex) {
293
294    EnterCriticalSection(& mutex->lock);
295 }
296
297 void xbt_os_mutex_unlock(xbt_os_mutex_t mutex) {
298
299    LeaveCriticalSection (& mutex->lock);
300
301 }
302
303 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex) {
304
305    if (!mutex) return;
306    
307    DeleteCriticalSection(& mutex->lock);                
308    free(mutex);
309 }
310
311 /***** condition related functions *****/
312  enum { /* KEEP IT IN SYNC WITH xbt_thread.c */
313     SIGNAL = 0,
314     BROADCAST = 1,
315     MAX_EVENTS = 2
316  };
317
318 typedef struct xbt_os_cond_ {
319   /* KEEP IT IN SYNC WITH xbt_thread.c */
320    HANDLE events[MAX_EVENTS];
321    
322    unsigned int waiters_count;           /* the number of waiters                        */
323    CRITICAL_SECTION waiters_count_lock;  /* protect access to waiters_count  */
324 } s_xbt_os_cond_t;
325
326 xbt_os_cond_t xbt_os_cond_init(void) {
327
328    xbt_os_cond_t res = xbt_new0(s_xbt_os_cond_t,1);
329         
330    memset(& res->waiters_count_lock,0,sizeof(CRITICAL_SECTION));
331         
332    /* initialize the critical section object */
333    InitializeCriticalSection(& res->waiters_count_lock);
334         
335    res->waiters_count = 0;
336         
337    /* Create an auto-reset event */
338    res->events[SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL); 
339         
340    if(!res->events[SIGNAL]){
341       DeleteCriticalSection(& res->waiters_count_lock);
342       free(res);
343       THROW0(system_error,0,"CreateEvent failed for the signals");
344    }
345         
346    /* Create a manual-reset event. */
347    res->events[BROADCAST] = CreateEvent (NULL, TRUE, FALSE,NULL);
348         
349    if(!res->events[BROADCAST]){
350                 
351       DeleteCriticalSection(& res->waiters_count_lock);         
352       CloseHandle(res->events[SIGNAL]);
353       free(res); 
354       THROW0(system_error,0,"CreateEvent failed for the broadcasts");
355    }
356
357    return res;
358 }
359
360 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex) {
361         
362    unsigned long wait_result;
363    int is_last_waiter;
364
365    /* lock the threads counter and increment it */
366    EnterCriticalSection (& cond->waiters_count_lock);
367    cond->waiters_count++;
368    LeaveCriticalSection (& cond->waiters_count_lock);
369                 
370    /* unlock the mutex associate with the condition */
371    LeaveCriticalSection (& mutex->lock);
372         
373    /* wait for a signal (broadcast or no) */
374    wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
375         
376    if(wait_result == WAIT_FAILED)
377      THROW0(system_error,0,"WaitForMultipleObjects failed, so we cannot wait on the condition");
378         
379    /* we have a signal lock the condition */
380    EnterCriticalSection (& cond->waiters_count_lock);
381    cond->waiters_count--;
382         
383    /* it's the last waiter or it's a broadcast ? */
384    is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1) && (cond->waiters_count == 0));
385         
386    LeaveCriticalSection (& cond->waiters_count_lock);
387         
388    /* yes it's the last waiter or it's a broadcast
389     * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
390     * by the system. 
391     */
392    if (is_last_waiter)
393       if(!ResetEvent (cond->events[BROADCAST]))
394         THROW0(system_error,0,"ResetEvent failed");
395         
396    /* relock the mutex associated with the condition in accordance with the posix thread specification */
397    EnterCriticalSection (& mutex->lock);
398 }
399
400 void xbt_os_cond_signal(xbt_os_cond_t cond) {
401    int have_waiters;
402
403    EnterCriticalSection (& cond->waiters_count_lock);
404    have_waiters = cond->waiters_count > 0;
405    LeaveCriticalSection (& cond->waiters_count_lock);
406         
407    if (have_waiters)
408      if(!SetEvent(cond->events[SIGNAL]))
409        THROW0(system_error,0,"SetEvent failed");
410        
411    xbt_os_thread_yield();
412 }
413
414 void xbt_os_cond_broadcast(xbt_os_cond_t cond){
415    int have_waiters;
416
417    EnterCriticalSection (& cond->waiters_count_lock);
418    have_waiters = cond->waiters_count > 0;
419    LeaveCriticalSection (& cond->waiters_count_lock);
420         
421    if (have_waiters)
422      SetEvent(cond->events[BROADCAST]);
423 }
424
425 void xbt_os_cond_destroy(xbt_os_cond_t cond){
426    int error = 0;
427    
428    if (!cond) return;
429    
430    if(!CloseHandle(cond->events[SIGNAL]))
431      error = 1;
432         
433    if(!CloseHandle(cond->events[BROADCAST]))
434      error = 1;
435         
436    DeleteCriticalSection(& cond->waiters_count_lock);
437         
438    xbt_free(cond);
439    
440    if (error)
441      THROW0(system_error,0,"Error while destroying the condition");
442 }
443
444 #endif