Logo AND Algorithmique Numérique Distribuée

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