Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
implement xbt_os_thread_cancel() for windows and make a little changes (test pointer...
[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