Logo AND Algorithmique Numérique Distribuée

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