Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
SMPI: Change the reference speed to a command line option
[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
123 static void *wrapper_start_routine(void *s)
124 {
125   xbt_os_thread_t t = s;
126   int errcode;
127
128   if ((errcode = pthread_setspecific(xbt_self_thread_key, t)))
129     THROW0(system_error, errcode,
130            "pthread_setspecific failed for xbt_self_thread_key");
131
132   return (*(t->start_routine)) (t->param);
133 }
134
135 xbt_os_thread_t xbt_os_thread_create(const char *name,
136                                      pvoid_f_pvoid_t start_routine,
137                                      void *param)
138 {
139   int errcode;
140
141   xbt_os_thread_t res_thread = xbt_new(s_xbt_os_thread_t, 1);
142   res_thread->name = xbt_strdup(name);
143   res_thread->start_routine = start_routine;
144   res_thread->param = param;
145   res_thread->exception = xbt_new(ex_ctx_t, 1);
146   XBT_CTX_INITIALIZE(res_thread->exception);
147
148   if ((errcode = pthread_create(&(res_thread->t), NULL,
149                                 wrapper_start_routine, res_thread)))
150     THROW1(system_error, errcode,
151            "pthread_create failed: %s", strerror(errcode));
152
153   return res_thread;
154 }
155
156 const char *xbt_os_thread_name(xbt_os_thread_t t)
157 {
158   return t->name;
159 }
160
161 const char *xbt_os_thread_self_name(void)
162 {
163   xbt_os_thread_t self = xbt_os_thread_self();
164   return self ? self->name : "main";
165 }
166
167 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
168 {
169
170   int errcode;
171
172   if ((errcode = pthread_join(thread->t, thread_return)))
173     THROW1(system_error, errcode, "pthread_join failed: %s",
174            strerror(errcode));
175   if (thread->exception)
176     free(thread->exception);
177
178   if (thread->name)
179     free(thread->name);
180
181   if (thread == main_thread)    /* just killed main thread */
182     main_thread = NULL;
183
184   free(thread);
185 }
186
187 void xbt_os_thread_exit(int *retval)
188 {
189   pthread_exit(retval);
190 }
191
192 xbt_os_thread_t xbt_os_thread_self(void)
193 {
194   xbt_os_thread_t res;
195
196   if (!thread_mod_inited)
197     return NULL;
198
199   res = pthread_getspecific(xbt_self_thread_key);
200   if (!res)
201     res = main_thread;
202
203   return res;
204 }
205
206 #include <sched.h>
207 void xbt_os_thread_yield(void)
208 {
209   sched_yield();
210 }
211
212 void xbt_os_thread_cancel(xbt_os_thread_t t)
213 {
214   pthread_cancel(t->t);
215 }
216
217 /****** mutex related functions ******/
218 typedef struct xbt_os_mutex_ {
219   /* KEEP IT IN SYNC WITH xbt_thread.c */
220   pthread_mutex_t m;
221 } s_xbt_os_mutex_t;
222
223 #include <time.h>
224 #include <math.h>
225
226 xbt_os_mutex_t xbt_os_mutex_init(void)
227 {
228   xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
229   int errcode;
230
231   if ((errcode = pthread_mutex_init(&(res->m), NULL)))
232     THROW1(system_error, errcode, "pthread_mutex_init() failed: %s",
233            strerror(errcode));
234
235   return res;
236 }
237
238 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
239 {
240   int errcode;
241
242   if ((errcode = pthread_mutex_lock(&(mutex->m))))
243     THROW2(system_error, errcode, "pthread_mutex_lock(%p) failed: %s",
244            mutex, strerror(errcode));
245 }
246
247
248 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
249 {
250   int errcode;
251
252   if (delay < 0) {
253     xbt_os_mutex_acquire(mutex);
254
255   } else if (delay == 0) {
256     errcode = pthread_mutex_trylock(&(mutex->m));
257
258     switch (errcode) {
259     case 0:
260       return;
261     case ETIMEDOUT:
262       THROW1(timeout_error, 0, "mutex %p not ready", mutex);
263     default:
264       THROW2(system_error, errcode, "xbt_mutex_timedacquire(%p) failed: %s",
265              mutex, strerror(errcode));
266     }
267
268
269   } else {
270
271 #ifdef HAVE_MUTEX_TIMEDLOCK
272     struct timespec ts_end;
273     double end = delay + xbt_os_time();
274
275     ts_end.tv_sec = (time_t) floor(end);
276     ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
277     DEBUG2("pthread_mutex_timedlock(%p,%p)", &(mutex->m), &ts_end);
278
279     errcode = pthread_mutex_timedlock(&(mutex->m), &ts_end);
280
281 #else /* Well, let's reimplement it since those lazy libc dudes didn't */
282     double start = xbt_os_time();
283     do {
284       errcode = pthread_mutex_trylock(&(mutex->m));
285       if (errcode == EBUSY)
286         xbt_os_thread_yield();
287     } while (errcode == EBUSY && xbt_os_time() - start < delay);
288
289     if (errcode == EBUSY)
290       errcode = ETIMEDOUT;
291
292 #endif /* HAVE_MUTEX_TIMEDLOCK */
293
294     switch (errcode) {
295     case 0:
296       return;
297
298     case ETIMEDOUT:
299       THROW2(timeout_error, delay,
300              "mutex %p wasn't signaled before timeout (%f)", mutex, delay);
301
302     default:
303       THROW3(system_error, errcode,
304              "pthread_mutex_timedlock(%p,%f) failed: %s", mutex, delay,
305              strerror(errcode));
306     }
307   }
308 }
309
310 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
311 {
312   int errcode;
313
314   if ((errcode = pthread_mutex_unlock(&(mutex->m))))
315     THROW2(system_error, errcode, "pthread_mutex_unlock(%p) failed: %s",
316            mutex, strerror(errcode));
317 }
318
319 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
320 {
321   int errcode;
322
323   if (!mutex)
324     return;
325
326   if ((errcode = pthread_mutex_destroy(&(mutex->m))))
327     THROW2(system_error, errcode, "pthread_mutex_destroy(%p) failed: %s",
328            mutex, strerror(errcode));
329   free(mutex);
330 }
331
332 /***** condition related functions *****/
333 typedef struct xbt_os_cond_ {
334   /* KEEP IT IN SYNC WITH xbt_thread.c */
335   pthread_cond_t c;
336 } s_xbt_os_cond_t;
337
338 xbt_os_cond_t xbt_os_cond_init(void)
339 {
340   xbt_os_cond_t res = xbt_new(s_xbt_os_cond_t, 1);
341   int errcode;
342   if ((errcode = pthread_cond_init(&(res->c), NULL)))
343     THROW1(system_error, errcode, "pthread_cond_init() failed: %s",
344            strerror(errcode));
345
346   return res;
347 }
348
349 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
350 {
351   int errcode;
352   if ((errcode = pthread_cond_wait(&(cond->c), &(mutex->m))))
353     THROW3(system_error, errcode, "pthread_cond_wait(%p,%p) failed: %s",
354            cond, mutex, strerror(errcode));
355 }
356
357
358 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
359                            double delay)
360 {
361   int errcode;
362   struct timespec ts_end;
363   double end = delay + xbt_os_time();
364
365   if (delay < 0) {
366     xbt_os_cond_wait(cond, mutex);
367   } else {
368     ts_end.tv_sec = (time_t) floor(end);
369     ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
370     DEBUG3("pthread_cond_timedwait(%p,%p,%p)", &(cond->c), &(mutex->m),
371            &ts_end);
372     switch ((errcode =
373              pthread_cond_timedwait(&(cond->c), &(mutex->m), &ts_end))) {
374     case 0:
375       return;
376     case ETIMEDOUT:
377       THROW3(timeout_error, errcode,
378              "condition %p (mutex %p) wasn't signaled before timeout (%f)",
379              cond, mutex, delay);
380     default:
381       THROW4(system_error, errcode,
382              "pthread_cond_timedwait(%p,%p,%f) failed: %s", cond, mutex,
383              delay, strerror(errcode));
384     }
385   }
386 }
387
388 void xbt_os_cond_signal(xbt_os_cond_t cond)
389 {
390   int errcode;
391   if ((errcode = pthread_cond_signal(&(cond->c))))
392     THROW2(system_error, errcode, "pthread_cond_signal(%p) failed: %s",
393            cond, strerror(errcode));
394 }
395
396 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
397 {
398   int errcode;
399   if ((errcode = pthread_cond_broadcast(&(cond->c))))
400     THROW2(system_error, errcode, "pthread_cond_broadcast(%p) failed: %s",
401            cond, strerror(errcode));
402 }
403
404 void xbt_os_cond_destroy(xbt_os_cond_t cond)
405 {
406   int errcode;
407
408   if (!cond)
409     return;
410
411   if ((errcode = pthread_cond_destroy(&(cond->c))))
412     THROW2(system_error, errcode, "pthread_cond_destroy(%p) failed: %s",
413            cond, strerror(errcode));
414   free(cond);
415 }
416
417 void *xbt_os_thread_getparam(void)
418 {
419   xbt_os_thread_t t = xbt_os_thread_self();
420   return t ? t->param : NULL;
421 }
422
423 typedef struct xbt_os_sem_ {
424 #ifndef HAVE_SEM_INIT
425   char *name;
426 #endif
427   sem_t s;
428   sem_t *ps;
429 } s_xbt_os_sem_t;
430
431 #ifndef SEM_FAILED
432 #define SEM_FAILED (-1)
433 #endif
434
435 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
436 {
437   xbt_os_sem_t res = xbt_new(s_xbt_os_sem_t, 1);
438
439   /* On some systems (MAC OS X), only the stub of sem_init is to be found.
440    * Any attempt to use it leads to ENOSYS (function not implemented).
441    * If such a prehistoric system is detected, do the job with sem_open instead
442    */
443 #ifdef HAVE_SEM_INIT
444   if (sem_init(&(res->s), 0, value) != 0)
445     THROW1(system_error, errno, "sem_init() failed: %s", strerror(errno));
446   res->ps = &(res->s);
447
448 #else /* damn, no sem_init(). Reimplement it */
449
450   xbt_os_mutex_acquire(next_sem_ID_lock);
451   res->name = bprintf("/%d.%d", (*xbt_getpid) (), ++next_sem_ID);
452   xbt_os_mutex_release(next_sem_ID_lock);
453
454   res->ps = sem_open(res->name, O_CREAT, 0644, value);
455   if ((res->ps == (sem_t *) SEM_FAILED) && (errno == ENAMETOOLONG)) {
456     /* Old darwins only allow 13 chars. Did you create *that* amount of semaphores? */
457     res->name[13] = '\0';
458     res->ps = sem_open(res->name, O_CREAT, 0644, 1);
459   }
460   if ((res->ps == (sem_t *) SEM_FAILED))
461     THROW1(system_error, errno, "sem_open() failed: %s", strerror(errno));
462
463   /* Remove the name from the semaphore namespace: we never join on it */
464   if (sem_unlink(res->name) < 0)
465     THROW1(system_error, errno, "sem_unlink() failed: %s", strerror(errno));
466
467 #endif
468
469   return res;
470 }
471
472 void xbt_os_sem_acquire(xbt_os_sem_t sem)
473 {
474   if (!sem)
475     THROW0(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
476   if (sem_wait(sem->ps) < 0)
477     THROW1(system_error, errno, "sem_wait() failed: %s", strerror(errno));
478 }
479
480 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double delay)
481 {
482   int errcode;
483
484   if (!sem)
485     THROW0(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
486
487   if (delay < 0) {
488     xbt_os_sem_acquire(sem);
489   } else if (delay == 0) {
490     errcode = sem_trywait(sem->ps);
491
492     switch (errcode) {
493     case 0:
494       return;
495     case ETIMEDOUT:
496       THROW1(timeout_error, 0, "semaphore %p not ready", sem);
497     default:
498       THROW2(system_error, errcode, "xbt_os_sem_timedacquire(%p) failed: %s",
499              sem, strerror(errcode));
500     }
501
502   } else {
503 #ifdef HAVE_SEM_WAIT
504     struct timespec ts_end;
505     double end = delay + xbt_os_time();
506
507     ts_end.tv_sec = (time_t) floor(end);
508     ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
509     DEBUG2("sem_timedwait(%p,%p)", sem->ps, &ts_end);
510     errcode = sem_timedwait(sem->s, &ts_end);
511
512 #else /* Okay, reimplement this function then */
513     double start = xbt_os_time();
514     do {
515       errcode = sem_trywait(sem->ps);
516       if (errcode == EBUSY)
517         xbt_os_thread_yield();
518     } while (errcode == EBUSY && xbt_os_time() - start < delay);
519
520     if (errcode == EBUSY)
521       errcode = ETIMEDOUT;
522 #endif
523
524     switch (errcode) {
525     case 0:
526       return;
527
528     case ETIMEDOUT:
529       THROW2(timeout_error, delay,
530              "semaphore %p wasn't signaled before timeout (%f)", sem, delay);
531
532     default:
533       THROW3(system_error, errcode, "sem_timedwait(%p,%f) failed: %s", sem,
534              delay, strerror(errcode));
535     }
536   }
537 }
538
539 void xbt_os_sem_release(xbt_os_sem_t sem)
540 {
541   if (!sem)
542     THROW0(arg_error, EINVAL, "Cannot release of the NULL semaphore");
543
544   if (sem_post(sem->ps) < 0)
545     THROW1(system_error, errno, "sem_post() failed: %s", strerror(errno));
546 }
547
548 void xbt_os_sem_destroy(xbt_os_sem_t sem)
549 {
550   if (!sem)
551     THROW0(arg_error, EINVAL, "Cannot destroy the NULL sempahore");
552
553 #ifdef HAVE_SEM_INIT
554   if (sem_destroy(sem->ps))
555     <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(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_init(void)
602 {
603   xbt_self_thread_key = TlsAlloc();
604 }
605
606 void xbt_os_thread_mod_exit(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