Logo AND Algorithmique Numérique Distribuée

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