Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
implement versatile threads (working both on simulator and in situ); the simulated...
[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
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 #include <time.h>
169 #include <math.h>
170 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex, double delay) {
171    int errcode;
172    struct timespec ts_end;
173    double end = delay + xbt_os_time();
174    ts_end.tv_sec = (time_t) floor(end);
175    ts_end.tv_nsec = (long)  ( ( end - ts_end.tv_sec) * 1000000000);
176    switch ( (errcode=pthread_cond_timedwait(&(cond->c),&(mutex->m), &ts_end)) ) {
177     case ETIMEDOUT:
178      THROW3(timeout_error,errcode,"condition %p (mutex %p) wasn't signaled before timeout (%f)",
179             cond,mutex, delay);
180     default:
181      THROW4(system_error,errcode,"pthread_cond_timedwait(%p,%p,%f) failed: %s",
182             cond,mutex, delay, strerror(errcode));
183    }   
184 }
185
186 void xbt_os_cond_signal(xbt_os_cond_t cond) {
187    int errcode;
188    if ((errcode=pthread_cond_signal(&(cond->c))))
189      THROW2(system_error,errcode,"pthread_cond_signal(%p) failed: %s",
190             cond, strerror(errcode));
191 }
192          
193 void xbt_os_cond_broadcast(xbt_os_cond_t cond){
194    int errcode;
195    if ((errcode=pthread_cond_broadcast(&(cond->c))))
196      THROW2(system_error,errcode,"pthread_cond_broadcast(%p) failed: %s",
197             cond, strerror(errcode));
198 }
199 void xbt_os_cond_destroy(xbt_os_cond_t cond){
200    int errcode;
201
202    if (!cond) return;
203
204    if ((errcode=pthread_cond_destroy(&(cond->c))))
205      THROW2(system_error,errcode,"pthread_cond_destroy(%p) failed: %s",
206             cond, strerror(errcode));
207    free(cond);
208 }
209
210 void *xbt_os_thread_getparam(void) {
211    xbt_os_thread_t t = xbt_os_thread_self();
212    return t->param;
213 }
214
215 /* ********************************* WINDOWS IMPLEMENTATION ************************************ */
216
217 #elif defined(WIN32)
218
219 typedef struct xbt_os_thread_ {
220   HANDLE handle;                  /* the win thread handle        */
221   unsigned long id;               /* the win thread id            */
222   pvoid_f_pvoid_t *start_routine;
223   void* param;
224 } s_xbt_os_thread_t ;
225
226 /* key to the TLS containing the xbt_os_thread_t structure */
227 static unsigned long xbt_self_thread_key;
228
229 void xbt_os_thread_mod_init(void) {
230    xbt_self_thread_key = TlsAlloc();
231 }
232 void xbt_os_thread_mod_exit(void) {
233    
234    if (!TlsFree(xbt_self_thread_key)) 
235      THROW0(system_error,(int)GetLastError(),"TlsFree() failed to cleanup the thread submodule");
236 }
237
238 static DWORD WINAPI  wrapper_start_routine(void *s) {
239   xbt_os_thread_t t = (xbt_os_thread_t)s;
240  
241     if(!TlsSetValue(xbt_self_thread_key,t))
242      THROW0(system_error,(int)GetLastError(),"TlsSetValue of data describing the created thread failed");
243    
244    return (DWORD)t->start_routine(t->param);
245 }
246
247
248 xbt_os_thread_t xbt_os_thread_create(pvoid_f_pvoid_t start_routine,
249                                void* param)  {
250    
251    xbt_os_thread_t t = xbt_new(s_xbt_os_thread_t,1);
252
253    t->start_routine = start_routine ;
254    t->param = param;
255    
256    t->handle = CreateThread(NULL,0,
257                             (LPTHREAD_START_ROUTINE)wrapper_start_routine,
258                             t,0,&(t->id));
259         
260    if(!t->handle) {
261      xbt_free(t);
262      THROW0(system_error,(int)GetLastError(),"CreateThread failed");
263    }
264    
265    return t;
266 }
267
268 void 
269 xbt_os_thread_join(xbt_os_thread_t thread,void ** thread_return) {
270
271         if(WAIT_OBJECT_0 != WaitForSingleObject(thread->handle,INFINITE))  
272                 THROW0(system_error,(int)GetLastError(), "WaitForSingleObject failed");
273                 
274         if(thread_return){
275                 
276                 if(!GetExitCodeThread(thread->handle,(DWORD*)(*thread_return)))
277                         THROW0(system_error,(int)GetLastError(), "GetExitCodeThread failed");
278         }
279         
280         CloseHandle(thread->handle);
281         free(thread);
282 }
283
284 void xbt_os_thread_exit(int *retval) {
285    if(retval)
286         ExitThread(*retval);
287    else
288         ExitThread(0);
289 }
290
291 xbt_os_thread_t xbt_os_thread_self(void) {
292    return TlsGetValue(xbt_self_thread_key);
293 }
294
295 void *xbt_os_thread_getparam(void) {
296    xbt_os_thread_t t = xbt_os_thread_self();
297    return t->param;
298 }
299
300
301 void xbt_os_thread_yield(void) {
302     Sleep(0);
303 }
304
305 /****** mutex related functions ******/
306 typedef struct xbt_os_mutex_ {
307   /* KEEP IT IN SYNC WITH xbt_thread.c */
308    CRITICAL_SECTION lock;   
309 } s_xbt_os_mutex_t;
310
311 xbt_os_mutex_t xbt_os_mutex_init(void) {
312    xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t,1);
313
314    /* initialize the critical section object */
315    InitializeCriticalSection(&(res->lock));
316    
317    return res;
318 }
319
320 void xbt_os_mutex_lock(xbt_os_mutex_t mutex) {
321
322    EnterCriticalSection(& mutex->lock);
323 }
324
325 void xbt_os_mutex_unlock(xbt_os_mutex_t mutex) {
326
327    LeaveCriticalSection (& mutex->lock);
328
329 }
330
331 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex) {
332
333    if (!mutex) return;
334    
335    DeleteCriticalSection(& mutex->lock);                
336    free(mutex);
337 }
338
339 /***** condition related functions *****/
340  enum { /* KEEP IT IN SYNC WITH xbt_thread.c */
341     SIGNAL = 0,
342     BROADCAST = 1,
343     MAX_EVENTS = 2
344  };
345
346 typedef struct xbt_os_cond_ {
347   /* KEEP IT IN SYNC WITH xbt_thread.c */
348    HANDLE events[MAX_EVENTS];
349    
350    unsigned int waiters_count;           /* the number of waiters                        */
351    CRITICAL_SECTION waiters_count_lock;  /* protect access to waiters_count  */
352 } s_xbt_os_cond_t;
353
354 xbt_os_cond_t xbt_os_cond_init(void) {
355
356    xbt_os_cond_t res = xbt_new0(s_xbt_os_cond_t,1);
357         
358    memset(& res->waiters_count_lock,0,sizeof(CRITICAL_SECTION));
359         
360    /* initialize the critical section object */
361    InitializeCriticalSection(& res->waiters_count_lock);
362         
363    res->waiters_count = 0;
364         
365    /* Create an auto-reset event */
366    res->events[SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL); 
367         
368    if(!res->events[SIGNAL]){
369       DeleteCriticalSection(& res->waiters_count_lock);
370       free(res);
371       THROW0(system_error,0,"CreateEvent failed for the signals");
372    }
373         
374    /* Create a manual-reset event. */
375    res->events[BROADCAST] = CreateEvent (NULL, TRUE, FALSE,NULL);
376         
377    if(!res->events[BROADCAST]){
378                 
379       DeleteCriticalSection(& res->waiters_count_lock);         
380       CloseHandle(res->events[SIGNAL]);
381       free(res); 
382       THROW0(system_error,0,"CreateEvent failed for the broadcasts");
383    }
384
385    return res;
386 }
387
388 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex) {
389         
390    unsigned long wait_result;
391    int is_last_waiter;
392
393    /* lock the threads counter and increment it */
394    EnterCriticalSection (& cond->waiters_count_lock);
395    cond->waiters_count++;
396    LeaveCriticalSection (& cond->waiters_count_lock);
397                 
398    /* unlock the mutex associate with the condition */
399    LeaveCriticalSection (& mutex->lock);
400         
401    /* wait for a signal (broadcast or no) */
402    wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
403         
404    if(wait_result == WAIT_FAILED)
405      THROW0(system_error,0,"WaitForMultipleObjects failed, so we cannot wait on the condition");
406         
407    /* we have a signal lock the condition */
408    EnterCriticalSection (& cond->waiters_count_lock);
409    cond->waiters_count--;
410         
411    /* it's the last waiter or it's a broadcast ? */
412    is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1) && (cond->waiters_count == 0));
413         
414    LeaveCriticalSection (& cond->waiters_count_lock);
415         
416    /* yes it's the last waiter or it's a broadcast
417     * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
418     * by the system. 
419     */
420    if (is_last_waiter)
421       if(!ResetEvent (cond->events[BROADCAST]))
422         THROW0(system_error,0,"ResetEvent failed");
423         
424    /* relock the mutex associated with the condition in accordance with the posix thread specification */
425    EnterCriticalSection (& mutex->lock);
426 }
427 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex, double delay) {
428    THROW_UNIMPLEMENTED;
429 }
430
431 void xbt_os_cond_signal(xbt_os_cond_t cond) {
432    int have_waiters;
433
434    EnterCriticalSection (& cond->waiters_count_lock);
435    have_waiters = cond->waiters_count > 0;
436    LeaveCriticalSection (& cond->waiters_count_lock);
437         
438    if (have_waiters)
439      if(!SetEvent(cond->events[SIGNAL]))
440        THROW0(system_error,0,"SetEvent failed");
441        
442    xbt_os_thread_yield();
443 }
444
445 void xbt_os_cond_broadcast(xbt_os_cond_t cond){
446    int have_waiters;
447
448    EnterCriticalSection (& cond->waiters_count_lock);
449    have_waiters = cond->waiters_count > 0;
450    LeaveCriticalSection (& cond->waiters_count_lock);
451         
452    if (have_waiters)
453      SetEvent(cond->events[BROADCAST]);
454 }
455
456 void xbt_os_cond_destroy(xbt_os_cond_t cond){
457    int error = 0;
458    
459    if (!cond) return;
460    
461    if(!CloseHandle(cond->events[SIGNAL]))
462      error = 1;
463         
464    if(!CloseHandle(cond->events[BROADCAST]))
465      error = 1;
466         
467    DeleteCriticalSection(& cond->waiters_count_lock);
468         
469    xbt_free(cond);
470    
471    if (error)
472      THROW0(system_error,0,"Error while destroying the condition");
473 }
474
475 #endif