Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
e18ae2ef2adfac0470110427e924fd2e2e17e195
[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 CONTEXT_UCONTEXT, xbt_os_thread_stub is used instead   */
4
5 /* Copyright (c) 2007, 2008, 2009, 2010. 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 "gras_config.h"
12 #include "xbt/sysdep.h"
13 #include "xbt/ex.h"
14 #include "xbt/ex_interface.h"   /* We play crude games with exceptions */
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 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_sync_os, xbt,
21                                 "Synchronization mechanism (OS-level)");
22
23 /* ********************************* PTHREAD IMPLEMENTATION ************************************ */
24 #ifdef HAVE_PTHREAD_H
25
26 #include <semaphore.h>
27
28 #ifdef HAVE_MUTEX_TIMEDLOCK
29 /* redefine the function header since we fail to get this from system headers on amd (at least) */
30 int pthread_mutex_timedlock(pthread_mutex_t * mutex,
31                             const struct timespec *abs_timeout);
32 #endif
33
34
35 /* use named sempahore when sem_init() does not work */
36 #ifndef HAVE_SEM_INIT
37 static int next_sem_ID = 0;
38 static xbt_os_mutex_t next_sem_ID_lock;
39 #endif
40
41 typedef struct xbt_os_thread_ {
42   pthread_t t;
43   int detached;
44   char *name;
45   void *param;
46   pvoid_f_pvoid_t start_routine;
47   xbt_running_ctx_t *running_ctx;
48   void *extra_data;
49 } s_xbt_os_thread_t;
50 static xbt_os_thread_t main_thread = NULL;
51
52 /* thread-specific data containing the xbt_os_thread_t structure */
53 static pthread_key_t xbt_self_thread_key;
54 static int thread_mod_inited = 0;
55
56 /* frees the xbt_os_thread_t corresponding to the current thread */
57 static void xbt_os_thread_free_thread_data(xbt_os_thread_t thread)
58 {
59   if (thread == main_thread)    /* just killed main thread */
60     main_thread = NULL;
61
62   free(thread->running_ctx);
63   free(thread->name);
64   free(thread);
65 }
66
67 /* callback: context fetching */
68 static xbt_running_ctx_t *_os_thread_get_running_ctx(void)
69 {
70   return xbt_os_thread_self()->running_ctx;
71 }
72
73 /* callback: termination */
74 static void _os_thread_ex_terminate(xbt_ex_t * e)
75 {
76   xbt_ex_display(e);
77   xbt_abort();
78   /* FIXME: there should be a configuration variable to choose to kill everyone or only this one */
79 }
80
81 void xbt_os_thread_mod_preinit(void)
82 {
83   int errcode;
84
85   if (thread_mod_inited)
86     return;
87
88   if ((errcode = pthread_key_create(&xbt_self_thread_key, NULL)))
89     THROWF(system_error, errcode,
90            "pthread_key_create failed for xbt_self_thread_key");
91   
92   main_thread = xbt_new(s_xbt_os_thread_t, 1);
93   main_thread->name = (char *) "main";
94   main_thread->start_routine = NULL;
95   main_thread->param = NULL;
96   main_thread->running_ctx = xbt_new(xbt_running_ctx_t, 1);
97   XBT_RUNNING_CTX_INITIALIZE(main_thread->running_ctx);
98
99   if ((errcode = pthread_setspecific(xbt_self_thread_key, main_thread)))
100     THROWF(system_error, errcode,
101            "pthread_setspecific failed for xbt_self_thread_key");
102
103   
104   __xbt_running_ctx_fetch = _os_thread_get_running_ctx;
105   __xbt_ex_terminate = _os_thread_ex_terminate;
106
107   thread_mod_inited = 1;
108
109 #ifndef HAVE_SEM_INIT
110   next_sem_ID_lock = xbt_os_mutex_init();
111 #endif
112
113 }
114
115 void xbt_os_thread_mod_postexit(void)
116 {
117   /* FIXME: don't try to free our key on shutdown.
118      Valgrind detects no leak if we don't, and whine if we try to */
119   //   int errcode;
120
121   //   if ((errcode=pthread_key_delete(xbt_self_thread_key)))
122   //     THROWF(system_error,errcode,"pthread_key_delete failed for xbt_self_thread_key");
123   free(main_thread->running_ctx);
124   free(main_thread);
125   main_thread = NULL;
126   thread_mod_inited = 0;
127 #ifndef HAVE_SEM_INIT
128   xbt_os_mutex_destroy(next_sem_ID_lock);
129 #endif
130
131   /* Restore the default exception setup */
132   __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
133   __xbt_ex_terminate = &__xbt_ex_terminate_default;
134 }
135
136 int xbt_os_thread_atfork(void (*prepare)(void),
137                          void (*parent)(void), void (*child)(void))
138 {
139 #ifdef WIN32
140   THROW_UNIMPLEMENTED; //pthread_atfork is not implemented in pthread.h on windows
141 #else
142   return pthread_atfork(prepare, parent, child);
143 #endif
144 }
145
146 static void *wrapper_start_routine(void *s)
147 {
148   xbt_os_thread_t t = s;
149   int errcode;
150
151   if ((errcode = pthread_setspecific(xbt_self_thread_key, t)))
152     THROWF(system_error, errcode,
153            "pthread_setspecific failed for xbt_self_thread_key");
154
155   void *res = t->start_routine(t->param);
156   if (t->detached)
157     xbt_os_thread_free_thread_data(t);
158   return res;
159 }
160
161 xbt_os_thread_t xbt_os_thread_create(const char *name,
162                                      pvoid_f_pvoid_t start_routine,
163                                      void *param,
164                                      void *extra_data)
165 {
166   int errcode;
167
168   xbt_os_thread_t res_thread = xbt_new(s_xbt_os_thread_t, 1);
169   res_thread->detached = 0;
170   res_thread->name = xbt_strdup(name);
171   res_thread->start_routine = start_routine;
172   res_thread->param = param;
173   res_thread->running_ctx = xbt_new(xbt_running_ctx_t, 1);
174   XBT_RUNNING_CTX_INITIALIZE(res_thread->running_ctx);
175   res_thread->extra_data = extra_data;
176   
177   if ((errcode = pthread_create(&(res_thread->t), NULL,
178                                 wrapper_start_routine, res_thread)))
179     THROWF(system_error, errcode,
180            "pthread_create failed: %s", strerror(errcode));
181
182   return res_thread;
183 }
184
185 const char *xbt_os_thread_name(xbt_os_thread_t t)
186 {
187   return t->name;
188 }
189
190 const char *xbt_os_thread_self_name(void)
191 {
192   xbt_os_thread_t me = xbt_os_thread_self();
193   return me ? me->name : "main";
194 }
195
196 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
197 {
198
199   int errcode;
200
201   if ((errcode = pthread_join(thread->t, thread_return)))
202     THROWF(system_error, errcode, "pthread_join failed: %s",
203            strerror(errcode));
204   xbt_os_thread_free_thread_data(thread);
205 }
206
207 void xbt_os_thread_exit(int *retval)
208 {
209   pthread_exit(retval);
210 }
211
212 xbt_os_thread_t xbt_os_thread_self(void)
213 {
214   xbt_os_thread_t res;
215
216   if (!thread_mod_inited)
217     return NULL;
218
219   res = pthread_getspecific(xbt_self_thread_key);
220
221   return res;
222 }
223
224 void xbt_os_thread_key_create(xbt_os_thread_key_t* key) {
225
226   int errcode;
227   if ((errcode = pthread_key_create(key, NULL)))
228     THROWF(system_error, errcode, "pthread_key_create failed");
229 }
230
231 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value) {
232
233   int errcode;
234   if ((errcode = pthread_setspecific(key, value)))
235     THROWF(system_error, errcode, "pthread_setspecific failed");
236 }
237
238 void* xbt_os_thread_get_specific(xbt_os_thread_key_t key) {
239   return pthread_getspecific(key);
240 }
241
242 void xbt_os_thread_detach(xbt_os_thread_t thread)
243 {
244   thread->detached = 1;
245   pthread_detach(thread->t);
246 }
247
248 #include <sched.h>
249 void xbt_os_thread_yield(void)
250 {
251   sched_yield();
252 }
253
254 void xbt_os_thread_cancel(xbt_os_thread_t t)
255 {
256   pthread_cancel(t->t);
257 }
258
259 /****** mutex related functions ******/
260 typedef struct xbt_os_mutex_ {
261   /* KEEP IT IN SYNC WITH xbt_thread.c */
262   pthread_mutex_t m;
263 } s_xbt_os_mutex_t;
264
265 #include <time.h>
266 #include <math.h>
267
268 xbt_os_mutex_t xbt_os_mutex_init(void)
269 {
270   xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
271   int errcode;
272
273   if ((errcode = pthread_mutex_init(&(res->m), NULL)))
274     THROWF(system_error, errcode, "pthread_mutex_init() failed: %s",
275            strerror(errcode));
276
277   return res;
278 }
279
280 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
281 {
282   int errcode;
283
284   if ((errcode = pthread_mutex_lock(&(mutex->m))))
285     THROWF(system_error, errcode, "pthread_mutex_lock(%p) failed: %s",
286            mutex, strerror(errcode));
287 }
288
289
290 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
291 {
292   int errcode;
293
294   if (delay < 0) {
295     xbt_os_mutex_acquire(mutex);
296
297   } else if (delay == 0) {
298     errcode = pthread_mutex_trylock(&(mutex->m));
299
300     switch (errcode) {
301     case 0:
302       return;
303     case ETIMEDOUT:
304       THROWF(timeout_error, 0, "mutex %p not ready", mutex);
305     default:
306       THROWF(system_error, errcode,
307              "xbt_mutex_timedacquire(%p) failed: %s", mutex,
308              strerror(errcode));
309     }
310
311
312   } else {
313
314 #ifdef HAVE_MUTEX_TIMEDLOCK
315     struct timespec ts_end;
316     double end = delay + xbt_os_time();
317
318     ts_end.tv_sec = (time_t) floor(end);
319     ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
320     XBT_DEBUG("pthread_mutex_timedlock(%p,%p)", &(mutex->m), &ts_end);
321
322     errcode = pthread_mutex_timedlock(&(mutex->m), &ts_end);
323
324 #else                           /* Well, let's reimplement it since those lazy libc dudes didn't */
325     double start = xbt_os_time();
326     do {
327       errcode = pthread_mutex_trylock(&(mutex->m));
328       if (errcode == EBUSY)
329         xbt_os_thread_yield();
330     } while (errcode == EBUSY && xbt_os_time() - start < delay);
331
332     if (errcode == EBUSY)
333       errcode = ETIMEDOUT;
334
335 #endif                          /* HAVE_MUTEX_TIMEDLOCK */
336
337     switch (errcode) {
338     case 0:
339       return;
340
341     case ETIMEDOUT:
342       THROWF(timeout_error, delay,
343              "mutex %p wasn't signaled before timeout (%f)", mutex, delay);
344
345     default:
346       THROWF(system_error, errcode,
347              "pthread_mutex_timedlock(%p,%f) failed: %s", mutex, delay,
348              strerror(errcode));
349     }
350   }
351 }
352
353 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
354 {
355   int errcode;
356
357   if ((errcode = pthread_mutex_unlock(&(mutex->m))))
358     THROWF(system_error, errcode, "pthread_mutex_unlock(%p) failed: %s",
359            mutex, strerror(errcode));
360 }
361
362 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
363 {
364   int errcode;
365
366   if (!mutex)
367     return;
368
369   if ((errcode = pthread_mutex_destroy(&(mutex->m))))
370     THROWF(system_error, errcode, "pthread_mutex_destroy(%p) failed: %s",
371            mutex, strerror(errcode));
372   free(mutex);
373 }
374
375 /***** condition related functions *****/
376 typedef struct xbt_os_cond_ {
377   /* KEEP IT IN SYNC WITH xbt_thread.c */
378   pthread_cond_t c;
379 } s_xbt_os_cond_t;
380
381 xbt_os_cond_t xbt_os_cond_init(void)
382 {
383   xbt_os_cond_t res = xbt_new(s_xbt_os_cond_t, 1);
384   int errcode;
385   if ((errcode = pthread_cond_init(&(res->c), NULL)))
386     THROWF(system_error, errcode, "pthread_cond_init() failed: %s",
387            strerror(errcode));
388
389   return res;
390 }
391
392 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
393 {
394   int errcode;
395   if ((errcode = pthread_cond_wait(&(cond->c), &(mutex->m))))
396     THROWF(system_error, errcode, "pthread_cond_wait(%p,%p) failed: %s",
397            cond, mutex, strerror(errcode));
398 }
399
400
401 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
402                            double delay)
403 {
404   int errcode;
405   struct timespec ts_end;
406   double end = delay + xbt_os_time();
407
408   if (delay < 0) {
409     xbt_os_cond_wait(cond, mutex);
410   } else {
411     ts_end.tv_sec = (time_t) floor(end);
412     ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
413     XBT_DEBUG("pthread_cond_timedwait(%p,%p,%p)", &(cond->c), &(mutex->m),
414            &ts_end);
415     switch ((errcode =
416              pthread_cond_timedwait(&(cond->c), &(mutex->m), &ts_end))) {
417     case 0:
418       return;
419     case ETIMEDOUT:
420       THROWF(timeout_error, errcode,
421              "condition %p (mutex %p) wasn't signaled before timeout (%f)",
422              cond, mutex, delay);
423     default:
424       THROWF(system_error, errcode,
425              "pthread_cond_timedwait(%p,%p,%f) failed: %s", cond, mutex,
426              delay, strerror(errcode));
427     }
428   }
429 }
430
431 void xbt_os_cond_signal(xbt_os_cond_t cond)
432 {
433   int errcode;
434   if ((errcode = pthread_cond_signal(&(cond->c))))
435     THROWF(system_error, errcode, "pthread_cond_signal(%p) failed: %s",
436            cond, strerror(errcode));
437 }
438
439 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
440 {
441   int errcode;
442   if ((errcode = pthread_cond_broadcast(&(cond->c))))
443     THROWF(system_error, errcode, "pthread_cond_broadcast(%p) failed: %s",
444            cond, strerror(errcode));
445 }
446
447 void xbt_os_cond_destroy(xbt_os_cond_t cond)
448 {
449   int errcode;
450
451   if (!cond)
452     return;
453
454   if ((errcode = pthread_cond_destroy(&(cond->c))))
455     THROWF(system_error, errcode, "pthread_cond_destroy(%p) failed: %s",
456            cond, strerror(errcode));
457   free(cond);
458 }
459
460 void *xbt_os_thread_getparam(void)
461 {
462   xbt_os_thread_t t = xbt_os_thread_self();
463   return t ? t->param : NULL;
464 }
465
466 typedef struct xbt_os_sem_ {
467 #ifndef HAVE_SEM_INIT
468   char *name;
469 #endif
470   sem_t s;
471   sem_t *ps;
472 } s_xbt_os_sem_t;
473
474 #ifndef SEM_FAILED
475 #define SEM_FAILED (-1)
476 #endif
477
478 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
479 {
480   xbt_os_sem_t res = xbt_new(s_xbt_os_sem_t, 1);
481
482   /* On some systems (MAC OS X), only the stub of sem_init is to be found.
483    * Any attempt to use it leads to ENOSYS (function not implemented).
484    * If such a prehistoric system is detected, do the job with sem_open instead
485    */
486 #ifdef HAVE_SEM_INIT
487   if (sem_init(&(res->s), 0, value) != 0)
488     THROWF(system_error, errno, "sem_init() failed: %s", strerror(errno));
489   res->ps = &(res->s);
490
491 #else                           /* damn, no sem_init(). Reimplement it */
492
493   xbt_os_mutex_acquire(next_sem_ID_lock);
494   res->name = bprintf("/%d", ++next_sem_ID);
495   xbt_os_mutex_release(next_sem_ID_lock);
496
497   res->ps = sem_open(res->name, O_CREAT, 0644, value);
498   if ((res->ps == (sem_t *) SEM_FAILED) && (errno == ENAMETOOLONG)) {
499     /* Old darwins only allow 13 chars. Did you create *that* amount of semaphores? */
500     res->name[13] = '\0';
501     res->ps = sem_open(res->name, O_CREAT, 0644, value);
502   }
503   if ((res->ps == (sem_t *) SEM_FAILED))
504     THROWF(system_error, errno, "sem_open() failed: %s", strerror(errno));
505
506   /* Remove the name from the semaphore namespace: we never join on it */
507   if (sem_unlink(res->name) < 0)
508     THROWF(system_error, errno, "sem_unlink() failed: %s",
509            strerror(errno));
510
511 #endif
512
513   return res;
514 }
515
516 void xbt_os_sem_acquire(xbt_os_sem_t sem)
517 {
518   if (!sem)
519     THROWF(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
520   if (sem_wait(sem->ps) < 0)
521     THROWF(system_error, errno, "sem_wait() failed: %s", strerror(errno));
522 }
523
524 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double delay)
525 {
526   int errcode;
527
528   if (!sem)
529     THROWF(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
530
531   if (delay < 0) {
532     xbt_os_sem_acquire(sem);
533   } else if (delay == 0) {
534     errcode = sem_trywait(sem->ps);
535
536     switch (errcode) {
537     case 0:
538       return;
539     case ETIMEDOUT:
540       THROWF(timeout_error, 0, "semaphore %p not ready", sem);
541     default:
542       THROWF(system_error, errcode,
543              "xbt_os_sem_timedacquire(%p) failed: %s", sem,
544              strerror(errcode));
545     }
546
547   } else {
548 #ifdef HAVE_SEM_WAIT
549     struct timespec ts_end;
550     double end = delay + xbt_os_time();
551
552     ts_end.tv_sec = (time_t) floor(end);
553     ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
554     XBT_DEBUG("sem_timedwait(%p,%p)", sem->ps, &ts_end);
555     errcode = sem_timedwait(sem->s, &ts_end);
556
557 #else                           /* Okay, reimplement this function then */
558     double start = xbt_os_time();
559     do {
560       errcode = sem_trywait(sem->ps);
561       if (errcode == EBUSY)
562         xbt_os_thread_yield();
563     } while (errcode == EBUSY && xbt_os_time() - start < delay);
564
565     if (errcode == EBUSY)
566       errcode = ETIMEDOUT;
567 #endif
568
569     switch (errcode) {
570     case 0:
571       return;
572
573     case ETIMEDOUT:
574       THROWF(timeout_error, delay,
575              "semaphore %p wasn't signaled before timeout (%f)", sem,
576              delay);
577
578     default:
579       THROWF(system_error, errcode, "sem_timedwait(%p,%f) failed: %s", sem,
580              delay, strerror(errcode));
581     }
582   }
583 }
584
585 void xbt_os_sem_release(xbt_os_sem_t sem)
586 {
587   if (!sem)
588     THROWF(arg_error, EINVAL, "Cannot release of the NULL semaphore");
589
590   if (sem_post(sem->ps) < 0)
591     THROWF(system_error, errno, "sem_post() failed: %s", strerror(errno));
592 }
593
594 void xbt_os_sem_destroy(xbt_os_sem_t sem)
595 {
596   if (!sem)
597     THROWF(arg_error, EINVAL, "Cannot destroy the NULL sempahore");
598
599 #ifdef HAVE_SEM_INIT
600   if (sem_destroy(sem->ps) < 0)
601     THROWF(system_error, errno, "sem_destroy() failed: %s",
602            strerror(errno));
603 #else
604   if (sem_close(sem->ps) < 0)
605     THROWF(system_error, errno, "sem_close() failed: %s", strerror(errno));
606   xbt_free(sem->name);
607
608 #endif
609   xbt_free(sem);
610 }
611
612 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
613 {
614   if (!sem)
615     THROWF(arg_error, EINVAL,
616            "Cannot get the value of the NULL semaphore");
617
618   if (sem_getvalue(&(sem->s), svalue) < 0)
619     THROWF(system_error, errno, "sem_getvalue() failed: %s",
620            strerror(errno));
621 }
622
623 /* ********************************* WINDOWS IMPLEMENTATION ************************************ */
624
625 #elif defined(_XBT_WIN32)
626
627 #include <math.h>
628
629 typedef struct xbt_os_thread_ {
630   char *name;
631   HANDLE handle;                /* the win thread handle        */
632   unsigned long id;             /* the win thread id            */
633   pvoid_f_pvoid_t start_routine;
634   void *param;
635   void *extra_data;
636 } s_xbt_os_thread_t;
637
638 /* so we can specify the size of the stack of the threads */
639 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
640 #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
641 #endif
642
643 /* the default size of the stack of the threads (in bytes)*/
644 #define XBT_DEFAULT_THREAD_STACK_SIZE  4096
645
646 /* key to the TLS containing the xbt_os_thread_t structure */
647 static unsigned long xbt_self_thread_key;
648
649 void xbt_os_thread_mod_preinit(void)
650 {
651   xbt_self_thread_key = TlsAlloc();
652 }
653
654 void xbt_os_thread_mod_postexit(void)
655 {
656
657   if (!TlsFree(xbt_self_thread_key))
658     THROWF(system_error, (int) GetLastError(),
659            "TlsFree() failed to cleanup the thread submodule");
660 }
661
662 int xbt_os_thread_atfork(void (*prepare)(void),
663                          void (*parent)(void), void (*child)(void))
664 {
665   return 0;
666 }
667
668 static DWORD WINAPI wrapper_start_routine(void *s)
669 {
670   xbt_os_thread_t t = (xbt_os_thread_t) s;
671   DWORD *rv;
672
673   if (!TlsSetValue(xbt_self_thread_key, t))
674     THROWF(system_error, (int) GetLastError(),
675            "TlsSetValue of data describing the created thread failed");
676
677   rv = (DWORD *) ((t->start_routine) (t->param));
678
679   return rv ? *rv : 0;
680
681 }
682
683
684 xbt_os_thread_t xbt_os_thread_create(const char *name,
685                                      pvoid_f_pvoid_t start_routine,
686                                      void *param,
687                                      void *extra_data)
688 {
689
690   xbt_os_thread_t t = xbt_new(s_xbt_os_thread_t, 1);
691
692   t->name = xbt_strdup(name);
693   t->start_routine = start_routine;
694   t->param = param;
695   t->extra_data = extra_data;
696   t->handle = CreateThread(NULL, XBT_DEFAULT_THREAD_STACK_SIZE,
697                            (LPTHREAD_START_ROUTINE) wrapper_start_routine,
698                            t, STACK_SIZE_PARAM_IS_A_RESERVATION, &(t->id));
699
700   if (!t->handle) {
701     xbt_free(t);
702     THROWF(system_error, (int) GetLastError(), "CreateThread failed");
703   }
704
705   return t;
706 }
707
708 const char *xbt_os_thread_name(xbt_os_thread_t t)
709 {
710   return t->name;
711 }
712
713 const char *xbt_os_thread_self_name(void)
714 {
715   xbt_os_thread_t t = xbt_os_thread_self();
716   return t ? t->name : "main";
717 }
718
719 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
720 {
721
722   if (WAIT_OBJECT_0 != WaitForSingleObject(thread->handle, INFINITE))
723     THROWF(system_error, (int) GetLastError(),
724            "WaitForSingleObject failed");
725
726   if (thread_return) {
727
728     if (!GetExitCodeThread(thread->handle, (DWORD *) (*thread_return)))
729       THROWF(system_error, (int) GetLastError(),
730              "GetExitCodeThread failed");
731   }
732
733   CloseHandle(thread->handle);
734
735   free(thread->name);
736
737   free(thread);
738 }
739
740 void xbt_os_thread_exit(int *retval)
741 {
742   if (retval)
743     ExitThread(*retval);
744   else
745     ExitThread(0);
746 }
747
748 void xbt_os_thread_key_create(xbt_os_thread_key_t* key) {
749
750   *key = TlsAlloc();
751 }
752
753 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value) {
754
755   if (!TlsSetValue(key, value))
756     THROWF(system_error, (int) GetLastError(), "TlsSetValue() failed");
757 }
758
759 void* xbt_os_thread_get_specific(xbt_os_thread_key_t key) {
760   return TlsGetValue(key);
761 }
762
763 void xbt_os_thread_detach(xbt_os_thread_t thread)
764 {
765   THROW_UNIMPLEMENTED;
766 }
767
768
769 xbt_os_thread_t xbt_os_thread_self(void)
770 {
771   return TlsGetValue(xbt_self_thread_key);
772 }
773
774 void *xbt_os_thread_getparam(void)
775 {
776   xbt_os_thread_t t = xbt_os_thread_self();
777   return t->param;
778 }
779
780
781 void xbt_os_thread_yield(void)
782 {
783   Sleep(0);
784 }
785
786 void xbt_os_thread_cancel(xbt_os_thread_t t)
787 {
788   if (!TerminateThread(t->handle, 0))
789     THROWF(system_error, (int) GetLastError(), "TerminateThread failed");
790 }
791
792 /****** mutex related functions ******/
793 typedef struct xbt_os_mutex_ {
794   /* KEEP IT IN SYNC WITH xbt_thread.c */
795   CRITICAL_SECTION lock;
796 } s_xbt_os_mutex_t;
797
798 xbt_os_mutex_t xbt_os_mutex_init(void)
799 {
800   xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
801
802   /* initialize the critical section object */
803   InitializeCriticalSection(&(res->lock));
804
805   return res;
806 }
807
808 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
809 {
810   EnterCriticalSection(&mutex->lock);
811 }
812
813 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
814 {
815   THROW_UNIMPLEMENTED;
816 }
817
818 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
819 {
820
821   LeaveCriticalSection(&mutex->lock);
822
823 }
824
825 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
826 {
827
828   if (!mutex)
829     return;
830
831   DeleteCriticalSection(&mutex->lock);
832   free(mutex);
833 }
834
835 /***** condition related functions *****/
836 enum {                          /* KEEP IT IN SYNC WITH xbt_thread.c */
837   SIGNAL = 0,
838   BROADCAST = 1,
839   MAX_EVENTS = 2
840 };
841
842 typedef struct xbt_os_cond_ {
843   /* KEEP IT IN SYNC WITH xbt_thread.c */
844   HANDLE events[MAX_EVENTS];
845
846   unsigned int waiters_count;   /* the number of waiters                        */
847   CRITICAL_SECTION waiters_count_lock;  /* protect access to waiters_count  */
848 } s_xbt_os_cond_t;
849
850 xbt_os_cond_t xbt_os_cond_init(void)
851 {
852
853   xbt_os_cond_t res = xbt_new0(s_xbt_os_cond_t, 1);
854
855   memset(&res->waiters_count_lock, 0, sizeof(CRITICAL_SECTION));
856
857   /* initialize the critical section object */
858   InitializeCriticalSection(&res->waiters_count_lock);
859
860   res->waiters_count = 0;
861
862   /* Create an auto-reset event */
863   res->events[SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL);
864
865   if (!res->events[SIGNAL]) {
866     DeleteCriticalSection(&res->waiters_count_lock);
867     free(res);
868     THROWF(system_error, 0, "CreateEvent failed for the signals");
869   }
870
871   /* Create a manual-reset event. */
872   res->events[BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
873
874   if (!res->events[BROADCAST]) {
875
876     DeleteCriticalSection(&res->waiters_count_lock);
877     CloseHandle(res->events[SIGNAL]);
878     free(res);
879     THROWF(system_error, 0, "CreateEvent failed for the broadcasts");
880   }
881
882   return res;
883 }
884
885 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
886 {
887
888   unsigned long wait_result;
889   int is_last_waiter;
890
891   /* lock the threads counter and increment it */
892   EnterCriticalSection(&cond->waiters_count_lock);
893   cond->waiters_count++;
894   LeaveCriticalSection(&cond->waiters_count_lock);
895
896   /* unlock the mutex associate with the condition */
897   LeaveCriticalSection(&mutex->lock);
898
899   /* wait for a signal (broadcast or no) */
900   wait_result = WaitForMultipleObjects(2, cond->events, FALSE, INFINITE);
901
902   if (wait_result == WAIT_FAILED)
903     THROWF(system_error, 0,
904            "WaitForMultipleObjects failed, so we cannot wait on the condition");
905
906   /* we have a signal lock the condition */
907   EnterCriticalSection(&cond->waiters_count_lock);
908   cond->waiters_count--;
909
910   /* it's the last waiter or it's a broadcast ? */
911   is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
912                     && (cond->waiters_count == 0));
913
914   LeaveCriticalSection(&cond->waiters_count_lock);
915
916   /* yes it's the last waiter or it's a broadcast
917    * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
918    * by the system.
919    */
920   if (is_last_waiter)
921     if (!ResetEvent(cond->events[BROADCAST]))
922       THROWF(system_error, 0, "ResetEvent failed");
923
924   /* relock the mutex associated with the condition in accordance with the posix thread specification */
925   EnterCriticalSection(&mutex->lock);
926 }
927
928 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
929                            double delay)
930 {
931
932   unsigned long wait_result = WAIT_TIMEOUT;
933   int is_last_waiter;
934   unsigned long end = (unsigned long) (delay * 1000);
935
936
937   if (delay < 0) {
938     xbt_os_cond_wait(cond, mutex);
939   } else {
940     XBT_DEBUG("xbt_cond_timedwait(%p,%p,%lu)", &(cond->events),
941            &(mutex->lock), end);
942
943     /* lock the threads counter and increment it */
944     EnterCriticalSection(&cond->waiters_count_lock);
945     cond->waiters_count++;
946     LeaveCriticalSection(&cond->waiters_count_lock);
947
948     /* unlock the mutex associate with the condition */
949     LeaveCriticalSection(&mutex->lock);
950     /* wait for a signal (broadcast or no) */
951
952     wait_result = WaitForMultipleObjects(2, cond->events, FALSE, end);
953
954     switch (wait_result) {
955     case WAIT_TIMEOUT:
956       THROWF(timeout_error, GetLastError(),
957              "condition %p (mutex %p) wasn't signaled before timeout (%f)",
958              cond, mutex, delay);
959     case WAIT_FAILED:
960       THROWF(system_error, GetLastError(),
961              "WaitForMultipleObjects failed, so we cannot wait on the condition");
962     }
963
964     /* we have a signal lock the condition */
965     EnterCriticalSection(&cond->waiters_count_lock);
966     cond->waiters_count--;
967
968     /* it's the last waiter or it's a broadcast ? */
969     is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
970                       && (cond->waiters_count == 0));
971
972     LeaveCriticalSection(&cond->waiters_count_lock);
973
974     /* yes it's the last waiter or it's a broadcast
975      * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
976      * by the system.
977      */
978     if (is_last_waiter)
979       if (!ResetEvent(cond->events[BROADCAST]))
980         THROWF(system_error, 0, "ResetEvent failed");
981
982     /* relock the mutex associated with the condition in accordance with the posix thread specification */
983     EnterCriticalSection(&mutex->lock);
984   }
985   /*THROW_UNIMPLEMENTED; */
986 }
987
988 void xbt_os_cond_signal(xbt_os_cond_t cond)
989 {
990   int have_waiters;
991
992   EnterCriticalSection(&cond->waiters_count_lock);
993   have_waiters = cond->waiters_count > 0;
994   LeaveCriticalSection(&cond->waiters_count_lock);
995
996   if (have_waiters)
997     if (!SetEvent(cond->events[SIGNAL]))
998       THROWF(system_error, 0, "SetEvent failed");
999
1000   xbt_os_thread_yield();
1001 }
1002
1003 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
1004 {
1005   int have_waiters;
1006
1007   EnterCriticalSection(&cond->waiters_count_lock);
1008   have_waiters = cond->waiters_count > 0;
1009   LeaveCriticalSection(&cond->waiters_count_lock);
1010
1011   if (have_waiters)
1012     SetEvent(cond->events[BROADCAST]);
1013 }
1014
1015 void xbt_os_cond_destroy(xbt_os_cond_t cond)
1016 {
1017   int error = 0;
1018
1019   if (!cond)
1020     return;
1021
1022   if (!CloseHandle(cond->events[SIGNAL]))
1023     error = 1;
1024
1025   if (!CloseHandle(cond->events[BROADCAST]))
1026     error = 1;
1027
1028   DeleteCriticalSection(&cond->waiters_count_lock);
1029
1030   xbt_free(cond);
1031
1032   if (error)
1033     THROWF(system_error, 0, "Error while destroying the condition");
1034 }
1035
1036 typedef struct xbt_os_sem_ {
1037   HANDLE h;
1038   unsigned int value;
1039   CRITICAL_SECTION value_lock;  /* protect access to value of the semaphore  */
1040 } s_xbt_os_sem_t;
1041
1042 #ifndef INT_MAX
1043 # define INT_MAX 32767          /* let's be safe by underestimating this value: this is for 16bits only */
1044 #endif
1045
1046 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
1047 {
1048   xbt_os_sem_t res;
1049
1050   if (value > INT_MAX)
1051     THROWF(arg_error, value,
1052            "Semaphore initial value too big: %ud cannot be stored as a signed int",
1053            value);
1054
1055   res = (xbt_os_sem_t) xbt_new0(s_xbt_os_sem_t, 1);
1056
1057   if (!(res->h = CreateSemaphore(NULL, value, (long) INT_MAX, NULL))) {
1058     THROWF(system_error, GetLastError(), "CreateSemaphore() failed: %s",
1059            strerror(GetLastError()));
1060     return NULL;
1061   }
1062
1063   res->value = value;
1064
1065   InitializeCriticalSection(&(res->value_lock));
1066
1067   return res;
1068 }
1069
1070 void xbt_os_sem_acquire(xbt_os_sem_t sem)
1071 {
1072   if (!sem)
1073     THROWF(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1074
1075   /* wait failure */
1076   if (WAIT_OBJECT_0 != WaitForSingleObject(sem->h, INFINITE))
1077     THROWF(system_error, GetLastError(),
1078            "WaitForSingleObject() failed: %s", strerror(GetLastError()));
1079   EnterCriticalSection(&(sem->value_lock));
1080   sem->value--;
1081   LeaveCriticalSection(&(sem->value_lock));
1082 }
1083
1084 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double timeout)
1085 {
1086   long seconds;
1087   long milliseconds;
1088   double end = timeout + xbt_os_time();
1089
1090   if (!sem)
1091     THROWF(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1092
1093   if (timeout < 0) {
1094     xbt_os_sem_acquire(sem);
1095   } else {                      /* timeout can be zero <-> try acquire ) */
1096
1097
1098     seconds = (long) floor(end);
1099     milliseconds = (long) ((end - seconds) * 1000);
1100     milliseconds += (seconds * 1000);
1101
1102     switch (WaitForSingleObject(sem->h, milliseconds)) {
1103     case WAIT_OBJECT_0:
1104       EnterCriticalSection(&(sem->value_lock));
1105       sem->value--;
1106       LeaveCriticalSection(&(sem->value_lock));
1107       return;
1108
1109     case WAIT_TIMEOUT:
1110       THROWF(timeout_error, GetLastError(),
1111              "semaphore %p wasn't signaled before timeout (%f)", sem,
1112              timeout);
1113       return;
1114
1115     default:
1116       THROWF(system_error, GetLastError(),
1117              "WaitForSingleObject(%p,%f) failed: %s", sem, timeout,
1118              strerror(GetLastError()));
1119     }
1120   }
1121 }
1122
1123 void xbt_os_sem_release(xbt_os_sem_t sem)
1124 {
1125   if (!sem)
1126     THROWF(arg_error, EINVAL, "Cannot release the NULL semaphore");
1127
1128   if (!ReleaseSemaphore(sem->h, 1, NULL))
1129     THROWF(system_error, GetLastError(), "ReleaseSemaphore() failed: %s",
1130            strerror(GetLastError()));
1131   EnterCriticalSection(&(sem->value_lock));
1132   sem->value++;
1133   LeaveCriticalSection(&(sem->value_lock));
1134 }
1135
1136 void xbt_os_sem_destroy(xbt_os_sem_t sem)
1137 {
1138   if (!sem)
1139     THROWF(arg_error, EINVAL, "Cannot destroy the NULL semaphore");
1140
1141   if (!CloseHandle(sem->h))
1142     THROWF(system_error, GetLastError(), "CloseHandle() failed: %s",
1143            strerror(GetLastError()));
1144
1145   DeleteCriticalSection(&(sem->value_lock));
1146
1147   xbt_free(sem);
1148
1149 }
1150
1151 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
1152 {
1153   if (!sem)
1154     THROWF(arg_error, EINVAL,
1155            "Cannot get the value of the NULL semaphore");
1156
1157   EnterCriticalSection(&(sem->value_lock));
1158   *svalue = sem->value;
1159   LeaveCriticalSection(&(sem->value_lock));
1160 }
1161
1162
1163 #endif
1164
1165
1166 /** @brief Returns the amount of cores on the current host */
1167 int xbt_os_get_numcores(void) {
1168 #ifdef WIN32
1169     SYSTEM_INFO sysinfo;
1170     GetSystemInfo(&sysinfo);
1171     return sysinfo.dwNumberOfProcessors;
1172 #elif MACOS
1173     int nm[2];
1174     size_t len = 4;
1175     uint32_t count;
1176
1177     nm[0] = CTL_HW; nm[1] = HW_AVAILCPU;
1178     sysctl(nm, 2, &count, &len, NULL, 0);
1179
1180     if(count < 1) {
1181         nm[1] = HW_NCPU;
1182         sysctl(nm, 2, &count, &len, NULL, 0);
1183         if(count < 1) { count = 1; }
1184     }
1185     return count;
1186 #else
1187     return sysconf(_SC_NPROCESSORS_ONLN);
1188 #endif
1189 }
1190
1191
1192 /***** reentrant mutexes *****/
1193 typedef struct xbt_os_rmutex_ {
1194   xbt_os_mutex_t mutex;
1195   xbt_os_thread_t owner;
1196   int count;
1197 } s_xbt_os_rmutex_t;
1198
1199 void xbt_os_thread_set_extra_data(void *data)
1200 {
1201   xbt_os_thread_self()->extra_data = data;
1202 }
1203
1204 void *xbt_os_thread_get_extra_data(void)
1205 {
1206   return xbt_os_thread_self()->extra_data;
1207 }
1208
1209 xbt_os_rmutex_t xbt_os_rmutex_init(void)
1210 {
1211   xbt_os_rmutex_t rmutex = xbt_new0(struct xbt_os_rmutex_, 1);
1212   rmutex->mutex = xbt_os_mutex_init();
1213   rmutex->owner = NULL;
1214   rmutex->count = 0;
1215   return rmutex;
1216 }
1217
1218 void xbt_os_rmutex_acquire(xbt_os_rmutex_t rmutex)
1219 {
1220   xbt_os_thread_t self = xbt_os_thread_self();
1221
1222   if (self == NULL) {
1223     /* the thread module is not initialized yet */
1224     rmutex->owner = NULL;
1225     return;
1226   }
1227
1228   if (self != rmutex->owner) {
1229     xbt_os_mutex_acquire(rmutex->mutex);
1230     rmutex->owner = self;
1231     rmutex->count = 1;
1232   } else {
1233     rmutex->count++;
1234  }
1235 }
1236
1237 void xbt_os_rmutex_release(xbt_os_rmutex_t rmutex)
1238 {
1239   if (rmutex->owner == NULL) {
1240     /* the thread module was not initialized */
1241     return;
1242   }
1243
1244   xbt_assert(rmutex->owner == xbt_os_thread_self());
1245
1246   if (--rmutex->count == 0) {
1247     rmutex->owner = NULL;
1248     xbt_os_mutex_release(rmutex->mutex);
1249   }
1250 }
1251
1252 void xbt_os_rmutex_destroy(xbt_os_rmutex_t rmutex)
1253 {
1254   xbt_os_mutex_destroy(rmutex->mutex);
1255   xbt_free(rmutex);
1256 }