Logo AND Algorithmique Numérique Distribuée

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