Logo AND Algorithmique Numérique Distribuée

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