Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
22f9a8ea2b5cb5c58139f9bcf11b5aecaac2f558
[simgrid.git] / src / xbt / xbt_os_thread.c
1 /* xbt_os_thread -- portability layer over the pthread API                  */
2 /* Used in RL to get win/lin portability, and in SG when CONTEXT_THREAD     */
3 /* in SG, when using HAVE_UCONTEXT_CONTEXTS, xbt_os_thread_stub is used instead   */
4
5 /* Copyright (c) 2007-2015. The SimGrid Team.
6  * All rights 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 <errno.h>
12
13 #if defined(WIN32)
14 #elif defined(__MACH__) && defined(__APPLE__)
15 #include <stdint.h>
16 #include <sys/types.h>
17 #include <sys/sysctl.h>
18 #else
19 #include <unistd.h>
20 #endif
21
22 #include "src/internal_config.h"
23 #include "xbt/sysdep.h"
24 #include "xbt/ex.h"
25 #include "src/xbt/ex_interface.h"   /* We play crude games with exceptions */
26 #include "src/portable.h"
27 #include "xbt/xbt_os_time.h"    /* Portable time facilities */
28 #include "xbt/xbt_os_thread.h"  /* This module */
29 #include "src/xbt_modinter.h"       /* Initialization/finalization of this module */
30
31 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_sync_os, xbt, "Synchronization mechanism (OS-level)");
32
33 /* ********************************* PTHREAD IMPLEMENTATION ************************************ */
34 #include <pthread.h>
35 #include <limits.h>
36 #include <semaphore.h>
37
38 #ifdef CORE_BINDING
39 #define _GNU_SOURCE
40 #include <sched.h>
41 #endif
42
43 /* use named sempahore when sem_init() does not work */
44 #ifndef HAVE_SEM_INIT
45 static int next_sem_ID = 0;
46 static xbt_os_mutex_t next_sem_ID_lock;
47 #endif
48
49 typedef struct xbt_os_thread_ {
50   pthread_t t;
51   int detached;
52   char *name;
53   void *param;
54   pvoid_f_pvoid_t start_routine;
55   xbt_running_ctx_t *running_ctx;
56   void *extra_data;
57 } s_xbt_os_thread_t;
58 static xbt_os_thread_t main_thread = NULL;
59
60 /* thread-specific data containing the xbt_os_thread_t structure */
61 static pthread_key_t xbt_self_thread_key;
62 static int thread_mod_inited = 0;
63
64 /* defaults attribute for pthreads */
65 //FIXME: find where to put this
66 static pthread_attr_t thread_attr;
67
68 /* frees the xbt_os_thread_t corresponding to the current thread */
69 static void xbt_os_thread_free_thread_data(xbt_os_thread_t thread)
70 {
71   if (thread == main_thread)    /* just killed main thread */
72     main_thread = NULL;
73
74   free(thread->running_ctx);
75   free(thread->name);
76   free(thread);
77 }
78
79 /* callback: context fetching */
80 static xbt_running_ctx_t *_os_thread_get_running_ctx(void)
81 {
82   return xbt_os_thread_self()->running_ctx;
83 }
84
85 /* callback: termination */
86 static void _os_thread_ex_terminate(xbt_ex_t * e)
87 {
88   xbt_ex_display(e);
89   xbt_abort();
90   /* FIXME: there should be a configuration variable to choose to kill everyone or only this one */
91 }
92
93 void xbt_os_thread_mod_preinit(void)
94 {
95   if (thread_mod_inited)
96     return;
97
98   int errcode = pthread_key_create(&xbt_self_thread_key, NULL);
99   xbt_assert(errcode == 0, "pthread_key_create failed for xbt_self_thread_key");
100   
101   main_thread = xbt_new(s_xbt_os_thread_t, 1);
102   main_thread->name = NULL;
103   main_thread->detached = 0;
104   main_thread->name = (char *) "main";
105   main_thread->param = NULL;
106   main_thread->start_routine = NULL;
107   main_thread->running_ctx = xbt_new(xbt_running_ctx_t, 1);
108   main_thread->extra_data = NULL;
109   XBT_RUNNING_CTX_INITIALIZE(main_thread->running_ctx);
110
111   if ((errcode = pthread_setspecific(xbt_self_thread_key, main_thread)))
112     THROWF(system_error, errcode,
113            "Impossible to set the SimGrid identity descriptor to the main thread (pthread_setspecific failed)");
114   
115   __xbt_running_ctx_fetch = _os_thread_get_running_ctx;
116   __xbt_ex_terminate = _os_thread_ex_terminate;
117
118   pthread_attr_init(&thread_attr);
119
120   thread_mod_inited = 1;
121
122 #ifndef HAVE_SEM_INIT
123   next_sem_ID_lock = xbt_os_mutex_init();
124 #endif
125 }
126
127 void xbt_os_thread_mod_postexit(void)
128 {
129   /* FIXME: don't try to free our key on shutdown.
130      Valgrind detects no leak if we don't, and whine if we try to */
131   //   int errcode;
132
133   //   if ((errcode=pthread_key_delete(xbt_self_thread_key)))
134   //     THROWF(system_error,errcode,"pthread_key_delete failed for xbt_self_thread_key");
135   free(main_thread->running_ctx);
136   free(main_thread);
137   main_thread = NULL;
138   thread_mod_inited = 0;
139 #ifndef HAVE_SEM_INIT
140   xbt_os_mutex_destroy(next_sem_ID_lock);
141 #endif
142
143   /* Restore the default exception setup */
144   __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
145   __xbt_ex_terminate = &__xbt_ex_terminate_default;
146 }
147
148 /* this function is critical to tesh+mmalloc, don't mess with it */
149 int xbt_os_thread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
150 {
151   return pthread_atfork(prepare, parent, child);
152 }
153
154 static void *wrapper_start_routine(void *s)
155 {
156   xbt_os_thread_t t = s;
157
158   int errcode = pthread_setspecific(xbt_self_thread_key, t);
159   xbt_assert(errcode == 0, "pthread_setspecific failed for xbt_self_thread_key");
160
161   void *res = t->start_routine(t->param);
162   if (t->detached)
163     xbt_os_thread_free_thread_data(t);
164   return res;
165 }
166
167
168 xbt_os_thread_t xbt_os_thread_create(const char *name,  pvoid_f_pvoid_t start_routine, void *param, void *extra_data)
169 {
170   xbt_os_thread_t res_thread = xbt_new(s_xbt_os_thread_t, 1);
171   res_thread->detached = 0;
172   res_thread->name = xbt_strdup(name);
173   res_thread->start_routine = start_routine;
174   res_thread->param = param;
175   res_thread->running_ctx = xbt_new(xbt_running_ctx_t, 1);
176   XBT_RUNNING_CTX_INITIALIZE(res_thread->running_ctx);
177   res_thread->extra_data = extra_data;
178   
179   int errcode = pthread_create(&(res_thread->t), &thread_attr, wrapper_start_routine, res_thread);
180   xbt_assert(errcode == 0, "pthread_create failed: %s", strerror(errcode));
181
182   return res_thread;
183 }
184
185
186 #ifdef CORE_BINDING
187 int xbt_os_thread_bind(xbt_os_thread_t thread, int cpu){
188   pthread_t pthread = thread->t;
189   int errcode = 0;
190   cpu_set_t cpuset;
191   CPU_ZERO(&cpuset);
192   CPU_SET(cpu, &cpuset);
193   errcode = pthread_setaffinity_np(pthread, sizeof(cpu_set_t), &cpuset);
194   return errcode;
195 }
196 #endif
197
198 void xbt_os_thread_setstacksize(int stack_size)
199 {
200   size_t alignment[] = {
201     xbt_pagesize,
202 #ifdef PTHREAD_STACK_MIN
203     PTHREAD_STACK_MIN,
204 #endif
205     0
206   };
207
208   xbt_assert(stack_size >= 0, "stack size %d is negative, maybe it exceeds MAX_INT?", stack_size);
209
210   size_t sz = stack_size;
211   int res = pthread_attr_setstacksize(&thread_attr, sz);
212
213   for (int i = 0; res == EINVAL && alignment[i] > 0; i++) {
214     /* Invalid size, try again with next multiple of alignment[i]. */
215     size_t rem = sz % alignment[i];
216     if (rem != 0 || sz == 0) {
217       size_t sz2 = sz - rem + alignment[i];
218       XBT_DEBUG("pthread_attr_setstacksize failed for %zd, try again with %zd", sz, sz2);
219       sz = sz2;
220       res = pthread_attr_setstacksize(&thread_attr, sz);
221     }
222   }
223
224   if (res == EINVAL)
225     XBT_WARN("invalid stack size (maybe too big): %zd", sz);
226   else if (res != 0)
227     XBT_WARN("unknown error %d in pthread stacksize setting: %zd", res, sz);
228 }
229
230 void xbt_os_thread_setguardsize(int guard_size)
231 {
232 #ifdef WIN32
233   THROW_UNIMPLEMENTED; //pthread_attr_setguardsize is not implemented in pthread.h on windows
234 #else
235   size_t sz = guard_size;
236   int res = pthread_attr_setguardsize(&thread_attr, sz);
237   if (res)
238     XBT_WARN("pthread_attr_setguardsize failed (%d) for size: %zd", res, sz);
239 #endif
240 }
241
242 const char *xbt_os_thread_name(xbt_os_thread_t t)
243 {
244   return t->name;
245 }
246
247 const char *xbt_os_thread_self_name(void)
248 {
249   xbt_os_thread_t me = xbt_os_thread_self();
250   return me ? me->name : "main";
251 }
252
253 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
254 {
255   int errcode = pthread_join(thread->t, thread_return);
256
257   xbt_assert(errcode==0, "pthread_join failed: %s", strerror(errcode));
258   xbt_os_thread_free_thread_data(thread);
259 }
260
261 void xbt_os_thread_exit(int *retval)
262 {
263   pthread_exit(retval);
264 }
265
266 xbt_os_thread_t xbt_os_thread_self(void)
267 {
268   if (!thread_mod_inited)
269     return NULL;
270
271   return pthread_getspecific(xbt_self_thread_key);
272 }
273
274 void xbt_os_thread_key_create(xbt_os_thread_key_t* key)
275 {
276   int errcode = pthread_key_create(key, NULL);
277   xbt_assert(errcode==0 , "pthread_key_create failed");
278 }
279
280 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value) {
281
282   int errcode = pthread_setspecific(key, value);
283   xbt_assert(errcode==0, "pthread_setspecific failed");
284 }
285
286 void* xbt_os_thread_get_specific(xbt_os_thread_key_t key) {
287   return pthread_getspecific(key);
288 }
289
290 void xbt_os_thread_detach(xbt_os_thread_t thread)
291 {
292   thread->detached = 1;
293   pthread_detach(thread->t);
294 }
295
296 #include <sched.h>
297 void xbt_os_thread_yield(void)
298 {
299   sched_yield();
300 }
301
302 void xbt_os_thread_cancel(xbt_os_thread_t t)
303 {
304   pthread_cancel(t->t);
305 }
306
307 /****** mutex related functions ******/
308 typedef struct xbt_os_mutex_ {
309   /* KEEP IT IN SYNC WITH xbt_thread.c */
310   pthread_mutex_t m;
311 } s_xbt_os_mutex_t;
312
313 #include <time.h>
314 #include <math.h>
315
316 xbt_os_mutex_t xbt_os_mutex_init(void)
317 {
318   xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
319   int errcode = pthread_mutex_init(&(res->m), NULL);
320   xbt_assert(errcode==0, "pthread_mutex_init() failed: %s", strerror(errcode));
321
322   return res;
323 }
324
325 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
326 {
327   int errcode = pthread_mutex_lock(&(mutex->m));
328   xbt_assert(errcode==0, "pthread_mutex_lock(%p) failed: %s", mutex, strerror(errcode));
329 }
330
331
332 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
333 {
334   int errcode;
335
336   if (delay < 0) {
337     xbt_os_mutex_acquire(mutex);
338
339   } else if (delay == 0) {
340     errcode = pthread_mutex_trylock(&(mutex->m));
341
342     switch (errcode) {
343     case 0:
344       return;
345     case ETIMEDOUT:
346       THROWF(timeout_error, 0, "mutex %p not ready", mutex);
347     default:
348       THROWF(system_error, errcode,
349              "xbt_os_mutex_timedacquire(%p) failed: %s", mutex,
350              strerror(errcode));
351     }
352
353
354   } else {
355
356 #ifdef HAVE_MUTEX_TIMEDLOCK
357     struct timespec ts_end;
358     double end = delay + xbt_os_time();
359
360     ts_end.tv_sec = (time_t) floor(end);
361     ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
362     XBT_DEBUG("pthread_mutex_timedlock(%p,%p)", &(mutex->m), &ts_end);
363
364     int errcode = pthread_mutex_timedlock(&(mutex->m), &ts_end);
365
366 #else            /* reimplement it since those lazy libc dudes didn't (Mac OSX, hu?) */
367     double start = xbt_os_time();
368     do {
369       errcode = pthread_mutex_trylock(&(mutex->m));
370       if (errcode == EBUSY)
371         xbt_os_thread_yield();
372     } while (errcode == EBUSY && xbt_os_time() - start < delay);
373
374     if (errcode == EBUSY)
375       errcode = ETIMEDOUT;
376
377 #endif                          /* HAVE_MUTEX_TIMEDLOCK */
378
379     switch (errcode) {
380     case 0:
381       return;
382
383     case ETIMEDOUT:
384       THROWF(timeout_error, delay,
385              "mutex %p wasn't signaled before timeout (%f)", mutex, delay);
386
387     default:
388       THROWF(system_error, errcode,
389              "pthread_mutex_timedlock(%p,%f) failed: %s", mutex, delay,
390              strerror(errcode));
391     }
392   }
393 }
394
395 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
396 {
397   int errcode = pthread_mutex_unlock(&(mutex->m));
398   xbt_assert(errcode==0, "pthread_mutex_unlock(%p) failed: %s", mutex, strerror(errcode));
399 }
400
401 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
402 {
403   if (!mutex)
404     return;
405
406   int errcode = pthread_mutex_destroy(&(mutex->m));
407   xbt_assert(errcode == 0, "pthread_mutex_destroy(%p) failed: %s", mutex, strerror(errcode));
408   free(mutex);
409 }
410
411 /***** condition related functions *****/
412 typedef struct xbt_os_cond_ {
413   /* KEEP IT IN SYNC WITH xbt_thread.c */
414   pthread_cond_t c;
415 } s_xbt_os_cond_t;
416
417 xbt_os_cond_t xbt_os_cond_init(void)
418 {
419   xbt_os_cond_t res = xbt_new(s_xbt_os_cond_t, 1);
420   int errcode = pthread_cond_init(&(res->c), NULL);
421   xbt_assert(errcode==0, "pthread_cond_init() failed: %s", strerror(errcode));
422   return res;
423 }
424
425 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
426 {
427   int errcode = pthread_cond_wait(&(cond->c), &(mutex->m));
428   xbt_assert(errcode==0, "pthread_cond_wait(%p,%p) failed: %s", cond, mutex, strerror(errcode));
429 }
430
431
432 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex, double delay)
433 {
434   int errcode;
435   struct timespec ts_end;
436   double end = delay + xbt_os_time();
437
438   if (delay < 0) {
439     xbt_os_cond_wait(cond, mutex);
440   } else {
441     ts_end.tv_sec = (time_t) floor(end);
442     ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
443     XBT_DEBUG("pthread_cond_timedwait(%p,%p,%p)", &(cond->c), &(mutex->m), &ts_end);
444     switch ((errcode = pthread_cond_timedwait(&(cond->c), &(mutex->m), &ts_end))) {
445     case 0:
446       return;
447     case ETIMEDOUT:
448       THROWF(timeout_error, errcode,
449              "condition %p (mutex %p) wasn't signaled before timeout (%f)",
450              cond, mutex, delay);
451     default:
452       THROWF(system_error, errcode, "pthread_cond_timedwait(%p,%p,%f) failed: %s", cond, mutex, delay, strerror(errcode));
453     }
454   }
455 }
456
457 void xbt_os_cond_signal(xbt_os_cond_t cond)
458 {
459   int errcode = pthread_cond_signal(&(cond->c));
460   xbt_assert(errcode==0, "pthread_cond_signal(%p) failed: %s", cond, strerror(errcode));
461 }
462
463 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
464 {
465   int errcode = pthread_cond_broadcast(&(cond->c));
466   xbt_assert(errcode==0, "pthread_cond_broadcast(%p) failed: %s", cond, strerror(errcode));
467 }
468
469 void xbt_os_cond_destroy(xbt_os_cond_t cond)
470 {
471   if (!cond)
472     return;
473
474   int errcode = pthread_cond_destroy(&(cond->c));
475   xbt_assert(errcode==0, "pthread_cond_destroy(%p) failed: %s", cond, strerror(errcode));
476   free(cond);
477 }
478
479 void *xbt_os_thread_getparam(void)
480 {
481   xbt_os_thread_t t = xbt_os_thread_self();
482   return t ? t->param : NULL;
483 }
484
485 typedef struct xbt_os_sem_ {
486 #ifndef HAVE_SEM_INIT
487   char *name;
488 #endif
489   sem_t s;
490   sem_t *ps;
491 } s_xbt_os_sem_t;
492
493 #ifndef SEM_FAILED
494 #define SEM_FAILED (-1)
495 #endif
496
497 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
498 {
499   xbt_os_sem_t res = xbt_new(s_xbt_os_sem_t, 1);
500
501   /* On some systems (MAC OS X), only the stub of sem_init is to be found.
502    * Any attempt to use it leads to ENOSYS (function not implemented).
503    * If such a prehistoric system is detected, do the job with sem_open instead
504    */
505 #ifdef HAVE_SEM_INIT
506   if (sem_init(&(res->s), 0, value) != 0)
507     THROWF(system_error, errno, "sem_init() failed: %s", strerror(errno));
508   res->ps = &(res->s);
509
510 #else                           /* damn, no sem_init(). Reimplement it */
511
512   xbt_os_mutex_acquire(next_sem_ID_lock);
513   res->name = bprintf("/%d", ++next_sem_ID);
514   xbt_os_mutex_release(next_sem_ID_lock);
515
516   res->ps = sem_open(res->name, O_CREAT, 0644, value);
517   if ((res->ps == (sem_t *) SEM_FAILED) && (errno == ENAMETOOLONG)) {
518     /* Old darwins only allow 13 chars. Did you create *that* amount of semaphores? */
519     res->name[13] = '\0';
520     res->ps = sem_open(res->name, O_CREAT, 0644, value);
521   }
522   if (res->ps == (sem_t *) SEM_FAILED)
523     THROWF(system_error, errno, "sem_open() failed: %s", strerror(errno));
524
525   /* Remove the name from the semaphore namespace: we never join on it */
526   if (sem_unlink(res->name) < 0)
527     THROWF(system_error, errno, "sem_unlink() failed: %s",
528            strerror(errno));
529
530 #endif
531
532   return res;
533 }
534
535 void xbt_os_sem_acquire(xbt_os_sem_t sem)
536 {
537   if (sem_wait(sem->ps) < 0)
538     THROWF(system_error, errno, "sem_wait() failed: %s", strerror(errno));
539 }
540
541 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double delay)
542 {
543   int errcode;
544
545   if (delay < 0) {
546     xbt_os_sem_acquire(sem);
547   } else if (delay == 0) {
548     errcode = sem_trywait(sem->ps);
549
550     switch (errcode) {
551     case 0:
552       return;
553     case ETIMEDOUT:
554       THROWF(timeout_error, 0, "semaphore %p not ready", sem);
555     default:
556       THROWF(system_error, errcode,
557              "xbt_os_sem_timedacquire(%p) failed: %s", sem,
558              strerror(errcode));
559     }
560
561   } else {
562 #ifdef HAVE_SEM_WAIT
563     struct timespec ts_end;
564     double end = delay + xbt_os_time();
565
566     ts_end.tv_sec = (time_t) floor(end);
567     ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
568     XBT_DEBUG("sem_timedwait(%p,%p)", sem->ps, &ts_end);
569     errcode = sem_timedwait(sem->s, &ts_end);
570
571 #else                           /* Okay, reimplement this function then */
572     double start = xbt_os_time();
573     do {
574       errcode = sem_trywait(sem->ps);
575       if (errcode == EBUSY)
576         xbt_os_thread_yield();
577     } while (errcode == EBUSY && xbt_os_time() - start < delay);
578
579     if (errcode == EBUSY)
580       errcode = ETIMEDOUT;
581 #endif
582
583     switch (errcode) {
584     case 0:
585       return;
586
587     case ETIMEDOUT:
588       THROWF(timeout_error, delay,
589              "semaphore %p wasn't signaled before timeout (%f)", sem,
590              delay);
591
592     default:
593       THROWF(system_error, errcode, "sem_timedwait(%p,%f) failed: %s", sem,
594              delay, strerror(errcode));
595     }
596   }
597 }
598
599 void xbt_os_sem_release(xbt_os_sem_t sem)
600 {
601   if (sem_post(sem->ps) < 0)
602     THROWF(system_error, errno, "sem_post() failed: %s", strerror(errno));
603 }
604
605 void xbt_os_sem_destroy(xbt_os_sem_t sem)
606 {
607 #ifdef HAVE_SEM_INIT
608   if (sem_destroy(sem->ps) < 0)
609     THROWF(system_error, errno, "sem_destroy() failed: %s",
610            strerror(errno));
611 #else
612   if (sem_close(sem->ps) < 0)
613     THROWF(system_error, errno, "sem_close() failed: %s", strerror(errno));
614   xbt_free(sem->name);
615
616 #endif
617   xbt_free(sem);
618 }
619
620 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
621 {
622   if (sem_getvalue(&(sem->s), svalue) < 0)
623     THROWF(system_error, errno, "sem_getvalue() failed: %s",
624            strerror(errno));
625 }
626
627
628 /** @brief Returns the amount of cores on the current host */
629 int xbt_os_get_numcores(void) {
630 #ifdef WIN32
631     SYSTEM_INFO sysinfo;
632     GetSystemInfo(&sysinfo);
633     return sysinfo.dwNumberOfProcessors;
634 #elif defined(__APPLE__) && defined(__MACH__)
635     int nm[2];
636     size_t len = 4;
637     uint32_t count;
638
639     nm[0] = CTL_HW; nm[1] = HW_AVAILCPU;
640     sysctl(nm, 2, &count, &len, NULL, 0);
641
642     if(count < 1) {
643         nm[1] = HW_NCPU;
644         sysctl(nm, 2, &count, &len, NULL, 0);
645         if(count < 1) { count = 1; }
646     }
647     return count;
648 #else
649     return sysconf(_SC_NPROCESSORS_ONLN);
650 #endif
651 }
652
653
654 /***** reentrant mutexes *****/
655 typedef struct xbt_os_rmutex_ {
656   xbt_os_mutex_t mutex;
657   xbt_os_thread_t owner;
658   int count;
659 } s_xbt_os_rmutex_t;
660
661 void xbt_os_thread_set_extra_data(void *data)
662 {
663   xbt_os_thread_self()->extra_data = data;
664 }
665
666 void *xbt_os_thread_get_extra_data(void)
667 {
668   xbt_os_thread_t thread = xbt_os_thread_self();
669   if (thread)
670     return xbt_os_thread_self()->extra_data;
671   else
672     return NULL;
673 }
674
675 xbt_os_rmutex_t xbt_os_rmutex_init(void)
676 {
677   xbt_os_rmutex_t rmutex = xbt_new0(struct xbt_os_rmutex_, 1);
678   rmutex->mutex = xbt_os_mutex_init();
679   rmutex->owner = NULL;
680   rmutex->count = 0;
681   return rmutex;
682 }
683
684 void xbt_os_rmutex_acquire(xbt_os_rmutex_t rmutex)
685 {
686   xbt_os_thread_t self = xbt_os_thread_self();
687
688   if (self == NULL) {
689     /* the thread module is not initialized yet */
690     rmutex->owner = NULL;
691     return;
692   }
693
694   if (self != rmutex->owner) {
695     xbt_os_mutex_acquire(rmutex->mutex);
696     rmutex->owner = self;
697     rmutex->count = 1;
698   } else {
699     rmutex->count++;
700  }
701 }
702
703 void xbt_os_rmutex_release(xbt_os_rmutex_t rmutex)
704 {
705   if (rmutex->owner == NULL) {
706     /* the thread module was not initialized */
707     return;
708   }
709
710   xbt_assert(rmutex->owner == xbt_os_thread_self());
711
712   if (--rmutex->count == 0) {
713     rmutex->owner = NULL;
714     xbt_os_mutex_release(rmutex->mutex);
715   }
716 }
717
718 void xbt_os_rmutex_destroy(xbt_os_rmutex_t rmutex)
719 {
720   xbt_os_mutex_destroy(rmutex->mutex);
721   xbt_free(rmutex);
722 }