Logo AND Algorithmique Numérique Distribuée

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