Logo AND Algorithmique Numérique Distribuée

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