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 */
5 /* Copyright (c) 2007, 2008, 2009, 2010. The SimGrid Team.
6 * All rights reserved. */
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. */
11 #include "gras_config.h"
12 #include "xbt/sysdep.h"
14 #include "xbt/ex_interface.h" /* We play crude games with exceptions */
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 */
20 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_sync_os, xbt,
21 "Synchronization mechanism (OS-level)");
23 /* ********************************* PTHREAD IMPLEMENTATION ************************************ */
26 #include <semaphore.h>
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);
35 /* use named sempahore when sem_init() does not work */
37 static int next_sem_ID = 0;
38 static xbt_os_mutex_t next_sem_ID_lock;
41 typedef struct xbt_os_thread_ {
46 pvoid_f_pvoid_t start_routine;
47 xbt_running_ctx_t *running_ctx;
50 static xbt_os_thread_t main_thread = NULL;
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;
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)
59 if (thread == main_thread) /* just killed main thread */
62 free(thread->running_ctx);
67 /* callback: context fetching */
68 static xbt_running_ctx_t *_os_thread_get_running_ctx(void)
70 return xbt_os_thread_self()->running_ctx;
73 /* callback: termination */
74 static void _os_thread_ex_terminate(xbt_ex_t * e)
79 /* FIXME: there should be a configuration variable to choose to kill everyone or only this one */
82 void xbt_os_thread_mod_preinit(void)
86 if (thread_mod_inited)
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");
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);
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");
105 __xbt_running_ctx_fetch = _os_thread_get_running_ctx;
106 __xbt_ex_terminate = _os_thread_ex_terminate;
108 thread_mod_inited = 1;
110 #ifndef HAVE_SEM_INIT
111 next_sem_ID_lock = xbt_os_mutex_init();
116 void xbt_os_thread_mod_postexit(void)
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 */
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);
127 thread_mod_inited = 0;
128 #ifndef HAVE_SEM_INIT
129 xbt_os_mutex_destroy(next_sem_ID_lock);
132 /* Restore the default exception setup */
133 __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
134 __xbt_ex_terminate = &__xbt_ex_terminate_default;
137 int xbt_os_thread_atfork(void (*prepare)(void),
138 void (*parent)(void), void (*child)(void))
140 return pthread_atfork(prepare, parent, child);
143 static void *wrapper_start_routine(void *s)
145 xbt_os_thread_t t = s;
148 if ((errcode = pthread_setspecific(xbt_self_thread_key, t)))
149 THROWF(system_error, errcode,
150 "pthread_setspecific failed for xbt_self_thread_key");
152 void *res = t->start_routine(t->param);
154 xbt_os_thread_free_thread_data(t);
158 xbt_os_thread_t xbt_os_thread_create(const char *name,
159 pvoid_f_pvoid_t start_routine,
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;
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));
182 const char *xbt_os_thread_name(xbt_os_thread_t t)
187 const char *xbt_os_thread_self_name(void)
189 xbt_os_thread_t me = xbt_os_thread_self();
190 return me ? me->name : "main";
193 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
198 if ((errcode = pthread_join(thread->t, thread_return)))
199 THROWF(system_error, errcode, "pthread_join failed: %s",
201 xbt_os_thread_free_thread_data(thread);
204 void xbt_os_thread_exit(int *retval)
206 pthread_exit(retval);
209 xbt_os_thread_t xbt_os_thread_self(void)
213 if (!thread_mod_inited)
216 res = pthread_getspecific(xbt_self_thread_key);
221 void xbt_os_thread_key_create(xbt_os_thread_key_t* key) {
224 if ((errcode = pthread_key_create(key, NULL)))
225 THROWF(system_error, errcode, "pthread_key_create failed");
228 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value) {
231 if ((errcode = pthread_setspecific(key, value)))
232 THROWF(system_error, errcode, "pthread_setspecific failed");
235 void* xbt_os_thread_get_specific(xbt_os_thread_key_t key) {
236 return pthread_getspecific(key);
239 void xbt_os_thread_detach(xbt_os_thread_t thread)
241 thread->detached = 1;
242 pthread_detach(thread->t);
246 void xbt_os_thread_yield(void)
251 void xbt_os_thread_cancel(xbt_os_thread_t t)
253 pthread_cancel(t->t);
256 /****** mutex related functions ******/
257 typedef struct xbt_os_mutex_ {
258 /* KEEP IT IN SYNC WITH xbt_thread.c */
265 xbt_os_mutex_t xbt_os_mutex_init(void)
267 xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
270 if ((errcode = pthread_mutex_init(&(res->m), NULL)))
271 THROWF(system_error, errcode, "pthread_mutex_init() failed: %s",
277 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
281 if ((errcode = pthread_mutex_lock(&(mutex->m))))
282 THROWF(system_error, errcode, "pthread_mutex_lock(%p) failed: %s",
283 mutex, strerror(errcode));
287 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
292 xbt_os_mutex_acquire(mutex);
294 } else if (delay == 0) {
295 errcode = pthread_mutex_trylock(&(mutex->m));
301 THROWF(timeout_error, 0, "mutex %p not ready", mutex);
303 THROWF(system_error, errcode,
304 "xbt_mutex_timedacquire(%p) failed: %s", mutex,
311 #ifdef HAVE_MUTEX_TIMEDLOCK
312 struct timespec ts_end;
313 double end = delay + xbt_os_time();
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);
319 errcode = pthread_mutex_timedlock(&(mutex->m), &ts_end);
321 #else /* Well, let's reimplement it since those lazy libc dudes didn't */
322 double start = xbt_os_time();
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);
329 if (errcode == EBUSY)
332 #endif /* HAVE_MUTEX_TIMEDLOCK */
339 THROWF(timeout_error, delay,
340 "mutex %p wasn't signaled before timeout (%f)", mutex, delay);
343 THROWF(system_error, errcode,
344 "pthread_mutex_timedlock(%p,%f) failed: %s", mutex, delay,
350 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
354 if ((errcode = pthread_mutex_unlock(&(mutex->m))))
355 THROWF(system_error, errcode, "pthread_mutex_unlock(%p) failed: %s",
356 mutex, strerror(errcode));
359 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
366 if ((errcode = pthread_mutex_destroy(&(mutex->m))))
367 THROWF(system_error, errcode, "pthread_mutex_destroy(%p) failed: %s",
368 mutex, strerror(errcode));
372 /***** condition related functions *****/
373 typedef struct xbt_os_cond_ {
374 /* KEEP IT IN SYNC WITH xbt_thread.c */
378 xbt_os_cond_t xbt_os_cond_init(void)
380 xbt_os_cond_t res = xbt_new(s_xbt_os_cond_t, 1);
382 if ((errcode = pthread_cond_init(&(res->c), NULL)))
383 THROWF(system_error, errcode, "pthread_cond_init() failed: %s",
389 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
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));
398 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
402 struct timespec ts_end;
403 double end = delay + xbt_os_time();
406 xbt_os_cond_wait(cond, mutex);
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),
413 pthread_cond_timedwait(&(cond->c), &(mutex->m), &ts_end))) {
417 THROWF(timeout_error, errcode,
418 "condition %p (mutex %p) wasn't signaled before timeout (%f)",
421 THROWF(system_error, errcode,
422 "pthread_cond_timedwait(%p,%p,%f) failed: %s", cond, mutex,
423 delay, strerror(errcode));
428 void xbt_os_cond_signal(xbt_os_cond_t cond)
431 if ((errcode = pthread_cond_signal(&(cond->c))))
432 THROWF(system_error, errcode, "pthread_cond_signal(%p) failed: %s",
433 cond, strerror(errcode));
436 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
439 if ((errcode = pthread_cond_broadcast(&(cond->c))))
440 THROWF(system_error, errcode, "pthread_cond_broadcast(%p) failed: %s",
441 cond, strerror(errcode));
444 void xbt_os_cond_destroy(xbt_os_cond_t cond)
451 if ((errcode = pthread_cond_destroy(&(cond->c))))
452 THROWF(system_error, errcode, "pthread_cond_destroy(%p) failed: %s",
453 cond, strerror(errcode));
457 void *xbt_os_thread_getparam(void)
459 xbt_os_thread_t t = xbt_os_thread_self();
460 return t ? t->param : NULL;
463 typedef struct xbt_os_sem_ {
464 #ifndef HAVE_SEM_INIT
472 #define SEM_FAILED (-1)
475 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
477 xbt_os_sem_t res = xbt_new(s_xbt_os_sem_t, 1);
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
484 if (sem_init(&(res->s), 0, value) != 0)
485 THROWF(system_error, errno, "sem_init() failed: %s", strerror(errno));
488 #else /* damn, no sem_init(). Reimplement it */
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);
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);
500 if ((res->ps == (sem_t *) SEM_FAILED))
501 THROWF(system_error, errno, "sem_open() failed: %s", strerror(errno));
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",
513 void xbt_os_sem_acquire(xbt_os_sem_t 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));
521 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double delay)
526 THROWF(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
529 xbt_os_sem_acquire(sem);
530 } else if (delay == 0) {
531 errcode = sem_trywait(sem->ps);
537 THROWF(timeout_error, 0, "semaphore %p not ready", sem);
539 THROWF(system_error, errcode,
540 "xbt_os_sem_timedacquire(%p) failed: %s", sem,
546 struct timespec ts_end;
547 double end = delay + xbt_os_time();
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);
554 #else /* Okay, reimplement this function then */
555 double start = xbt_os_time();
557 errcode = sem_trywait(sem->ps);
558 if (errcode == EBUSY)
559 xbt_os_thread_yield();
560 } while (errcode == EBUSY && xbt_os_time() - start < delay);
562 if (errcode == EBUSY)
571 THROWF(timeout_error, delay,
572 "semaphore %p wasn't signaled before timeout (%f)", sem,
576 THROWF(system_error, errcode, "sem_timedwait(%p,%f) failed: %s", sem,
577 delay, strerror(errcode));
582 void xbt_os_sem_release(xbt_os_sem_t sem)
585 THROWF(arg_error, EINVAL, "Cannot release of the NULL semaphore");
587 if (sem_post(sem->ps) < 0)
588 THROWF(system_error, errno, "sem_post() failed: %s", strerror(errno));
591 void xbt_os_sem_destroy(xbt_os_sem_t sem)
594 THROWF(arg_error, EINVAL, "Cannot destroy the NULL sempahore");
597 if (sem_destroy(sem->ps) < 0)
598 THROWF(system_error, errno, "sem_destroy() failed: %s",
601 if (sem_close(sem->ps) < 0)
602 THROWF(system_error, errno, "sem_close() failed: %s", strerror(errno));
609 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
612 THROWF(arg_error, EINVAL,
613 "Cannot get the value of the NULL semaphore");
615 if (sem_getvalue(&(sem->s), svalue) < 0)
616 THROWF(system_error, errno, "sem_getvalue() failed: %s",
620 /* ********************************* WINDOWS IMPLEMENTATION ************************************ */
622 #elif defined(_XBT_WIN32)
626 typedef struct xbt_os_thread_ {
628 HANDLE handle; /* the win thread handle */
629 unsigned long id; /* the win thread id */
630 pvoid_f_pvoid_t start_routine;
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
640 /* the default size of the stack of the threads (in bytes)*/
641 #define XBT_DEFAULT_THREAD_STACK_SIZE 4096
643 /* key to the TLS containing the xbt_os_thread_t structure */
644 static unsigned long xbt_self_thread_key;
646 void xbt_os_thread_mod_preinit(void)
648 xbt_self_thread_key = TlsAlloc();
651 void xbt_os_thread_mod_postexit(void)
654 if (!TlsFree(xbt_self_thread_key))
655 THROWF(system_error, (int) GetLastError(),
656 "TlsFree() failed to cleanup the thread submodule");
659 int xbt_os_thread_atfork(void (*prepare)(void),
660 void (*parent)(void), void (*child)(void))
665 static DWORD WINAPI wrapper_start_routine(void *s)
667 xbt_os_thread_t t = (xbt_os_thread_t) s;
670 if (!TlsSetValue(xbt_self_thread_key, t))
671 THROWF(system_error, (int) GetLastError(),
672 "TlsSetValue of data describing the created thread failed");
674 rv = (DWORD *) ((t->start_routine) (t->param));
681 xbt_os_thread_t xbt_os_thread_create(const char *name,
682 pvoid_f_pvoid_t start_routine,
687 xbt_os_thread_t t = xbt_new(s_xbt_os_thread_t, 1);
689 t->name = xbt_strdup(name);
690 t->start_routine = start_routine;
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));
699 THROWF(system_error, (int) GetLastError(), "CreateThread failed");
705 const char *xbt_os_thread_name(xbt_os_thread_t t)
710 const char *xbt_os_thread_self_name(void)
712 xbt_os_thread_t t = xbt_os_thread_self();
713 return t ? t->name : "main";
716 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
719 if (WAIT_OBJECT_0 != WaitForSingleObject(thread->handle, INFINITE))
720 THROWF(system_error, (int) GetLastError(),
721 "WaitForSingleObject failed");
725 if (!GetExitCodeThread(thread->handle, (DWORD *) (*thread_return)))
726 THROWF(system_error, (int) GetLastError(),
727 "GetExitCodeThread failed");
730 CloseHandle(thread->handle);
737 void xbt_os_thread_exit(int *retval)
745 void xbt_os_thread_key_create(xbt_os_thread_key_t* key) {
750 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value) {
752 if (!TlsSetValue(key, value))
753 THROWF(system_error, (int) GetLastError(), "TlsSetValue() failed");
756 void* xbt_os_thread_get_specific(xbt_os_thread_key_t key) {
757 return TlsGetValue(key);
760 void xbt_os_thread_detach(xbt_os_thread_t thread)
766 xbt_os_thread_t xbt_os_thread_self(void)
768 return TlsGetValue(xbt_self_thread_key);
771 void *xbt_os_thread_getparam(void)
773 xbt_os_thread_t t = xbt_os_thread_self();
778 void xbt_os_thread_yield(void)
783 void xbt_os_thread_cancel(xbt_os_thread_t t)
785 if (!TerminateThread(t->handle, 0))
786 THROWF(system_error, (int) GetLastError(), "TerminateThread failed");
789 /****** mutex related functions ******/
790 typedef struct xbt_os_mutex_ {
791 /* KEEP IT IN SYNC WITH xbt_thread.c */
792 CRITICAL_SECTION lock;
795 xbt_os_mutex_t xbt_os_mutex_init(void)
797 xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
799 /* initialize the critical section object */
800 InitializeCriticalSection(&(res->lock));
805 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
807 EnterCriticalSection(&mutex->lock);
810 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
815 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
818 LeaveCriticalSection(&mutex->lock);
822 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
828 DeleteCriticalSection(&mutex->lock);
832 /***** condition related functions *****/
833 enum { /* KEEP IT IN SYNC WITH xbt_thread.c */
839 typedef struct xbt_os_cond_ {
840 /* KEEP IT IN SYNC WITH xbt_thread.c */
841 HANDLE events[MAX_EVENTS];
843 unsigned int waiters_count; /* the number of waiters */
844 CRITICAL_SECTION waiters_count_lock; /* protect access to waiters_count */
847 xbt_os_cond_t xbt_os_cond_init(void)
850 xbt_os_cond_t res = xbt_new0(s_xbt_os_cond_t, 1);
852 memset(&res->waiters_count_lock, 0, sizeof(CRITICAL_SECTION));
854 /* initialize the critical section object */
855 InitializeCriticalSection(&res->waiters_count_lock);
857 res->waiters_count = 0;
859 /* Create an auto-reset event */
860 res->events[SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL);
862 if (!res->events[SIGNAL]) {
863 DeleteCriticalSection(&res->waiters_count_lock);
865 THROWF(system_error, 0, "CreateEvent failed for the signals");
868 /* Create a manual-reset event. */
869 res->events[BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
871 if (!res->events[BROADCAST]) {
873 DeleteCriticalSection(&res->waiters_count_lock);
874 CloseHandle(res->events[SIGNAL]);
876 THROWF(system_error, 0, "CreateEvent failed for the broadcasts");
882 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
885 unsigned long wait_result;
888 /* lock the threads counter and increment it */
889 EnterCriticalSection(&cond->waiters_count_lock);
890 cond->waiters_count++;
891 LeaveCriticalSection(&cond->waiters_count_lock);
893 /* unlock the mutex associate with the condition */
894 LeaveCriticalSection(&mutex->lock);
896 /* wait for a signal (broadcast or no) */
897 wait_result = WaitForMultipleObjects(2, cond->events, FALSE, INFINITE);
899 if (wait_result == WAIT_FAILED)
900 THROWF(system_error, 0,
901 "WaitForMultipleObjects failed, so we cannot wait on the condition");
903 /* we have a signal lock the condition */
904 EnterCriticalSection(&cond->waiters_count_lock);
905 cond->waiters_count--;
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));
911 LeaveCriticalSection(&cond->waiters_count_lock);
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
918 if (!ResetEvent(cond->events[BROADCAST]))
919 THROWF(system_error, 0, "ResetEvent failed");
921 /* relock the mutex associated with the condition in accordance with the posix thread specification */
922 EnterCriticalSection(&mutex->lock);
925 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
929 unsigned long wait_result = WAIT_TIMEOUT;
931 unsigned long end = (unsigned long) (delay * 1000);
935 xbt_os_cond_wait(cond, mutex);
937 XBT_DEBUG("xbt_cond_timedwait(%p,%p,%lu)", &(cond->events),
938 &(mutex->lock), end);
940 /* lock the threads counter and increment it */
941 EnterCriticalSection(&cond->waiters_count_lock);
942 cond->waiters_count++;
943 LeaveCriticalSection(&cond->waiters_count_lock);
945 /* unlock the mutex associate with the condition */
946 LeaveCriticalSection(&mutex->lock);
947 /* wait for a signal (broadcast or no) */
949 wait_result = WaitForMultipleObjects(2, cond->events, FALSE, end);
951 switch (wait_result) {
953 THROWF(timeout_error, GetLastError(),
954 "condition %p (mutex %p) wasn't signaled before timeout (%f)",
957 THROWF(system_error, GetLastError(),
958 "WaitForMultipleObjects failed, so we cannot wait on the condition");
961 /* we have a signal lock the condition */
962 EnterCriticalSection(&cond->waiters_count_lock);
963 cond->waiters_count--;
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));
969 LeaveCriticalSection(&cond->waiters_count_lock);
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
976 if (!ResetEvent(cond->events[BROADCAST]))
977 THROWF(system_error, 0, "ResetEvent failed");
979 /* relock the mutex associated with the condition in accordance with the posix thread specification */
980 EnterCriticalSection(&mutex->lock);
982 /*THROW_UNIMPLEMENTED; */
985 void xbt_os_cond_signal(xbt_os_cond_t cond)
989 EnterCriticalSection(&cond->waiters_count_lock);
990 have_waiters = cond->waiters_count > 0;
991 LeaveCriticalSection(&cond->waiters_count_lock);
994 if (!SetEvent(cond->events[SIGNAL]))
995 THROWF(system_error, 0, "SetEvent failed");
997 xbt_os_thread_yield();
1000 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
1004 EnterCriticalSection(&cond->waiters_count_lock);
1005 have_waiters = cond->waiters_count > 0;
1006 LeaveCriticalSection(&cond->waiters_count_lock);
1009 SetEvent(cond->events[BROADCAST]);
1012 void xbt_os_cond_destroy(xbt_os_cond_t cond)
1019 if (!CloseHandle(cond->events[SIGNAL]))
1022 if (!CloseHandle(cond->events[BROADCAST]))
1025 DeleteCriticalSection(&cond->waiters_count_lock);
1030 THROWF(system_error, 0, "Error while destroying the condition");
1033 typedef struct xbt_os_sem_ {
1036 CRITICAL_SECTION value_lock; /* protect access to value of the semaphore */
1040 # define INT_MAX 32767 /* let's be safe by underestimating this value: this is for 16bits only */
1043 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
1047 if (value > INT_MAX)
1048 THROWF(arg_error, value,
1049 "Semaphore initial value too big: %ud cannot be stored as a signed int",
1052 res = (xbt_os_sem_t) xbt_new0(s_xbt_os_sem_t, 1);
1054 if (!(res->h = CreateSemaphore(NULL, value, (long) INT_MAX, NULL))) {
1055 THROWF(system_error, GetLastError(), "CreateSemaphore() failed: %s",
1056 strerror(GetLastError()));
1062 InitializeCriticalSection(&(res->value_lock));
1067 void xbt_os_sem_acquire(xbt_os_sem_t sem)
1070 THROWF(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
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));
1078 LeaveCriticalSection(&(sem->value_lock));
1081 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double timeout)
1085 double end = timeout + xbt_os_time();
1088 THROWF(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1091 xbt_os_sem_acquire(sem);
1092 } else { /* timeout can be zero <-> try acquire ) */
1095 seconds = (long) floor(end);
1096 milliseconds = (long) ((end - seconds) * 1000);
1097 milliseconds += (seconds * 1000);
1099 switch (WaitForSingleObject(sem->h, milliseconds)) {
1101 EnterCriticalSection(&(sem->value_lock));
1103 LeaveCriticalSection(&(sem->value_lock));
1107 THROWF(timeout_error, GetLastError(),
1108 "semaphore %p wasn't signaled before timeout (%f)", sem,
1113 THROWF(system_error, GetLastError(),
1114 "WaitForSingleObject(%p,%f) failed: %s", sem, timeout,
1115 strerror(GetLastError()));
1120 void xbt_os_sem_release(xbt_os_sem_t sem)
1123 THROWF(arg_error, EINVAL, "Cannot release the NULL semaphore");
1125 if (!ReleaseSemaphore(sem->h, 1, NULL))
1126 THROWF(system_error, GetLastError(), "ReleaseSemaphore() failed: %s",
1127 strerror(GetLastError()));
1128 EnterCriticalSection(&(sem->value_lock));
1130 LeaveCriticalSection(&(sem->value_lock));
1133 void xbt_os_sem_destroy(xbt_os_sem_t sem)
1136 THROWF(arg_error, EINVAL, "Cannot destroy the NULL semaphore");
1138 if (!CloseHandle(sem->h))
1139 THROWF(system_error, GetLastError(), "CloseHandle() failed: %s",
1140 strerror(GetLastError()));
1142 DeleteCriticalSection(&(sem->value_lock));
1148 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
1151 THROWF(arg_error, EINVAL,
1152 "Cannot get the value of the NULL semaphore");
1154 EnterCriticalSection(&(sem->value_lock));
1155 *svalue = sem->value;
1156 LeaveCriticalSection(&(sem->value_lock));
1162 /***** reentrant mutexes *****/
1163 typedef struct xbt_os_rmutex_ {
1164 xbt_os_mutex_t mutex;
1165 xbt_os_thread_t owner;
1167 } s_xbt_os_rmutex_t;
1169 void xbt_os_thread_set_extra_data(void *data)
1171 xbt_os_thread_self()->extra_data = data;
1174 void *xbt_os_thread_get_extra_data(void)
1176 return xbt_os_thread_self()->extra_data;
1179 xbt_os_rmutex_t xbt_os_rmutex_init(void)
1181 xbt_os_rmutex_t rmutex = xbt_new0(struct xbt_os_rmutex_, 1);
1182 rmutex->mutex = xbt_os_mutex_init();
1183 rmutex->owner = NULL;
1188 void xbt_os_rmutex_acquire(xbt_os_rmutex_t rmutex)
1190 xbt_os_thread_t self = xbt_os_thread_self();
1193 /* the thread module is not initialized yet */
1194 rmutex->owner = NULL;
1198 if (self != rmutex->owner) {
1199 xbt_os_mutex_acquire(rmutex->mutex);
1200 rmutex->owner = self;
1207 void xbt_os_rmutex_release(xbt_os_rmutex_t rmutex)
1209 if (rmutex->owner == NULL) {
1210 /* the thread module was not initialized */
1214 xbt_assert(rmutex->owner == xbt_os_thread_self());
1216 if (--rmutex->count == 0) {
1217 rmutex->owner = NULL;
1218 xbt_os_mutex_release(rmutex->mutex);
1222 void xbt_os_rmutex_destroy(xbt_os_rmutex_t rmutex)
1224 xbt_os_mutex_destroy(rmutex->mutex);