Logo AND Algorithmique Numérique Distribuée

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