Logo AND Algorithmique Numérique Distribuée

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