Logo AND Algorithmique Numérique Distribuée

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