Logo AND Algorithmique Numérique Distribuée

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