Logo AND Algorithmique Numérique Distribuée

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