Logo AND Algorithmique Numérique Distribuée

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