Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of scm.gforge.inria.fr:/gitroot/simgrid/simgrid
[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   if (thread->name)
733     free(thread->name);
734
735   free(thread);
736 }
737
738 void xbt_os_thread_exit(int *retval)
739 {
740   if (retval)
741     ExitThread(*retval);
742   else
743     ExitThread(0);
744 }
745
746 void xbt_os_thread_key_create(xbt_os_thread_key_t* key) {
747
748   *key = TlsAlloc();
749 }
750
751 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value) {
752
753   if (!TlsSetValue(key, value))
754     THROWF(system_error, (int) GetLastError(), "TlsSetValue() failed");
755 }
756
757 void* xbt_os_thread_get_specific(xbt_os_thread_key_t key) {
758   return TlsGetValue(key);
759 }
760
761 void xbt_os_thread_detach(xbt_os_thread_t thread)
762 {
763   THROW_UNIMPLEMENTED;
764 }
765
766
767 xbt_os_thread_t xbt_os_thread_self(void)
768 {
769   return TlsGetValue(xbt_self_thread_key);
770 }
771
772 void *xbt_os_thread_getparam(void)
773 {
774   xbt_os_thread_t t = xbt_os_thread_self();
775   return t->param;
776 }
777
778
779 void xbt_os_thread_yield(void)
780 {
781   Sleep(0);
782 }
783
784 void xbt_os_thread_cancel(xbt_os_thread_t t)
785 {
786   if (!TerminateThread(t->handle, 0))
787     THROWF(system_error, (int) GetLastError(), "TerminateThread failed");
788 }
789
790 /****** mutex related functions ******/
791 typedef struct xbt_os_mutex_ {
792   /* KEEP IT IN SYNC WITH xbt_thread.c */
793   CRITICAL_SECTION lock;
794 } s_xbt_os_mutex_t;
795
796 xbt_os_mutex_t xbt_os_mutex_init(void)
797 {
798   xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
799
800   /* initialize the critical section object */
801   InitializeCriticalSection(&(res->lock));
802
803   return res;
804 }
805
806 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
807 {
808   EnterCriticalSection(&mutex->lock);
809 }
810
811 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
812 {
813   THROW_UNIMPLEMENTED;
814 }
815
816 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
817 {
818
819   LeaveCriticalSection(&mutex->lock);
820
821 }
822
823 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
824 {
825
826   if (!mutex)
827     return;
828
829   DeleteCriticalSection(&mutex->lock);
830   free(mutex);
831 }
832
833 /***** condition related functions *****/
834 enum {                          /* KEEP IT IN SYNC WITH xbt_thread.c */
835   SIGNAL = 0,
836   BROADCAST = 1,
837   MAX_EVENTS = 2
838 };
839
840 typedef struct xbt_os_cond_ {
841   /* KEEP IT IN SYNC WITH xbt_thread.c */
842   HANDLE events[MAX_EVENTS];
843
844   unsigned int waiters_count;   /* the number of waiters                        */
845   CRITICAL_SECTION waiters_count_lock;  /* protect access to waiters_count  */
846 } s_xbt_os_cond_t;
847
848 xbt_os_cond_t xbt_os_cond_init(void)
849 {
850
851   xbt_os_cond_t res = xbt_new0(s_xbt_os_cond_t, 1);
852
853   memset(&res->waiters_count_lock, 0, sizeof(CRITICAL_SECTION));
854
855   /* initialize the critical section object */
856   InitializeCriticalSection(&res->waiters_count_lock);
857
858   res->waiters_count = 0;
859
860   /* Create an auto-reset event */
861   res->events[SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL);
862
863   if (!res->events[SIGNAL]) {
864     DeleteCriticalSection(&res->waiters_count_lock);
865     free(res);
866     THROWF(system_error, 0, "CreateEvent failed for the signals");
867   }
868
869   /* Create a manual-reset event. */
870   res->events[BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
871
872   if (!res->events[BROADCAST]) {
873
874     DeleteCriticalSection(&res->waiters_count_lock);
875     CloseHandle(res->events[SIGNAL]);
876     free(res);
877     THROWF(system_error, 0, "CreateEvent failed for the broadcasts");
878   }
879
880   return res;
881 }
882
883 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
884 {
885
886   unsigned long wait_result;
887   int is_last_waiter;
888
889   /* lock the threads counter and increment it */
890   EnterCriticalSection(&cond->waiters_count_lock);
891   cond->waiters_count++;
892   LeaveCriticalSection(&cond->waiters_count_lock);
893
894   /* unlock the mutex associate with the condition */
895   LeaveCriticalSection(&mutex->lock);
896
897   /* wait for a signal (broadcast or no) */
898   wait_result = WaitForMultipleObjects(2, cond->events, FALSE, INFINITE);
899
900   if (wait_result == WAIT_FAILED)
901     THROWF(system_error, 0,
902            "WaitForMultipleObjects failed, so we cannot wait on the condition");
903
904   /* we have a signal lock the condition */
905   EnterCriticalSection(&cond->waiters_count_lock);
906   cond->waiters_count--;
907
908   /* it's the last waiter or it's a broadcast ? */
909   is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
910                     && (cond->waiters_count == 0));
911
912   LeaveCriticalSection(&cond->waiters_count_lock);
913
914   /* yes it's the last waiter or it's a broadcast
915    * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
916    * by the system.
917    */
918   if (is_last_waiter)
919     if (!ResetEvent(cond->events[BROADCAST]))
920       THROWF(system_error, 0, "ResetEvent failed");
921
922   /* relock the mutex associated with the condition in accordance with the posix thread specification */
923   EnterCriticalSection(&mutex->lock);
924 }
925
926 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
927                            double delay)
928 {
929
930   unsigned long wait_result = WAIT_TIMEOUT;
931   int is_last_waiter;
932   unsigned long end = (unsigned long) (delay * 1000);
933
934
935   if (delay < 0) {
936     xbt_os_cond_wait(cond, mutex);
937   } else {
938     XBT_DEBUG("xbt_cond_timedwait(%p,%p,%lu)", &(cond->events),
939            &(mutex->lock), end);
940
941     /* lock the threads counter and increment it */
942     EnterCriticalSection(&cond->waiters_count_lock);
943     cond->waiters_count++;
944     LeaveCriticalSection(&cond->waiters_count_lock);
945
946     /* unlock the mutex associate with the condition */
947     LeaveCriticalSection(&mutex->lock);
948     /* wait for a signal (broadcast or no) */
949
950     wait_result = WaitForMultipleObjects(2, cond->events, FALSE, end);
951
952     switch (wait_result) {
953     case WAIT_TIMEOUT:
954       THROWF(timeout_error, GetLastError(),
955              "condition %p (mutex %p) wasn't signaled before timeout (%f)",
956              cond, mutex, delay);
957     case WAIT_FAILED:
958       THROWF(system_error, GetLastError(),
959              "WaitForMultipleObjects failed, so we cannot wait on the condition");
960     }
961
962     /* we have a signal lock the condition */
963     EnterCriticalSection(&cond->waiters_count_lock);
964     cond->waiters_count--;
965
966     /* it's the last waiter or it's a broadcast ? */
967     is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
968                       && (cond->waiters_count == 0));
969
970     LeaveCriticalSection(&cond->waiters_count_lock);
971
972     /* yes it's the last waiter or it's a broadcast
973      * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
974      * by the system.
975      */
976     if (is_last_waiter)
977       if (!ResetEvent(cond->events[BROADCAST]))
978         THROWF(system_error, 0, "ResetEvent failed");
979
980     /* relock the mutex associated with the condition in accordance with the posix thread specification */
981     EnterCriticalSection(&mutex->lock);
982   }
983   /*THROW_UNIMPLEMENTED; */
984 }
985
986 void xbt_os_cond_signal(xbt_os_cond_t cond)
987 {
988   int have_waiters;
989
990   EnterCriticalSection(&cond->waiters_count_lock);
991   have_waiters = cond->waiters_count > 0;
992   LeaveCriticalSection(&cond->waiters_count_lock);
993
994   if (have_waiters)
995     if (!SetEvent(cond->events[SIGNAL]))
996       THROWF(system_error, 0, "SetEvent failed");
997
998   xbt_os_thread_yield();
999 }
1000
1001 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
1002 {
1003   int have_waiters;
1004
1005   EnterCriticalSection(&cond->waiters_count_lock);
1006   have_waiters = cond->waiters_count > 0;
1007   LeaveCriticalSection(&cond->waiters_count_lock);
1008
1009   if (have_waiters)
1010     SetEvent(cond->events[BROADCAST]);
1011 }
1012
1013 void xbt_os_cond_destroy(xbt_os_cond_t cond)
1014 {
1015   int error = 0;
1016
1017   if (!cond)
1018     return;
1019
1020   if (!CloseHandle(cond->events[SIGNAL]))
1021     error = 1;
1022
1023   if (!CloseHandle(cond->events[BROADCAST]))
1024     error = 1;
1025
1026   DeleteCriticalSection(&cond->waiters_count_lock);
1027
1028   xbt_free(cond);
1029
1030   if (error)
1031     THROWF(system_error, 0, "Error while destroying the condition");
1032 }
1033
1034 typedef struct xbt_os_sem_ {
1035   HANDLE h;
1036   unsigned int value;
1037   CRITICAL_SECTION value_lock;  /* protect access to value of the semaphore  */
1038 } s_xbt_os_sem_t;
1039
1040 #ifndef INT_MAX
1041 # define INT_MAX 32767          /* let's be safe by underestimating this value: this is for 16bits only */
1042 #endif
1043
1044 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
1045 {
1046   xbt_os_sem_t res;
1047
1048   if (value > INT_MAX)
1049     THROWF(arg_error, value,
1050            "Semaphore initial value too big: %ud cannot be stored as a signed int",
1051            value);
1052
1053   res = (xbt_os_sem_t) xbt_new0(s_xbt_os_sem_t, 1);
1054
1055   if (!(res->h = CreateSemaphore(NULL, value, (long) INT_MAX, NULL))) {
1056     THROWF(system_error, GetLastError(), "CreateSemaphore() failed: %s",
1057            strerror(GetLastError()));
1058     return NULL;
1059   }
1060
1061   res->value = value;
1062
1063   InitializeCriticalSection(&(res->value_lock));
1064
1065   return res;
1066 }
1067
1068 void xbt_os_sem_acquire(xbt_os_sem_t sem)
1069 {
1070   if (!sem)
1071     THROWF(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1072
1073   /* wait failure */
1074   if (WAIT_OBJECT_0 != WaitForSingleObject(sem->h, INFINITE))
1075     THROWF(system_error, GetLastError(),
1076            "WaitForSingleObject() failed: %s", strerror(GetLastError()));
1077   EnterCriticalSection(&(sem->value_lock));
1078   sem->value--;
1079   LeaveCriticalSection(&(sem->value_lock));
1080 }
1081
1082 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double timeout)
1083 {
1084   long seconds;
1085   long milliseconds;
1086   double end = timeout + xbt_os_time();
1087
1088   if (!sem)
1089     THROWF(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1090
1091   if (timeout < 0) {
1092     xbt_os_sem_acquire(sem);
1093   } else {                      /* timeout can be zero <-> try acquire ) */
1094
1095
1096     seconds = (long) floor(end);
1097     milliseconds = (long) ((end - seconds) * 1000);
1098     milliseconds += (seconds * 1000);
1099
1100     switch (WaitForSingleObject(sem->h, milliseconds)) {
1101     case WAIT_OBJECT_0:
1102       EnterCriticalSection(&(sem->value_lock));
1103       sem->value--;
1104       LeaveCriticalSection(&(sem->value_lock));
1105       return;
1106
1107     case WAIT_TIMEOUT:
1108       THROWF(timeout_error, GetLastError(),
1109              "semaphore %p wasn't signaled before timeout (%f)", sem,
1110              timeout);
1111       return;
1112
1113     default:
1114       THROWF(system_error, GetLastError(),
1115              "WaitForSingleObject(%p,%f) failed: %s", sem, timeout,
1116              strerror(GetLastError()));
1117     }
1118   }
1119 }
1120
1121 void xbt_os_sem_release(xbt_os_sem_t sem)
1122 {
1123   if (!sem)
1124     THROWF(arg_error, EINVAL, "Cannot release the NULL semaphore");
1125
1126   if (!ReleaseSemaphore(sem->h, 1, NULL))
1127     THROWF(system_error, GetLastError(), "ReleaseSemaphore() failed: %s",
1128            strerror(GetLastError()));
1129   EnterCriticalSection(&(sem->value_lock));
1130   sem->value++;
1131   LeaveCriticalSection(&(sem->value_lock));
1132 }
1133
1134 void xbt_os_sem_destroy(xbt_os_sem_t sem)
1135 {
1136   if (!sem)
1137     THROWF(arg_error, EINVAL, "Cannot destroy the NULL semaphore");
1138
1139   if (!CloseHandle(sem->h))
1140     THROWF(system_error, GetLastError(), "CloseHandle() failed: %s",
1141            strerror(GetLastError()));
1142
1143   DeleteCriticalSection(&(sem->value_lock));
1144
1145   xbt_free(sem);
1146
1147 }
1148
1149 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
1150 {
1151   if (!sem)
1152     THROWF(arg_error, EINVAL,
1153            "Cannot get the value of the NULL semaphore");
1154
1155   EnterCriticalSection(&(sem->value_lock));
1156   *svalue = sem->value;
1157   LeaveCriticalSection(&(sem->value_lock));
1158 }
1159
1160
1161 #endif
1162
1163 /***** reentrant mutexes *****/
1164 typedef struct xbt_os_rmutex_ {
1165   xbt_os_mutex_t mutex;
1166   xbt_os_thread_t owner;
1167   int count;
1168 } s_xbt_os_rmutex_t;
1169
1170 void xbt_os_thread_set_extra_data(void *data)
1171 {
1172   xbt_os_thread_self()->extra_data = data;
1173 }
1174
1175 void *xbt_os_thread_get_extra_data(void)
1176 {
1177   return xbt_os_thread_self()->extra_data;
1178 }
1179
1180 xbt_os_rmutex_t xbt_os_rmutex_init(void)
1181 {
1182   xbt_os_rmutex_t rmutex = xbt_new0(struct xbt_os_rmutex_, 1);
1183   rmutex->mutex = xbt_os_mutex_init();
1184   rmutex->owner = NULL;
1185   rmutex->count = 0;
1186   return rmutex;
1187 }
1188
1189 void xbt_os_rmutex_acquire(xbt_os_rmutex_t rmutex)
1190 {
1191   xbt_os_thread_t self = xbt_os_thread_self();
1192
1193   if (self == NULL) {
1194     /* the thread module is not initialized yet */
1195     rmutex->owner = NULL;
1196     return;
1197   }
1198
1199   if (self != rmutex->owner) {
1200     xbt_os_mutex_acquire(rmutex->mutex);
1201     rmutex->owner = self;
1202     rmutex->count = 1;
1203   } else {
1204     rmutex->count++;
1205  }
1206 }
1207
1208 void xbt_os_rmutex_release(xbt_os_rmutex_t rmutex)
1209 {
1210   if (rmutex->owner == NULL) {
1211     /* the thread module was not initialized */
1212     return;
1213   }
1214
1215   xbt_assert(rmutex->owner == xbt_os_thread_self());
1216
1217   if (--rmutex->count == 0) {
1218     rmutex->owner = NULL;
1219     xbt_os_mutex_release(rmutex->mutex);
1220   }
1221 }
1222
1223 void xbt_os_rmutex_destroy(xbt_os_rmutex_t rmutex)
1224 {
1225   xbt_os_mutex_destroy(rmutex->mutex);
1226   xbt_free(rmutex);
1227 }