Logo AND Algorithmique Numérique Distribuée

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