Logo AND Algorithmique Numérique Distribuée

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