3 /* xbt_os_thread -- portability layer over the pthread API */
4 /* Used in RL to get win/lin portability, and in SG when CONTEXT_THREAD */
5 /* in SG, when using CONTEXT_UCONTEXT, xbt_os_thread_stub is used instead */
7 /* Copyright 2006,2007 Malek Cherier, Martin Quinson
8 * All right reserved. */
10 /* This program is free software; you can redistribute it and/or modify it
11 * under the terms of the license (GNU LGPL) which comes with this package. */
13 #include "xbt/sysdep.h"
15 #include "xbt/ex_interface.h" /* We play crude games with exceptions */
17 #include "xbt/xbt_os_time.h" /* Portable time facilities */
18 #include "xbt/xbt_os_thread.h" /* This module */
19 #include "xbt_modinter.h" /* Initialization/finalization of this module */
21 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_sync_os, xbt,
22 "Synchronization mechanism (OS-level)");
24 /* ********************************* PTHREAD IMPLEMENTATION ************************************ */
28 #include <semaphore.h>
30 #ifdef HAVE_MUTEX_TIMEDLOCK
31 /* redefine the function header since we fail to get this from system headers on amd (at least) */
32 int pthread_mutex_timedlock(pthread_mutex_t * mutex,
33 const struct timespec *abs_timeout);
37 /* use named sempahore when sem_init() does not work */
39 static int next_sem_ID = 0;
40 static xbt_os_mutex_t next_sem_ID_lock;
43 typedef struct xbt_os_thread_ {
47 pvoid_f_pvoid_t start_routine;
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(void *d)
62 /* callback: context fetching */
63 static ex_ctx_t *_os_thread_ex_ctx(void)
65 return xbt_os_thread_self()->exception;
68 /* callback: termination */
69 static void _os_thread_ex_terminate(xbt_ex_t * e)
74 /* FIXME: there should be a configuration variable to choose to kill everyone or only this one */
77 void xbt_os_thread_mod_init(void)
81 if (thread_mod_inited)
84 if ((errcode = pthread_key_create(&xbt_self_thread_key, NULL)))
85 THROW0(system_error, errcode,
86 "pthread_key_create failed for xbt_self_thread_key");
88 main_thread = xbt_new(s_xbt_os_thread_t, 1);
89 main_thread->name = (char *) "main";
90 main_thread->start_routine = NULL;
91 main_thread->param = NULL;
92 main_thread->exception = xbt_new(ex_ctx_t, 1);
93 XBT_CTX_INITIALIZE(main_thread->exception);
95 __xbt_ex_ctx = _os_thread_ex_ctx;
96 __xbt_ex_terminate = _os_thread_ex_terminate;
98 thread_mod_inited = 1;
100 #ifndef HAVE_SEM_WAIT
101 next_sem_ID_lock = xbt_os_mutex_init();
106 void xbt_os_thread_mod_exit(void)
108 /* FIXME: don't try to free our key on shutdown.
109 Valgrind detects no leak if we don't, and whine if we try to */
112 // if ((errcode=pthread_key_delete(xbt_self_thread_key)))
113 // THROW0(system_error,errcode,"pthread_key_delete failed for xbt_self_thread_key");
114 free(main_thread->exception);
117 thread_mod_inited = 0;
118 #ifndef HAVE_SEM_WAIT
119 xbt_os_mutex_destroy(next_sem_ID_lock);
122 /* Restore the default exception setup */
123 __xbt_ex_ctx = &__xbt_ex_ctx_default;
124 __xbt_ex_terminate = &__xbt_ex_terminate_default;
127 static void *wrapper_start_routine(void *s)
129 xbt_os_thread_t t = s;
132 if ((errcode = pthread_setspecific(xbt_self_thread_key, t)))
133 THROW0(system_error, errcode,
134 "pthread_setspecific failed for xbt_self_thread_key");
136 return (*(t->start_routine)) (t->param);
139 xbt_os_thread_t xbt_os_thread_create(const char *name,
140 pvoid_f_pvoid_t start_routine,
145 xbt_os_thread_t res_thread = xbt_new(s_xbt_os_thread_t, 1);
146 res_thread->name = xbt_strdup(name);
147 res_thread->start_routine = start_routine;
148 res_thread->param = param;
149 res_thread->exception = xbt_new(ex_ctx_t, 1);
150 XBT_CTX_INITIALIZE(res_thread->exception);
152 if ((errcode = pthread_create(&(res_thread->t), NULL,
153 wrapper_start_routine, res_thread)))
154 THROW1(system_error, errcode,
155 "pthread_create failed: %s", strerror(errcode));
160 const char *xbt_os_thread_name(xbt_os_thread_t t)
165 const char *xbt_os_thread_self_name(void)
167 xbt_os_thread_t self = xbt_os_thread_self();
168 return self ? self->name : "main";
171 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
176 if ((errcode = pthread_join(thread->t, thread_return)))
177 THROW1(system_error, errcode, "pthread_join failed: %s",
179 if (thread->exception)
180 free(thread->exception);
185 if (thread == main_thread) /* just killed main thread */
191 void xbt_os_thread_exit(int *retval)
193 pthread_exit(retval);
196 xbt_os_thread_t xbt_os_thread_self(void)
200 if (!thread_mod_inited)
203 res = pthread_getspecific(xbt_self_thread_key);
211 void xbt_os_thread_yield(void)
216 void xbt_os_thread_cancel(xbt_os_thread_t t)
218 pthread_cancel(t->t);
221 /****** mutex related functions ******/
222 typedef struct xbt_os_mutex_ {
223 /* KEEP IT IN SYNC WITH xbt_thread.c */
230 xbt_os_mutex_t xbt_os_mutex_init(void)
232 xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
235 if ((errcode = pthread_mutex_init(&(res->m), NULL)))
236 THROW1(system_error, errcode, "pthread_mutex_init() failed: %s",
242 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
246 if ((errcode = pthread_mutex_lock(&(mutex->m))))
247 THROW2(system_error, errcode, "pthread_mutex_lock(%p) failed: %s",
248 mutex, strerror(errcode));
252 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
257 xbt_os_mutex_acquire(mutex);
259 } else if (delay == 0) {
260 errcode = pthread_mutex_trylock(&(mutex->m));
266 THROW1(timeout_error, 0, "mutex %p not ready", mutex);
268 THROW2(system_error, errcode, "xbt_mutex_timedacquire(%p) failed: %s",
269 mutex, strerror(errcode));
275 #ifdef HAVE_MUTEX_TIMEDLOCK
276 struct timespec ts_end;
277 double end = delay + xbt_os_time();
279 ts_end.tv_sec = (time_t) floor(end);
280 ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
281 DEBUG2("pthread_mutex_timedlock(%p,%p)", &(mutex->m), &ts_end);
283 errcode = pthread_mutex_timedlock(&(mutex->m), &ts_end);
285 #else /* Well, let's reimplement it since those lazy libc dudes didn't */
286 double start = xbt_os_time();
288 errcode = pthread_mutex_trylock(&(mutex->m));
289 if (errcode == EBUSY)
290 xbt_os_thread_yield();
291 } while (errcode == EBUSY && xbt_os_time() - start < delay);
293 if (errcode == EBUSY)
296 #endif /* HAVE_MUTEX_TIMEDLOCK */
303 THROW2(timeout_error, delay,
304 "mutex %p wasn't signaled before timeout (%f)", mutex, delay);
307 THROW3(system_error, errcode,
308 "pthread_mutex_timedlock(%p,%f) failed: %s", mutex, delay,
314 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
318 if ((errcode = pthread_mutex_unlock(&(mutex->m))))
319 THROW2(system_error, errcode, "pthread_mutex_unlock(%p) failed: %s",
320 mutex, strerror(errcode));
323 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
330 if ((errcode = pthread_mutex_destroy(&(mutex->m))))
331 THROW2(system_error, errcode, "pthread_mutex_destroy(%p) failed: %s",
332 mutex, strerror(errcode));
336 /***** condition related functions *****/
337 typedef struct xbt_os_cond_ {
338 /* KEEP IT IN SYNC WITH xbt_thread.c */
342 xbt_os_cond_t xbt_os_cond_init(void)
344 xbt_os_cond_t res = xbt_new(s_xbt_os_cond_t, 1);
346 if ((errcode = pthread_cond_init(&(res->c), NULL)))
347 THROW1(system_error, errcode, "pthread_cond_init() failed: %s",
353 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
356 if ((errcode = pthread_cond_wait(&(cond->c), &(mutex->m))))
357 THROW3(system_error, errcode, "pthread_cond_wait(%p,%p) failed: %s",
358 cond, mutex, strerror(errcode));
362 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
366 struct timespec ts_end;
367 double end = delay + xbt_os_time();
370 xbt_os_cond_wait(cond, mutex);
372 ts_end.tv_sec = (time_t) floor(end);
373 ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
374 DEBUG3("pthread_cond_timedwait(%p,%p,%p)", &(cond->c), &(mutex->m),
377 pthread_cond_timedwait(&(cond->c), &(mutex->m), &ts_end))) {
381 THROW3(timeout_error, errcode,
382 "condition %p (mutex %p) wasn't signaled before timeout (%f)",
385 THROW4(system_error, errcode,
386 "pthread_cond_timedwait(%p,%p,%f) failed: %s", cond, mutex,
387 delay, strerror(errcode));
392 void xbt_os_cond_signal(xbt_os_cond_t cond)
395 if ((errcode = pthread_cond_signal(&(cond->c))))
396 THROW2(system_error, errcode, "pthread_cond_signal(%p) failed: %s",
397 cond, strerror(errcode));
400 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
403 if ((errcode = pthread_cond_broadcast(&(cond->c))))
404 THROW2(system_error, errcode, "pthread_cond_broadcast(%p) failed: %s",
405 cond, strerror(errcode));
408 void xbt_os_cond_destroy(xbt_os_cond_t cond)
415 if ((errcode = pthread_cond_destroy(&(cond->c))))
416 THROW2(system_error, errcode, "pthread_cond_destroy(%p) failed: %s",
417 cond, strerror(errcode));
421 void *xbt_os_thread_getparam(void)
423 xbt_os_thread_t t = xbt_os_thread_self();
424 return t ? t->param : NULL;
427 typedef struct xbt_os_sem_ {
428 #ifndef HAVE_SEM_INIT
436 #define SEM_FAILED (-1)
439 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
441 xbt_os_sem_t res = xbt_new(s_xbt_os_sem_t, 1);
443 /* On some systems (MAC OS X), only the stub of sem_init is to be found.
444 * Any attempt to use it leads to ENOSYS (function not implemented).
445 * If such a prehistoric system is detected, do the job with sem_open instead
448 if (sem_init(&(res->s), 0, value) != 0)
449 THROW1(system_error, errno, "sem_init() failed: %s", strerror(errno));
452 #else /* damn, no sem_init(). Reimplement it */
454 xbt_os_mutex_acquire(next_sem_ID_lock);
455 res->name = bprintf("/%d.%d", (*xbt_getpid) (), ++next_sem_ID);
456 xbt_os_mutex_release(next_sem_ID_lock);
458 res->ps = sem_open(res->name, O_CREAT, 0644, value);
459 if ((res->ps == (sem_t *) SEM_FAILED) && (errno == ENAMETOOLONG)) {
460 /* Old darwins only allow 13 chars. Did you create *that* amount of semaphores? */
461 res->name[13] = '\0';
462 res->ps = sem_open(res->name, O_CREAT, 0644, 1);
464 if ((res->ps == (sem_t *) SEM_FAILED))
465 THROW1(system_error, errno, "sem_open() failed: %s", strerror(errno));
467 /* Remove the name from the semaphore namespace: we never join on it */
468 if (sem_unlink(res->name) < 0)
469 THROW1(system_error, errno, "sem_unlink() failed: %s", strerror(errno));
476 void xbt_os_sem_acquire(xbt_os_sem_t sem)
479 THROW0(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
480 if (sem_wait(sem->ps) < 0)
481 THROW1(system_error, errno, "sem_wait() failed: %s", strerror(errno));
484 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double delay)
489 THROW0(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
492 xbt_os_sem_acquire(sem);
493 } else if (delay == 0) {
494 errcode = sem_trywait(sem->ps);
500 THROW1(timeout_error, 0, "semaphore %p not ready", sem);
502 THROW2(system_error, errcode, "xbt_os_sem_timedacquire(%p) failed: %s",
503 sem, strerror(errcode));
508 struct timespec ts_end;
509 double end = delay + xbt_os_time();
511 ts_end.tv_sec = (time_t) floor(end);
512 ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
513 DEBUG2("sem_timedwait(%p,%p)", sem->ps, &ts_end);
514 errcode = sem_timedwait(sem->s, &ts_end);
516 #else /* Okay, reimplement this function then */
517 double start = xbt_os_time();
519 errcode = sem_trywait(sem->ps);
520 if (errcode == EBUSY)
521 xbt_os_thread_yield();
522 } while (errcode == EBUSY && xbt_os_time() - start < delay);
524 if (errcode == EBUSY)
533 THROW2(timeout_error, delay,
534 "semaphore %p wasn't signaled before timeout (%f)", sem, delay);
537 THROW3(system_error, errcode, "sem_timedwait(%p,%f) failed: %s", sem,
538 delay, strerror(errcode));
543 void xbt_os_sem_release(xbt_os_sem_t sem)
546 THROW0(arg_error, EINVAL, "Cannot release of the NULL semaphore");
548 if (sem_post(sem->ps) < 0)
549 THROW1(system_error, errno, "sem_post() failed: %s", strerror(errno));
552 void xbt_os_sem_destroy(xbt_os_sem_t sem)
555 THROW0(arg_error, EINVAL, "Cannot destroy the NULL sempahore");
558 if (sem_destroy(sem->ps))
560 THROW1(system_error, errno, "sem_destroy() failed: %s",
563 if (sem_close(sem->ps) < 0)
564 THROW1(system_error, errno, "sem_close() failed: %s", strerror(errno));
571 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
574 THROW0(arg_error, EINVAL, "Cannot get the value of the NULL semaphore");
576 if (sem_getvalue(&(sem->s), svalue) < 0)
577 THROW1(system_error, errno, "sem_getvalue() failed: %s", strerror(errno));
580 /* ********************************* WINDOWS IMPLEMENTATION ************************************ */
586 typedef struct xbt_os_thread_ {
588 HANDLE handle; /* the win thread handle */
589 unsigned long id; /* the win thread id */
590 pvoid_f_pvoid_t start_routine;
594 /* so we can specify the size of the stack of the threads */
595 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
596 #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
599 /* the default size of the stack of the threads (in bytes)*/
600 #define XBT_DEFAULT_THREAD_STACK_SIZE 4096
602 /* key to the TLS containing the xbt_os_thread_t structure */
603 static unsigned long xbt_self_thread_key;
605 void xbt_os_thread_mod_init(void)
607 xbt_self_thread_key = TlsAlloc();
610 void xbt_os_thread_mod_exit(void)
613 if (!TlsFree(xbt_self_thread_key))
614 THROW0(system_error, (int) GetLastError(),
615 "TlsFree() failed to cleanup the thread submodule");
618 static DWORD WINAPI wrapper_start_routine(void *s)
620 xbt_os_thread_t t = (xbt_os_thread_t) s;
623 if (!TlsSetValue(xbt_self_thread_key, t))
624 THROW0(system_error, (int) GetLastError(),
625 "TlsSetValue of data describing the created thread failed");
627 rv = (DWORD *) ((t->start_routine) (t->param));
634 xbt_os_thread_t xbt_os_thread_create(const char *name,
635 pvoid_f_pvoid_t start_routine,
639 xbt_os_thread_t t = xbt_new(s_xbt_os_thread_t, 1);
641 t->name = xbt_strdup(name);
642 t->start_routine = start_routine;
645 t->handle = CreateThread(NULL, XBT_DEFAULT_THREAD_STACK_SIZE,
646 (LPTHREAD_START_ROUTINE) wrapper_start_routine,
647 t, STACK_SIZE_PARAM_IS_A_RESERVATION, &(t->id));
651 THROW0(system_error, (int) GetLastError(), "CreateThread failed");
657 const char *xbt_os_thread_name(xbt_os_thread_t t)
662 const char *xbt_os_thread_self_name(void)
664 xbt_os_thread_t t = xbt_os_thread_self();
665 return t ? t->name : "main";
668 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
671 if (WAIT_OBJECT_0 != WaitForSingleObject(thread->handle, INFINITE))
672 THROW0(system_error, (int) GetLastError(), "WaitForSingleObject failed");
676 if (!GetExitCodeThread(thread->handle, (DWORD *) (*thread_return)))
677 THROW0(system_error, (int) GetLastError(), "GetExitCodeThread failed");
680 CloseHandle(thread->handle);
688 void xbt_os_thread_exit(int *retval)
696 xbt_os_thread_t xbt_os_thread_self(void)
698 return TlsGetValue(xbt_self_thread_key);
701 void *xbt_os_thread_getparam(void)
703 xbt_os_thread_t t = xbt_os_thread_self();
708 void xbt_os_thread_yield(void)
713 void xbt_os_thread_cancel(xbt_os_thread_t t)
715 if (!TerminateThread(t->handle, 0))
716 THROW0(system_error, (int) GetLastError(), "TerminateThread failed");
719 /****** mutex related functions ******/
720 typedef struct xbt_os_mutex_ {
721 /* KEEP IT IN SYNC WITH xbt_thread.c */
722 CRITICAL_SECTION lock;
725 xbt_os_mutex_t xbt_os_mutex_init(void)
727 xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
729 /* initialize the critical section object */
730 InitializeCriticalSection(&(res->lock));
735 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
737 EnterCriticalSection(&mutex->lock);
740 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
745 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
748 LeaveCriticalSection(&mutex->lock);
752 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
758 DeleteCriticalSection(&mutex->lock);
762 /***** condition related functions *****/
763 enum { /* KEEP IT IN SYNC WITH xbt_thread.c */
769 typedef struct xbt_os_cond_ {
770 /* KEEP IT IN SYNC WITH xbt_thread.c */
771 HANDLE events[MAX_EVENTS];
773 unsigned int waiters_count; /* the number of waiters */
774 CRITICAL_SECTION waiters_count_lock; /* protect access to waiters_count */
777 xbt_os_cond_t xbt_os_cond_init(void)
780 xbt_os_cond_t res = xbt_new0(s_xbt_os_cond_t, 1);
782 memset(&res->waiters_count_lock, 0, sizeof(CRITICAL_SECTION));
784 /* initialize the critical section object */
785 InitializeCriticalSection(&res->waiters_count_lock);
787 res->waiters_count = 0;
789 /* Create an auto-reset event */
790 res->events[SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL);
792 if (!res->events[SIGNAL]) {
793 DeleteCriticalSection(&res->waiters_count_lock);
795 THROW0(system_error, 0, "CreateEvent failed for the signals");
798 /* Create a manual-reset event. */
799 res->events[BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
801 if (!res->events[BROADCAST]) {
803 DeleteCriticalSection(&res->waiters_count_lock);
804 CloseHandle(res->events[SIGNAL]);
806 THROW0(system_error, 0, "CreateEvent failed for the broadcasts");
812 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
815 unsigned long wait_result;
818 /* lock the threads counter and increment it */
819 EnterCriticalSection(&cond->waiters_count_lock);
820 cond->waiters_count++;
821 LeaveCriticalSection(&cond->waiters_count_lock);
823 /* unlock the mutex associate with the condition */
824 LeaveCriticalSection(&mutex->lock);
826 /* wait for a signal (broadcast or no) */
827 wait_result = WaitForMultipleObjects(2, cond->events, FALSE, INFINITE);
829 if (wait_result == WAIT_FAILED)
830 THROW0(system_error, 0,
831 "WaitForMultipleObjects failed, so we cannot wait on the condition");
833 /* we have a signal lock the condition */
834 EnterCriticalSection(&cond->waiters_count_lock);
835 cond->waiters_count--;
837 /* it's the last waiter or it's a broadcast ? */
838 is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
839 && (cond->waiters_count == 0));
841 LeaveCriticalSection(&cond->waiters_count_lock);
843 /* yes it's the last waiter or it's a broadcast
844 * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
848 if (!ResetEvent(cond->events[BROADCAST]))
849 THROW0(system_error, 0, "ResetEvent failed");
851 /* relock the mutex associated with the condition in accordance with the posix thread specification */
852 EnterCriticalSection(&mutex->lock);
855 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
859 unsigned long wait_result = WAIT_TIMEOUT;
861 unsigned long end = (unsigned long) (delay * 1000);
865 xbt_os_cond_wait(cond, mutex);
867 DEBUG3("xbt_cond_timedwait(%p,%p,%lu)", &(cond->events), &(mutex->lock),
870 /* lock the threads counter and increment it */
871 EnterCriticalSection(&cond->waiters_count_lock);
872 cond->waiters_count++;
873 LeaveCriticalSection(&cond->waiters_count_lock);
875 /* unlock the mutex associate with the condition */
876 LeaveCriticalSection(&mutex->lock);
877 /* wait for a signal (broadcast or no) */
879 wait_result = WaitForMultipleObjects(2, cond->events, FALSE, end);
881 switch (wait_result) {
883 THROW3(timeout_error, GetLastError(),
884 "condition %p (mutex %p) wasn't signaled before timeout (%f)",
887 THROW0(system_error, GetLastError(),
888 "WaitForMultipleObjects failed, so we cannot wait on the condition");
891 /* we have a signal lock the condition */
892 EnterCriticalSection(&cond->waiters_count_lock);
893 cond->waiters_count--;
895 /* it's the last waiter or it's a broadcast ? */
896 is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
897 && (cond->waiters_count == 0));
899 LeaveCriticalSection(&cond->waiters_count_lock);
901 /* yes it's the last waiter or it's a broadcast
902 * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
906 if (!ResetEvent(cond->events[BROADCAST]))
907 THROW0(system_error, 0, "ResetEvent failed");
909 /* relock the mutex associated with the condition in accordance with the posix thread specification */
910 EnterCriticalSection(&mutex->lock);
912 /*THROW_UNIMPLEMENTED; */
915 void xbt_os_cond_signal(xbt_os_cond_t cond)
919 EnterCriticalSection(&cond->waiters_count_lock);
920 have_waiters = cond->waiters_count > 0;
921 LeaveCriticalSection(&cond->waiters_count_lock);
924 if (!SetEvent(cond->events[SIGNAL]))
925 THROW0(system_error, 0, "SetEvent failed");
927 xbt_os_thread_yield();
930 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
934 EnterCriticalSection(&cond->waiters_count_lock);
935 have_waiters = cond->waiters_count > 0;
936 LeaveCriticalSection(&cond->waiters_count_lock);
939 SetEvent(cond->events[BROADCAST]);
942 void xbt_os_cond_destroy(xbt_os_cond_t cond)
949 if (!CloseHandle(cond->events[SIGNAL]))
952 if (!CloseHandle(cond->events[BROADCAST]))
955 DeleteCriticalSection(&cond->waiters_count_lock);
960 THROW0(system_error, 0, "Error while destroying the condition");
963 typedef struct xbt_os_sem_ {
966 CRITICAL_SECTION value_lock; /* protect access to value of the semaphore */
970 # define INT_MAX 32767 /* let's be safe by underestimating this value: this is for 16bits only */
973 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
978 THROW1(arg_error, value,
979 "Semaphore initial value too big: %ud cannot be stored as a signed int",
982 res = (xbt_os_sem_t) xbt_new0(s_xbt_os_sem_t, 1);
984 if (!(res->h = CreateSemaphore(NULL, value, (long) INT_MAX, NULL))) {
985 THROW1(system_error, GetLastError(), "CreateSemaphore() failed: %s",
986 strerror(GetLastError()));
992 InitializeCriticalSection(&(res->value_lock));
997 void xbt_os_sem_acquire(xbt_os_sem_t sem)
1000 THROW0(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1003 if (WAIT_OBJECT_0 != WaitForSingleObject(sem->h, INFINITE))
1004 THROW1(system_error, GetLastError(), "WaitForSingleObject() failed: %s",
1005 strerror(GetLastError()));
1006 EnterCriticalSection(&(sem->value_lock));
1008 LeaveCriticalSection(&(sem->value_lock));
1011 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double timeout)
1015 double end = timeout + xbt_os_time();
1018 THROW0(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1021 xbt_os_sem_acquire(sem);
1022 } else { /* timeout can be zero <-> try acquire ) */
1025 seconds = (long) floor(end);
1026 milliseconds = (long) ((end - seconds) * 1000);
1027 milliseconds += (seconds * 1000);
1029 switch (WaitForSingleObject(sem->h, milliseconds)) {
1031 EnterCriticalSection(&(sem->value_lock));
1033 LeaveCriticalSection(&(sem->value_lock));
1037 THROW2(timeout_error, GetLastError(),
1038 "semaphore %p wasn't signaled before timeout (%f)", sem,
1043 THROW3(system_error, GetLastError(),
1044 "WaitForSingleObject(%p,%f) failed: %s", sem, timeout,
1045 strerror(GetLastError()));
1050 void xbt_os_sem_release(xbt_os_sem_t sem)
1053 THROW0(arg_error, EINVAL, "Cannot release the NULL semaphore");
1055 if (!ReleaseSemaphore(sem->h, 1, NULL))
1056 THROW1(system_error, GetLastError(), "ReleaseSemaphore() failed: %s",
1057 strerror(GetLastError()));
1058 EnterCriticalSection(&(sem->value_lock));
1060 LeaveCriticalSection(&(sem->value_lock));
1063 void xbt_os_sem_destroy(xbt_os_sem_t sem)
1066 THROW0(arg_error, EINVAL, "Cannot destroy the NULL semaphore");
1068 if (!CloseHandle(sem->h))
1069 THROW1(system_error, GetLastError(), "CloseHandle() failed: %s",
1070 strerror(GetLastError()));
1072 DeleteCriticalSection(&(sem->value_lock));
1078 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
1081 THROW0(arg_error, EINVAL, "Cannot get the value of the NULL semaphore");
1083 EnterCriticalSection(&(sem->value_lock));
1084 *svalue = sem->value;
1085 LeaveCriticalSection(&(sem->value_lock));