Logo AND Algorithmique Numérique Distribuée

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