Logo AND Algorithmique Numérique Distribuée

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