Logo AND Algorithmique Numérique Distribuée

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