Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Remove weird parenthesis...
[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)<0)
556       THROW1(system_error, errno, "sem_destroy() failed: %s",
557              strerror(errno));
558 #else
559   if (sem_close(sem->ps) < 0)
560     THROW1(system_error, errno, "sem_close() failed: %s", strerror(errno));
561   xbt_free(sem->name);
562
563 #endif
564   xbt_free(sem);
565 }
566
567 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
568 {
569   if (!sem)
570     THROW0(arg_error, EINVAL, "Cannot get the value of the NULL semaphore");
571
572   if (sem_getvalue(&(sem->s), svalue) < 0)
573     THROW1(system_error, errno, "sem_getvalue() failed: %s", strerror(errno));
574 }
575
576 /* ********************************* WINDOWS IMPLEMENTATION ************************************ */
577
578 #elif defined(_XBT_WIN32)
579
580 #include <math.h>
581
582 typedef struct xbt_os_thread_ {
583   char *name;
584   HANDLE handle;                /* the win thread handle        */
585   unsigned long id;             /* the win thread id            */
586   pvoid_f_pvoid_t start_routine;
587   void *param;
588 } s_xbt_os_thread_t;
589
590 /* so we can specify the size of the stack of the threads */
591 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
592 #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
593 #endif
594
595 /* the default size of the stack of the threads (in bytes)*/
596 #define XBT_DEFAULT_THREAD_STACK_SIZE   4096
597
598 /* key to the TLS containing the xbt_os_thread_t structure */
599 static unsigned long xbt_self_thread_key;
600
601 void xbt_os_thread_mod_preinit(void)
602 {
603   xbt_self_thread_key = TlsAlloc();
604 }
605
606 void xbt_os_thread_mod_postexit(void)
607 {
608
609   if (!TlsFree(xbt_self_thread_key))
610     THROW0(system_error, (int) GetLastError(),
611            "TlsFree() failed to cleanup the thread submodule");
612 }
613
614 static DWORD WINAPI wrapper_start_routine(void *s)
615 {
616   xbt_os_thread_t t = (xbt_os_thread_t) s;
617   DWORD *rv;
618
619   if (!TlsSetValue(xbt_self_thread_key, t))
620     THROW0(system_error, (int) GetLastError(),
621            "TlsSetValue of data describing the created thread failed");
622
623   rv = (DWORD *) ((t->start_routine) (t->param));
624
625   return rv ? *rv : 0;
626
627 }
628
629
630 xbt_os_thread_t xbt_os_thread_create(const char *name,
631                                      pvoid_f_pvoid_t start_routine,
632                                      void *param)
633 {
634
635   xbt_os_thread_t t = xbt_new(s_xbt_os_thread_t, 1);
636
637   t->name = xbt_strdup(name);
638   t->start_routine = start_routine;
639   t->param = param;
640
641   t->handle = CreateThread(NULL, XBT_DEFAULT_THREAD_STACK_SIZE,
642                            (LPTHREAD_START_ROUTINE) wrapper_start_routine,
643                            t, STACK_SIZE_PARAM_IS_A_RESERVATION, &(t->id));
644
645   if (!t->handle) {
646     xbt_free(t);
647     THROW0(system_error, (int) GetLastError(), "CreateThread failed");
648   }
649
650   return t;
651 }
652
653 const char *xbt_os_thread_name(xbt_os_thread_t t)
654 {
655   return t->name;
656 }
657
658 const char *xbt_os_thread_self_name(void)
659 {
660   xbt_os_thread_t t = xbt_os_thread_self();
661   return t ? t->name : "main";
662 }
663
664 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
665 {
666
667   if (WAIT_OBJECT_0 != WaitForSingleObject(thread->handle, INFINITE))
668     THROW0(system_error, (int) GetLastError(), "WaitForSingleObject failed");
669
670   if (thread_return) {
671
672     if (!GetExitCodeThread(thread->handle, (DWORD *) (*thread_return)))
673       THROW0(system_error, (int) GetLastError(), "GetExitCodeThread failed");
674   }
675
676   CloseHandle(thread->handle);
677
678   if (thread->name)
679     free(thread->name);
680
681   free(thread);
682 }
683
684 void xbt_os_thread_exit(int *retval)
685 {
686   if (retval)
687     ExitThread(*retval);
688   else
689     ExitThread(0);
690 }
691
692 xbt_os_thread_t xbt_os_thread_self(void)
693 {
694   return TlsGetValue(xbt_self_thread_key);
695 }
696
697 void *xbt_os_thread_getparam(void)
698 {
699   xbt_os_thread_t t = xbt_os_thread_self();
700   return t->param;
701 }
702
703
704 void xbt_os_thread_yield(void)
705 {
706   Sleep(0);
707 }
708
709 void xbt_os_thread_cancel(xbt_os_thread_t t)
710 {
711   if (!TerminateThread(t->handle, 0))
712     THROW0(system_error, (int) GetLastError(), "TerminateThread failed");
713 }
714
715 /****** mutex related functions ******/
716 typedef struct xbt_os_mutex_ {
717   /* KEEP IT IN SYNC WITH xbt_thread.c */
718   CRITICAL_SECTION lock;
719 } s_xbt_os_mutex_t;
720
721 xbt_os_mutex_t xbt_os_mutex_init(void)
722 {
723   xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
724
725   /* initialize the critical section object */
726   InitializeCriticalSection(&(res->lock));
727
728   return res;
729 }
730
731 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
732 {
733   EnterCriticalSection(&mutex->lock);
734 }
735
736 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
737 {
738   THROW_UNIMPLEMENTED;
739 }
740
741 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
742 {
743
744   LeaveCriticalSection(&mutex->lock);
745
746 }
747
748 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
749 {
750
751   if (!mutex)
752     return;
753
754   DeleteCriticalSection(&mutex->lock);
755   free(mutex);
756 }
757
758 /***** condition related functions *****/
759 enum {                          /* KEEP IT IN SYNC WITH xbt_thread.c */
760   SIGNAL = 0,
761   BROADCAST = 1,
762   MAX_EVENTS = 2
763 };
764
765 typedef struct xbt_os_cond_ {
766   /* KEEP IT IN SYNC WITH xbt_thread.c */
767   HANDLE events[MAX_EVENTS];
768
769   unsigned int waiters_count;   /* the number of waiters                        */
770   CRITICAL_SECTION waiters_count_lock;  /* protect access to waiters_count  */
771 } s_xbt_os_cond_t;
772
773 xbt_os_cond_t xbt_os_cond_init(void)
774 {
775
776   xbt_os_cond_t res = xbt_new0(s_xbt_os_cond_t, 1);
777
778   memset(&res->waiters_count_lock, 0, sizeof(CRITICAL_SECTION));
779
780   /* initialize the critical section object */
781   InitializeCriticalSection(&res->waiters_count_lock);
782
783   res->waiters_count = 0;
784
785   /* Create an auto-reset event */
786   res->events[SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL);
787
788   if (!res->events[SIGNAL]) {
789     DeleteCriticalSection(&res->waiters_count_lock);
790     free(res);
791     THROW0(system_error, 0, "CreateEvent failed for the signals");
792   }
793
794   /* Create a manual-reset event. */
795   res->events[BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
796
797   if (!res->events[BROADCAST]) {
798
799     DeleteCriticalSection(&res->waiters_count_lock);
800     CloseHandle(res->events[SIGNAL]);
801     free(res);
802     THROW0(system_error, 0, "CreateEvent failed for the broadcasts");
803   }
804
805   return res;
806 }
807
808 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
809 {
810
811   unsigned long wait_result;
812   int is_last_waiter;
813
814   /* lock the threads counter and increment it */
815   EnterCriticalSection(&cond->waiters_count_lock);
816   cond->waiters_count++;
817   LeaveCriticalSection(&cond->waiters_count_lock);
818
819   /* unlock the mutex associate with the condition */
820   LeaveCriticalSection(&mutex->lock);
821
822   /* wait for a signal (broadcast or no) */
823   wait_result = WaitForMultipleObjects(2, cond->events, FALSE, INFINITE);
824
825   if (wait_result == WAIT_FAILED)
826     THROW0(system_error, 0,
827            "WaitForMultipleObjects failed, so we cannot wait on the condition");
828
829   /* we have a signal lock the condition */
830   EnterCriticalSection(&cond->waiters_count_lock);
831   cond->waiters_count--;
832
833   /* it's the last waiter or it's a broadcast ? */
834   is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
835                     && (cond->waiters_count == 0));
836
837   LeaveCriticalSection(&cond->waiters_count_lock);
838
839   /* yes it's the last waiter or it's a broadcast
840    * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
841    * by the system.
842    */
843   if (is_last_waiter)
844     if (!ResetEvent(cond->events[BROADCAST]))
845       THROW0(system_error, 0, "ResetEvent failed");
846
847   /* relock the mutex associated with the condition in accordance with the posix thread specification */
848   EnterCriticalSection(&mutex->lock);
849 }
850
851 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
852                            double delay)
853 {
854
855   unsigned long wait_result = WAIT_TIMEOUT;
856   int is_last_waiter;
857   unsigned long end = (unsigned long) (delay * 1000);
858
859
860   if (delay < 0) {
861     xbt_os_cond_wait(cond, mutex);
862   } else {
863     DEBUG3("xbt_cond_timedwait(%p,%p,%lu)", &(cond->events), &(mutex->lock),
864            end);
865
866     /* lock the threads counter and increment it */
867     EnterCriticalSection(&cond->waiters_count_lock);
868     cond->waiters_count++;
869     LeaveCriticalSection(&cond->waiters_count_lock);
870
871     /* unlock the mutex associate with the condition */
872     LeaveCriticalSection(&mutex->lock);
873     /* wait for a signal (broadcast or no) */
874
875     wait_result = WaitForMultipleObjects(2, cond->events, FALSE, end);
876
877     switch (wait_result) {
878     case WAIT_TIMEOUT:
879       THROW3(timeout_error, GetLastError(),
880              "condition %p (mutex %p) wasn't signaled before timeout (%f)",
881              cond, mutex, delay);
882     case WAIT_FAILED:
883       THROW0(system_error, GetLastError(),
884              "WaitForMultipleObjects failed, so we cannot wait on the condition");
885     }
886
887     /* we have a signal lock the condition */
888     EnterCriticalSection(&cond->waiters_count_lock);
889     cond->waiters_count--;
890
891     /* it's the last waiter or it's a broadcast ? */
892     is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
893                       && (cond->waiters_count == 0));
894
895     LeaveCriticalSection(&cond->waiters_count_lock);
896
897     /* yes it's the last waiter or it's a broadcast
898      * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
899      * by the system.
900      */
901     if (is_last_waiter)
902       if (!ResetEvent(cond->events[BROADCAST]))
903         THROW0(system_error, 0, "ResetEvent failed");
904
905     /* relock the mutex associated with the condition in accordance with the posix thread specification */
906     EnterCriticalSection(&mutex->lock);
907   }
908   /*THROW_UNIMPLEMENTED; */
909 }
910
911 void xbt_os_cond_signal(xbt_os_cond_t cond)
912 {
913   int have_waiters;
914
915   EnterCriticalSection(&cond->waiters_count_lock);
916   have_waiters = cond->waiters_count > 0;
917   LeaveCriticalSection(&cond->waiters_count_lock);
918
919   if (have_waiters)
920     if (!SetEvent(cond->events[SIGNAL]))
921       THROW0(system_error, 0, "SetEvent failed");
922
923   xbt_os_thread_yield();
924 }
925
926 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
927 {
928   int have_waiters;
929
930   EnterCriticalSection(&cond->waiters_count_lock);
931   have_waiters = cond->waiters_count > 0;
932   LeaveCriticalSection(&cond->waiters_count_lock);
933
934   if (have_waiters)
935     SetEvent(cond->events[BROADCAST]);
936 }
937
938 void xbt_os_cond_destroy(xbt_os_cond_t cond)
939 {
940   int error = 0;
941
942   if (!cond)
943     return;
944
945   if (!CloseHandle(cond->events[SIGNAL]))
946     error = 1;
947
948   if (!CloseHandle(cond->events[BROADCAST]))
949     error = 1;
950
951   DeleteCriticalSection(&cond->waiters_count_lock);
952
953   xbt_free(cond);
954
955   if (error)
956     THROW0(system_error, 0, "Error while destroying the condition");
957 }
958
959 typedef struct xbt_os_sem_ {
960   HANDLE h;
961   unsigned int value;
962   CRITICAL_SECTION value_lock;  /* protect access to value of the semaphore  */
963 } s_xbt_os_sem_t;
964
965 #ifndef INT_MAX
966 # define INT_MAX 32767          /* let's be safe by underestimating this value: this is for 16bits only */
967 #endif
968
969 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
970 {
971   xbt_os_sem_t res;
972
973   if (value > INT_MAX)
974     THROW1(arg_error, value,
975            "Semaphore initial value too big: %ud cannot be stored as a signed int",
976            value);
977
978   res = (xbt_os_sem_t) xbt_new0(s_xbt_os_sem_t, 1);
979
980   if (!(res->h = CreateSemaphore(NULL, value, (long) INT_MAX, NULL))) {
981     THROW1(system_error, GetLastError(), "CreateSemaphore() failed: %s",
982            strerror(GetLastError()));
983     return NULL;
984   }
985
986   res->value = value;
987
988   InitializeCriticalSection(&(res->value_lock));
989
990   return res;
991 }
992
993 void xbt_os_sem_acquire(xbt_os_sem_t sem)
994 {
995   if (!sem)
996     THROW0(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
997
998   /* wait failure */
999   if (WAIT_OBJECT_0 != WaitForSingleObject(sem->h, INFINITE))
1000     THROW1(system_error, GetLastError(), "WaitForSingleObject() failed: %s",
1001            strerror(GetLastError()));
1002   EnterCriticalSection(&(sem->value_lock));
1003   sem->value--;
1004   LeaveCriticalSection(&(sem->value_lock));
1005 }
1006
1007 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double timeout)
1008 {
1009   long seconds;
1010   long milliseconds;
1011   double end = timeout + xbt_os_time();
1012
1013   if (!sem)
1014     THROW0(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1015
1016   if (timeout < 0) {
1017     xbt_os_sem_acquire(sem);
1018   } else {                      /* timeout can be zero <-> try acquire ) */
1019
1020
1021     seconds = (long) floor(end);
1022     milliseconds = (long) ((end - seconds) * 1000);
1023     milliseconds += (seconds * 1000);
1024
1025     switch (WaitForSingleObject(sem->h, milliseconds)) {
1026     case WAIT_OBJECT_0:
1027       EnterCriticalSection(&(sem->value_lock));
1028       sem->value--;
1029       LeaveCriticalSection(&(sem->value_lock));
1030       return;
1031
1032     case WAIT_TIMEOUT:
1033       THROW2(timeout_error, GetLastError(),
1034              "semaphore %p wasn't signaled before timeout (%f)", sem,
1035              timeout);
1036       return;
1037
1038     default:
1039       THROW3(system_error, GetLastError(),
1040              "WaitForSingleObject(%p,%f) failed: %s", sem, timeout,
1041              strerror(GetLastError()));
1042     }
1043   }
1044 }
1045
1046 void xbt_os_sem_release(xbt_os_sem_t sem)
1047 {
1048   if (!sem)
1049     THROW0(arg_error, EINVAL, "Cannot release the NULL semaphore");
1050
1051   if (!ReleaseSemaphore(sem->h, 1, NULL))
1052     THROW1(system_error, GetLastError(), "ReleaseSemaphore() failed: %s",
1053            strerror(GetLastError()));
1054   EnterCriticalSection(&(sem->value_lock));
1055   sem->value++;
1056   LeaveCriticalSection(&(sem->value_lock));
1057 }
1058
1059 void xbt_os_sem_destroy(xbt_os_sem_t sem)
1060 {
1061   if (!sem)
1062     THROW0(arg_error, EINVAL, "Cannot destroy the NULL semaphore");
1063
1064   if (!CloseHandle(sem->h))
1065     THROW1(system_error, GetLastError(), "CloseHandle() failed: %s",
1066            strerror(GetLastError()));
1067
1068   DeleteCriticalSection(&(sem->value_lock));
1069
1070   xbt_free(sem);
1071
1072 }
1073
1074 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
1075 {
1076   if (!sem)
1077     THROW0(arg_error, EINVAL, "Cannot get the value of the NULL semaphore");
1078
1079   EnterCriticalSection(&(sem->value_lock));
1080   *svalue = sem->value;
1081   LeaveCriticalSection(&(sem->value_lock));
1082 }
1083
1084 #endif