Logo AND Algorithmique Numérique Distribuée

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