Logo AND Algorithmique Numérique Distribuée

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