Logo AND Algorithmique Numérique Distribuée

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