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 "internal_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 /* attribute structure to handle pthread stack size changing */
57 //FIXME: find where to put this
58 static pthread_attr_t attr;
59 static int thread_attr_inited = 0;
61 /* frees the xbt_os_thread_t corresponding to the current thread */
62 static void xbt_os_thread_free_thread_data(xbt_os_thread_t thread)
64 if (thread == main_thread) /* just killed main thread */
67 free(thread->running_ctx);
72 /* callback: context fetching */
73 static xbt_running_ctx_t *_os_thread_get_running_ctx(void)
75 return xbt_os_thread_self()->running_ctx;
78 /* callback: termination */
79 static void _os_thread_ex_terminate(xbt_ex_t * e)
83 /* FIXME: there should be a configuration variable to choose to kill everyone or only this one */
86 void xbt_os_thread_mod_preinit(void)
90 if (thread_mod_inited)
93 if ((errcode = pthread_key_create(&xbt_self_thread_key, NULL)))
94 THROWF(system_error, errcode,
95 "pthread_key_create failed for xbt_self_thread_key");
97 main_thread = xbt_new(s_xbt_os_thread_t, 1);
98 main_thread->name = (char *) "main";
99 main_thread->start_routine = NULL;
100 main_thread->param = NULL;
101 main_thread->running_ctx = xbt_new(xbt_running_ctx_t, 1);
102 XBT_RUNNING_CTX_INITIALIZE(main_thread->running_ctx);
104 if ((errcode = pthread_setspecific(xbt_self_thread_key, main_thread)))
105 THROWF(system_error, errcode,
106 "pthread_setspecific failed for xbt_self_thread_key");
109 __xbt_running_ctx_fetch = _os_thread_get_running_ctx;
110 __xbt_ex_terminate = _os_thread_ex_terminate;
112 thread_mod_inited = 1;
114 #ifndef HAVE_SEM_INIT
115 next_sem_ID_lock = xbt_os_mutex_init();
120 void xbt_os_thread_mod_postexit(void)
122 /* FIXME: don't try to free our key on shutdown.
123 Valgrind detects no leak if we don't, and whine if we try to */
126 // if ((errcode=pthread_key_delete(xbt_self_thread_key)))
127 // THROWF(system_error,errcode,"pthread_key_delete failed for xbt_self_thread_key");
128 free(main_thread->running_ctx);
131 thread_mod_inited = 0;
132 #ifndef HAVE_SEM_INIT
133 xbt_os_mutex_destroy(next_sem_ID_lock);
136 /* Restore the default exception setup */
137 __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
138 __xbt_ex_terminate = &__xbt_ex_terminate_default;
141 /* this function is critical to tesh+mmalloc, don't mess with it */
142 int xbt_os_thread_atfork(void (*prepare)(void),
143 void (*parent)(void), void (*child)(void))
146 THROW_UNIMPLEMENTED; //pthread_atfork is not implemented in pthread.h on windows
148 return pthread_atfork(prepare, parent, child);
152 static void *wrapper_start_routine(void *s)
154 xbt_os_thread_t t = s;
157 if ((errcode = pthread_setspecific(xbt_self_thread_key, t)))
158 THROWF(system_error, errcode,
159 "pthread_setspecific failed for xbt_self_thread_key");
161 void *res = t->start_routine(t->param);
163 xbt_os_thread_free_thread_data(t);
168 xbt_os_thread_t xbt_os_thread_create(const char *name,
169 pvoid_f_pvoid_t start_routine,
175 xbt_os_thread_t res_thread = xbt_new(s_xbt_os_thread_t, 1);
176 res_thread->detached = 0;
177 res_thread->name = xbt_strdup(name);
178 res_thread->start_routine = start_routine;
179 res_thread->param = param;
180 res_thread->running_ctx = xbt_new(xbt_running_ctx_t, 1);
181 XBT_RUNNING_CTX_INITIALIZE(res_thread->running_ctx);
182 res_thread->extra_data = extra_data;
184 if ((errcode = pthread_create(&(res_thread->t), thread_attr_inited!=0? &attr: NULL,
185 wrapper_start_routine, res_thread)))
186 THROWF(system_error, errcode,
187 "pthread_create failed: %s", strerror(errcode));
195 void xbt_os_thread_setstacksize(int stack_size)
198 if(stack_size<0)xbt_die("stack size is negative, maybe it exceeds MAX_INT?\n");
199 pthread_attr_init(&attr);
200 pthread_attr_getstacksize (&attr, &def);
201 int res = pthread_attr_setstacksize (&attr, stack_size);
203 if(res==EINVAL)XBT_WARN("Thread stack size is either < PTHREAD_STACK_MIN, > the max limit of the system, or perhaps not a multiple of PTHREAD_STACK_MIN - The parameter was ignored");
204 else XBT_WARN("unknown error in pthread stacksize setting");
206 pthread_attr_setstacksize (&attr, def);
208 thread_attr_inited=1;
211 const char *xbt_os_thread_name(xbt_os_thread_t t)
216 const char *xbt_os_thread_self_name(void)
218 xbt_os_thread_t me = xbt_os_thread_self();
219 return me ? me->name : "main";
222 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
227 if ((errcode = pthread_join(thread->t, thread_return)))
228 THROWF(system_error, errcode, "pthread_join failed: %s",
230 xbt_os_thread_free_thread_data(thread);
233 void xbt_os_thread_exit(int *retval)
235 pthread_exit(retval);
238 xbt_os_thread_t xbt_os_thread_self(void)
242 if (!thread_mod_inited)
245 res = pthread_getspecific(xbt_self_thread_key);
250 void xbt_os_thread_key_create(xbt_os_thread_key_t* key) {
253 if ((errcode = pthread_key_create(key, NULL)))
254 THROWF(system_error, errcode, "pthread_key_create failed");
257 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value) {
260 if ((errcode = pthread_setspecific(key, value)))
261 THROWF(system_error, errcode, "pthread_setspecific failed");
264 void* xbt_os_thread_get_specific(xbt_os_thread_key_t key) {
265 return pthread_getspecific(key);
268 void xbt_os_thread_detach(xbt_os_thread_t thread)
270 thread->detached = 1;
271 pthread_detach(thread->t);
275 void xbt_os_thread_yield(void)
280 void xbt_os_thread_cancel(xbt_os_thread_t t)
282 pthread_cancel(t->t);
285 /****** mutex related functions ******/
286 typedef struct xbt_os_mutex_ {
287 /* KEEP IT IN SYNC WITH xbt_thread.c */
294 xbt_os_mutex_t xbt_os_mutex_init(void)
296 xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
299 if ((errcode = pthread_mutex_init(&(res->m), NULL)))
300 THROWF(system_error, errcode, "pthread_mutex_init() failed: %s",
306 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
310 if ((errcode = pthread_mutex_lock(&(mutex->m))))
311 THROWF(system_error, errcode, "pthread_mutex_lock(%p) failed: %s",
312 mutex, strerror(errcode));
316 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
321 xbt_os_mutex_acquire(mutex);
323 } else if (delay == 0) {
324 errcode = pthread_mutex_trylock(&(mutex->m));
330 THROWF(timeout_error, 0, "mutex %p not ready", mutex);
332 THROWF(system_error, errcode,
333 "xbt_os_mutex_timedacquire(%p) failed: %s", mutex,
340 #ifdef HAVE_MUTEX_TIMEDLOCK
341 struct timespec ts_end;
342 double end = delay + xbt_os_time();
344 ts_end.tv_sec = (time_t) floor(end);
345 ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
346 XBT_DEBUG("pthread_mutex_timedlock(%p,%p)", &(mutex->m), &ts_end);
348 errcode = pthread_mutex_timedlock(&(mutex->m), &ts_end);
350 #else /* Well, let's reimplement it since those lazy libc dudes didn't */
351 double start = xbt_os_time();
353 errcode = pthread_mutex_trylock(&(mutex->m));
354 if (errcode == EBUSY)
355 xbt_os_thread_yield();
356 } while (errcode == EBUSY && xbt_os_time() - start < delay);
358 if (errcode == EBUSY)
361 #endif /* HAVE_MUTEX_TIMEDLOCK */
368 THROWF(timeout_error, delay,
369 "mutex %p wasn't signaled before timeout (%f)", mutex, delay);
372 THROWF(system_error, errcode,
373 "pthread_mutex_timedlock(%p,%f) failed: %s", mutex, delay,
379 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
383 if ((errcode = pthread_mutex_unlock(&(mutex->m))))
384 THROWF(system_error, errcode, "pthread_mutex_unlock(%p) failed: %s",
385 mutex, strerror(errcode));
388 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
395 if ((errcode = pthread_mutex_destroy(&(mutex->m))))
396 THROWF(system_error, errcode, "pthread_mutex_destroy(%p) failed: %s",
397 mutex, strerror(errcode));
401 /***** condition related functions *****/
402 typedef struct xbt_os_cond_ {
403 /* KEEP IT IN SYNC WITH xbt_thread.c */
407 xbt_os_cond_t xbt_os_cond_init(void)
409 xbt_os_cond_t res = xbt_new(s_xbt_os_cond_t, 1);
411 if ((errcode = pthread_cond_init(&(res->c), NULL)))
412 THROWF(system_error, errcode, "pthread_cond_init() failed: %s",
418 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
421 if ((errcode = pthread_cond_wait(&(cond->c), &(mutex->m))))
422 THROWF(system_error, errcode, "pthread_cond_wait(%p,%p) failed: %s",
423 cond, mutex, strerror(errcode));
427 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
431 struct timespec ts_end;
432 double end = delay + xbt_os_time();
435 xbt_os_cond_wait(cond, mutex);
437 ts_end.tv_sec = (time_t) floor(end);
438 ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
439 XBT_DEBUG("pthread_cond_timedwait(%p,%p,%p)", &(cond->c), &(mutex->m),
442 pthread_cond_timedwait(&(cond->c), &(mutex->m), &ts_end))) {
446 THROWF(timeout_error, errcode,
447 "condition %p (mutex %p) wasn't signaled before timeout (%f)",
450 THROWF(system_error, errcode,
451 "pthread_cond_timedwait(%p,%p,%f) failed: %s", cond, mutex,
452 delay, strerror(errcode));
457 void xbt_os_cond_signal(xbt_os_cond_t cond)
460 if ((errcode = pthread_cond_signal(&(cond->c))))
461 THROWF(system_error, errcode, "pthread_cond_signal(%p) failed: %s",
462 cond, strerror(errcode));
465 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
468 if ((errcode = pthread_cond_broadcast(&(cond->c))))
469 THROWF(system_error, errcode, "pthread_cond_broadcast(%p) failed: %s",
470 cond, strerror(errcode));
473 void xbt_os_cond_destroy(xbt_os_cond_t cond)
480 if ((errcode = pthread_cond_destroy(&(cond->c))))
481 THROWF(system_error, errcode, "pthread_cond_destroy(%p) failed: %s",
482 cond, strerror(errcode));
486 void *xbt_os_thread_getparam(void)
488 xbt_os_thread_t t = xbt_os_thread_self();
489 return t ? t->param : NULL;
492 typedef struct xbt_os_sem_ {
493 #ifndef HAVE_SEM_INIT
501 #define SEM_FAILED (-1)
504 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
506 xbt_os_sem_t res = xbt_new(s_xbt_os_sem_t, 1);
508 /* On some systems (MAC OS X), only the stub of sem_init is to be found.
509 * Any attempt to use it leads to ENOSYS (function not implemented).
510 * If such a prehistoric system is detected, do the job with sem_open instead
513 if (sem_init(&(res->s), 0, value) != 0)
514 THROWF(system_error, errno, "sem_init() failed: %s", strerror(errno));
517 #else /* damn, no sem_init(). Reimplement it */
519 xbt_os_mutex_acquire(next_sem_ID_lock);
520 res->name = bprintf("/%d", ++next_sem_ID);
521 xbt_os_mutex_release(next_sem_ID_lock);
523 res->ps = sem_open(res->name, O_CREAT, 0644, value);
524 if ((res->ps == (sem_t *) SEM_FAILED) && (errno == ENAMETOOLONG)) {
525 /* Old darwins only allow 13 chars. Did you create *that* amount of semaphores? */
526 res->name[13] = '\0';
527 res->ps = sem_open(res->name, O_CREAT, 0644, value);
529 if ((res->ps == (sem_t *) SEM_FAILED))
530 THROWF(system_error, errno, "sem_open() failed: %s", strerror(errno));
532 /* Remove the name from the semaphore namespace: we never join on it */
533 if (sem_unlink(res->name) < 0)
534 THROWF(system_error, errno, "sem_unlink() failed: %s",
542 void xbt_os_sem_acquire(xbt_os_sem_t sem)
545 THROWF(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
546 if (sem_wait(sem->ps) < 0)
547 THROWF(system_error, errno, "sem_wait() failed: %s", strerror(errno));
550 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double delay)
555 THROWF(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
558 xbt_os_sem_acquire(sem);
559 } else if (delay == 0) {
560 errcode = sem_trywait(sem->ps);
566 THROWF(timeout_error, 0, "semaphore %p not ready", sem);
568 THROWF(system_error, errcode,
569 "xbt_os_sem_timedacquire(%p) failed: %s", sem,
575 struct timespec ts_end;
576 double end = delay + xbt_os_time();
578 ts_end.tv_sec = (time_t) floor(end);
579 ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
580 XBT_DEBUG("sem_timedwait(%p,%p)", sem->ps, &ts_end);
581 errcode = sem_timedwait(sem->s, &ts_end);
583 #else /* Okay, reimplement this function then */
584 double start = xbt_os_time();
586 errcode = sem_trywait(sem->ps);
587 if (errcode == EBUSY)
588 xbt_os_thread_yield();
589 } while (errcode == EBUSY && xbt_os_time() - start < delay);
591 if (errcode == EBUSY)
600 THROWF(timeout_error, delay,
601 "semaphore %p wasn't signaled before timeout (%f)", sem,
605 THROWF(system_error, errcode, "sem_timedwait(%p,%f) failed: %s", sem,
606 delay, strerror(errcode));
611 void xbt_os_sem_release(xbt_os_sem_t sem)
614 THROWF(arg_error, EINVAL, "Cannot release of the NULL semaphore");
616 if (sem_post(sem->ps) < 0)
617 THROWF(system_error, errno, "sem_post() failed: %s", strerror(errno));
620 void xbt_os_sem_destroy(xbt_os_sem_t sem)
623 THROWF(arg_error, EINVAL, "Cannot destroy the NULL sempahore");
626 if (sem_destroy(sem->ps) < 0)
627 THROWF(system_error, errno, "sem_destroy() failed: %s",
630 if (sem_close(sem->ps) < 0)
631 THROWF(system_error, errno, "sem_close() failed: %s", strerror(errno));
638 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
641 THROWF(arg_error, EINVAL,
642 "Cannot get the value of the NULL semaphore");
644 if (sem_getvalue(&(sem->s), svalue) < 0)
645 THROWF(system_error, errno, "sem_getvalue() failed: %s",
649 /* ********************************* WINDOWS IMPLEMENTATION ************************************ */
651 #elif defined(_XBT_WIN32)
655 typedef struct xbt_os_thread_ {
657 HANDLE handle; /* the win thread handle */
658 unsigned long id; /* the win thread id */
659 pvoid_f_pvoid_t start_routine;
664 /* so we can specify the size of the stack of the threads */
665 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
666 #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
669 /* the default size of the stack of the threads (in bytes)*/
670 #define XBT_DEFAULT_THREAD_STACK_SIZE 4096
671 static int stack_size=0;
672 /* key to the TLS containing the xbt_os_thread_t structure */
673 static unsigned long xbt_self_thread_key;
675 void xbt_os_thread_mod_preinit(void)
677 xbt_self_thread_key = TlsAlloc();
680 void xbt_os_thread_mod_postexit(void)
683 if (!TlsFree(xbt_self_thread_key))
684 THROWF(system_error, (int) GetLastError(),
685 "TlsFree() failed to cleanup the thread submodule");
688 int xbt_os_thread_atfork(void (*prepare)(void),
689 void (*parent)(void), void (*child)(void))
694 static DWORD WINAPI wrapper_start_routine(void *s)
696 xbt_os_thread_t t = (xbt_os_thread_t) s;
699 if (!TlsSetValue(xbt_self_thread_key, t))
700 THROWF(system_error, (int) GetLastError(),
701 "TlsSetValue of data describing the created thread failed");
703 rv = (DWORD *) ((t->start_routine) (t->param));
710 xbt_os_thread_t xbt_os_thread_create(const char *name,
711 pvoid_f_pvoid_t start_routine,
716 xbt_os_thread_t t = xbt_new(s_xbt_os_thread_t, 1);
718 t->name = xbt_strdup(name);
719 t->start_routine = start_routine;
721 t->extra_data = extra_data;
722 t->handle = CreateThread(NULL, stack_size==0 ? XBT_DEFAULT_THREAD_STACK_SIZE : stack_size,
723 (LPTHREAD_START_ROUTINE) wrapper_start_routine,
724 t, STACK_SIZE_PARAM_IS_A_RESERVATION, &(t->id));
728 THROWF(system_error, (int) GetLastError(), "CreateThread failed");
734 void xbt_os_thread_setstacksize(int size)
739 const char *xbt_os_thread_name(xbt_os_thread_t t)
744 const char *xbt_os_thread_self_name(void)
746 xbt_os_thread_t t = xbt_os_thread_self();
747 return t ? t->name : "main";
750 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
753 if (WAIT_OBJECT_0 != WaitForSingleObject(thread->handle, INFINITE))
754 THROWF(system_error, (int) GetLastError(),
755 "WaitForSingleObject failed");
759 if (!GetExitCodeThread(thread->handle, (DWORD *) (*thread_return)))
760 THROWF(system_error, (int) GetLastError(),
761 "GetExitCodeThread failed");
764 CloseHandle(thread->handle);
771 void xbt_os_thread_exit(int *retval)
779 void xbt_os_thread_key_create(xbt_os_thread_key_t* key) {
784 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value) {
786 if (!TlsSetValue(key, value))
787 THROWF(system_error, (int) GetLastError(), "TlsSetValue() failed");
790 void* xbt_os_thread_get_specific(xbt_os_thread_key_t key) {
791 return TlsGetValue(key);
794 void xbt_os_thread_detach(xbt_os_thread_t thread)
800 xbt_os_thread_t xbt_os_thread_self(void)
802 return TlsGetValue(xbt_self_thread_key);
805 void *xbt_os_thread_getparam(void)
807 xbt_os_thread_t t = xbt_os_thread_self();
812 void xbt_os_thread_yield(void)
817 void xbt_os_thread_cancel(xbt_os_thread_t t)
819 if (!TerminateThread(t->handle, 0))
820 THROWF(system_error, (int) GetLastError(), "TerminateThread failed");
823 /****** mutex related functions ******/
824 typedef struct xbt_os_mutex_ {
825 /* KEEP IT IN SYNC WITH xbt_thread.c */
826 CRITICAL_SECTION lock;
829 xbt_os_mutex_t xbt_os_mutex_init(void)
831 xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
833 /* initialize the critical section object */
834 InitializeCriticalSection(&(res->lock));
839 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
841 EnterCriticalSection(&mutex->lock);
844 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
849 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
852 LeaveCriticalSection(&mutex->lock);
856 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
862 DeleteCriticalSection(&mutex->lock);
866 /***** condition related functions *****/
867 enum { /* KEEP IT IN SYNC WITH xbt_thread.c */
873 typedef struct xbt_os_cond_ {
874 /* KEEP IT IN SYNC WITH xbt_thread.c */
875 HANDLE events[MAX_EVENTS];
877 unsigned int waiters_count; /* the number of waiters */
878 CRITICAL_SECTION waiters_count_lock; /* protect access to waiters_count */
881 xbt_os_cond_t xbt_os_cond_init(void)
884 xbt_os_cond_t res = xbt_new0(s_xbt_os_cond_t, 1);
886 memset(&res->waiters_count_lock, 0, sizeof(CRITICAL_SECTION));
888 /* initialize the critical section object */
889 InitializeCriticalSection(&res->waiters_count_lock);
891 res->waiters_count = 0;
893 /* Create an auto-reset event */
894 res->events[SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL);
896 if (!res->events[SIGNAL]) {
897 DeleteCriticalSection(&res->waiters_count_lock);
899 THROWF(system_error, 0, "CreateEvent failed for the signals");
902 /* Create a manual-reset event. */
903 res->events[BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
905 if (!res->events[BROADCAST]) {
907 DeleteCriticalSection(&res->waiters_count_lock);
908 CloseHandle(res->events[SIGNAL]);
910 THROWF(system_error, 0, "CreateEvent failed for the broadcasts");
916 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
919 unsigned long wait_result;
922 /* lock the threads counter and increment it */
923 EnterCriticalSection(&cond->waiters_count_lock);
924 cond->waiters_count++;
925 LeaveCriticalSection(&cond->waiters_count_lock);
927 /* unlock the mutex associate with the condition */
928 LeaveCriticalSection(&mutex->lock);
930 /* wait for a signal (broadcast or no) */
931 wait_result = WaitForMultipleObjects(2, cond->events, FALSE, INFINITE);
933 if (wait_result == WAIT_FAILED)
934 THROWF(system_error, 0,
935 "WaitForMultipleObjects failed, so we cannot wait on the condition");
937 /* we have a signal lock the condition */
938 EnterCriticalSection(&cond->waiters_count_lock);
939 cond->waiters_count--;
941 /* it's the last waiter or it's a broadcast ? */
942 is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
943 && (cond->waiters_count == 0));
945 LeaveCriticalSection(&cond->waiters_count_lock);
947 /* yes it's the last waiter or it's a broadcast
948 * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
952 if (!ResetEvent(cond->events[BROADCAST]))
953 THROWF(system_error, 0, "ResetEvent failed");
955 /* relock the mutex associated with the condition in accordance with the posix thread specification */
956 EnterCriticalSection(&mutex->lock);
959 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
963 unsigned long wait_result = WAIT_TIMEOUT;
965 unsigned long end = (unsigned long) (delay * 1000);
969 xbt_os_cond_wait(cond, mutex);
971 XBT_DEBUG("xbt_cond_timedwait(%p,%p,%lu)", &(cond->events),
972 &(mutex->lock), end);
974 /* lock the threads counter and increment it */
975 EnterCriticalSection(&cond->waiters_count_lock);
976 cond->waiters_count++;
977 LeaveCriticalSection(&cond->waiters_count_lock);
979 /* unlock the mutex associate with the condition */
980 LeaveCriticalSection(&mutex->lock);
981 /* wait for a signal (broadcast or no) */
983 wait_result = WaitForMultipleObjects(2, cond->events, FALSE, end);
985 switch (wait_result) {
987 THROWF(timeout_error, GetLastError(),
988 "condition %p (mutex %p) wasn't signaled before timeout (%f)",
991 THROWF(system_error, GetLastError(),
992 "WaitForMultipleObjects failed, so we cannot wait on the condition");
995 /* we have a signal lock the condition */
996 EnterCriticalSection(&cond->waiters_count_lock);
997 cond->waiters_count--;
999 /* it's the last waiter or it's a broadcast ? */
1000 is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
1001 && (cond->waiters_count == 0));
1003 LeaveCriticalSection(&cond->waiters_count_lock);
1005 /* yes it's the last waiter or it's a broadcast
1006 * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
1010 if (!ResetEvent(cond->events[BROADCAST]))
1011 THROWF(system_error, 0, "ResetEvent failed");
1013 /* relock the mutex associated with the condition in accordance with the posix thread specification */
1014 EnterCriticalSection(&mutex->lock);
1016 /*THROW_UNIMPLEMENTED; */
1019 void xbt_os_cond_signal(xbt_os_cond_t cond)
1023 EnterCriticalSection(&cond->waiters_count_lock);
1024 have_waiters = cond->waiters_count > 0;
1025 LeaveCriticalSection(&cond->waiters_count_lock);
1028 if (!SetEvent(cond->events[SIGNAL]))
1029 THROWF(system_error, 0, "SetEvent failed");
1031 xbt_os_thread_yield();
1034 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
1038 EnterCriticalSection(&cond->waiters_count_lock);
1039 have_waiters = cond->waiters_count > 0;
1040 LeaveCriticalSection(&cond->waiters_count_lock);
1043 SetEvent(cond->events[BROADCAST]);
1046 void xbt_os_cond_destroy(xbt_os_cond_t cond)
1053 if (!CloseHandle(cond->events[SIGNAL]))
1056 if (!CloseHandle(cond->events[BROADCAST]))
1059 DeleteCriticalSection(&cond->waiters_count_lock);
1064 THROWF(system_error, 0, "Error while destroying the condition");
1067 typedef struct xbt_os_sem_ {
1070 CRITICAL_SECTION value_lock; /* protect access to value of the semaphore */
1074 # define INT_MAX 32767 /* let's be safe by underestimating this value: this is for 16bits only */
1077 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
1081 if (value > INT_MAX)
1082 THROWF(arg_error, value,
1083 "Semaphore initial value too big: %ud cannot be stored as a signed int",
1086 res = (xbt_os_sem_t) xbt_new0(s_xbt_os_sem_t, 1);
1088 if (!(res->h = CreateSemaphore(NULL, value, (long) INT_MAX, NULL))) {
1089 THROWF(system_error, GetLastError(), "CreateSemaphore() failed: %s",
1090 strerror(GetLastError()));
1096 InitializeCriticalSection(&(res->value_lock));
1101 void xbt_os_sem_acquire(xbt_os_sem_t sem)
1104 THROWF(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1107 if (WAIT_OBJECT_0 != WaitForSingleObject(sem->h, INFINITE))
1108 THROWF(system_error, GetLastError(),
1109 "WaitForSingleObject() failed: %s", strerror(GetLastError()));
1110 EnterCriticalSection(&(sem->value_lock));
1112 LeaveCriticalSection(&(sem->value_lock));
1115 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double timeout)
1119 double end = timeout + xbt_os_time();
1122 THROWF(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1125 xbt_os_sem_acquire(sem);
1126 } else { /* timeout can be zero <-> try acquire ) */
1129 seconds = (long) floor(end);
1130 milliseconds = (long) ((end - seconds) * 1000);
1131 milliseconds += (seconds * 1000);
1133 switch (WaitForSingleObject(sem->h, milliseconds)) {
1135 EnterCriticalSection(&(sem->value_lock));
1137 LeaveCriticalSection(&(sem->value_lock));
1141 THROWF(timeout_error, GetLastError(),
1142 "semaphore %p wasn't signaled before timeout (%f)", sem,
1147 THROWF(system_error, GetLastError(),
1148 "WaitForSingleObject(%p,%f) failed: %s", sem, timeout,
1149 strerror(GetLastError()));
1154 void xbt_os_sem_release(xbt_os_sem_t sem)
1157 THROWF(arg_error, EINVAL, "Cannot release the NULL semaphore");
1159 if (!ReleaseSemaphore(sem->h, 1, NULL))
1160 THROWF(system_error, GetLastError(), "ReleaseSemaphore() failed: %s",
1161 strerror(GetLastError()));
1162 EnterCriticalSection(&(sem->value_lock));
1164 LeaveCriticalSection(&(sem->value_lock));
1167 void xbt_os_sem_destroy(xbt_os_sem_t sem)
1170 THROWF(arg_error, EINVAL, "Cannot destroy the NULL semaphore");
1172 if (!CloseHandle(sem->h))
1173 THROWF(system_error, GetLastError(), "CloseHandle() failed: %s",
1174 strerror(GetLastError()));
1176 DeleteCriticalSection(&(sem->value_lock));
1182 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
1185 THROWF(arg_error, EINVAL,
1186 "Cannot get the value of the NULL semaphore");
1188 EnterCriticalSection(&(sem->value_lock));
1189 *svalue = sem->value;
1190 LeaveCriticalSection(&(sem->value_lock));
1197 /** @brief Returns the amount of cores on the current host */
1198 int xbt_os_get_numcores(void) {
1200 SYSTEM_INFO sysinfo;
1201 GetSystemInfo(&sysinfo);
1202 return sysinfo.dwNumberOfProcessors;
1208 nm[0] = CTL_HW; nm[1] = HW_AVAILCPU;
1209 sysctl(nm, 2, &count, &len, NULL, 0);
1213 sysctl(nm, 2, &count, &len, NULL, 0);
1214 if(count < 1) { count = 1; }
1218 return sysconf(_SC_NPROCESSORS_ONLN);
1223 /***** reentrant mutexes *****/
1224 typedef struct xbt_os_rmutex_ {
1225 xbt_os_mutex_t mutex;
1226 xbt_os_thread_t owner;
1228 } s_xbt_os_rmutex_t;
1230 void xbt_os_thread_set_extra_data(void *data)
1232 xbt_os_thread_self()->extra_data = data;
1235 void *xbt_os_thread_get_extra_data(void)
1237 return xbt_os_thread_self()->extra_data;
1240 xbt_os_rmutex_t xbt_os_rmutex_init(void)
1242 xbt_os_rmutex_t rmutex = xbt_new0(struct xbt_os_rmutex_, 1);
1243 rmutex->mutex = xbt_os_mutex_init();
1244 rmutex->owner = NULL;
1249 void xbt_os_rmutex_acquire(xbt_os_rmutex_t rmutex)
1251 xbt_os_thread_t self = xbt_os_thread_self();
1254 /* the thread module is not initialized yet */
1255 rmutex->owner = NULL;
1259 if (self != rmutex->owner) {
1260 xbt_os_mutex_acquire(rmutex->mutex);
1261 rmutex->owner = self;
1268 void xbt_os_rmutex_release(xbt_os_rmutex_t rmutex)
1270 if (rmutex->owner == NULL) {
1271 /* the thread module was not initialized */
1275 xbt_assert(rmutex->owner == xbt_os_thread_self());
1277 if (--rmutex->count == 0) {
1278 rmutex->owner = NULL;
1279 xbt_os_mutex_release(rmutex->mutex);
1283 void xbt_os_rmutex_destroy(xbt_os_rmutex_t rmutex)
1285 xbt_os_mutex_destroy(rmutex->mutex);