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-2014. 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 ************************************ */
27 #include <semaphore.h>
34 #ifdef HAVE_MUTEX_TIMEDLOCK
35 /* redefine the function header since we fail to get this from system headers on amd (at least) */
36 int pthread_mutex_timedlock(pthread_mutex_t * mutex,
37 const struct timespec *abs_timeout);
41 /* use named sempahore when sem_init() does not work */
43 static int next_sem_ID = 0;
44 static xbt_os_mutex_t next_sem_ID_lock;
47 typedef struct xbt_os_thread_ {
52 pvoid_f_pvoid_t start_routine;
53 xbt_running_ctx_t *running_ctx;
56 static xbt_os_thread_t main_thread = NULL;
58 /* thread-specific data containing the xbt_os_thread_t structure */
59 static pthread_key_t xbt_self_thread_key;
60 static int thread_mod_inited = 0;
62 /* defaults attribute for pthreads */
63 //FIXME: find where to put this
64 static pthread_attr_t thread_attr;
66 /* frees the xbt_os_thread_t corresponding to the current thread */
67 static void xbt_os_thread_free_thread_data(xbt_os_thread_t thread)
69 if (thread == main_thread) /* just killed main thread */
72 free(thread->running_ctx);
77 /* callback: context fetching */
78 static xbt_running_ctx_t *_os_thread_get_running_ctx(void)
80 return xbt_os_thread_self()->running_ctx;
83 /* callback: termination */
84 static void _os_thread_ex_terminate(xbt_ex_t * e)
88 /* FIXME: there should be a configuration variable to choose to kill everyone or only this one */
91 void xbt_os_thread_mod_preinit(void)
95 if (thread_mod_inited)
98 if ((errcode = pthread_key_create(&xbt_self_thread_key, NULL)))
99 THROWF(system_error, errcode,
100 "pthread_key_create failed for xbt_self_thread_key");
102 main_thread = xbt_new(s_xbt_os_thread_t, 1);
103 main_thread->name = (char *) "main";
104 main_thread->start_routine = NULL;
105 main_thread->param = NULL;
106 main_thread->running_ctx = xbt_new(xbt_running_ctx_t, 1);
107 XBT_RUNNING_CTX_INITIALIZE(main_thread->running_ctx);
109 if ((errcode = pthread_setspecific(xbt_self_thread_key, main_thread)))
110 THROWF(system_error, errcode,
111 "pthread_setspecific failed for xbt_self_thread_key");
113 __xbt_running_ctx_fetch = _os_thread_get_running_ctx;
114 __xbt_ex_terminate = _os_thread_ex_terminate;
116 pthread_attr_init(&thread_attr);
118 thread_mod_inited = 1;
120 #ifndef HAVE_SEM_INIT
121 next_sem_ID_lock = xbt_os_mutex_init();
126 void xbt_os_thread_mod_postexit(void)
128 /* FIXME: don't try to free our key on shutdown.
129 Valgrind detects no leak if we don't, and whine if we try to */
132 // if ((errcode=pthread_key_delete(xbt_self_thread_key)))
133 // THROWF(system_error,errcode,"pthread_key_delete failed for xbt_self_thread_key");
134 free(main_thread->running_ctx);
137 thread_mod_inited = 0;
138 #ifndef HAVE_SEM_INIT
139 xbt_os_mutex_destroy(next_sem_ID_lock);
142 /* Restore the default exception setup */
143 __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
144 __xbt_ex_terminate = &__xbt_ex_terminate_default;
147 /* this function is critical to tesh+mmalloc, don't mess with it */
148 int xbt_os_thread_atfork(void (*prepare)(void),
149 void (*parent)(void), void (*child)(void))
152 THROW_UNIMPLEMENTED; //pthread_atfork is not implemented in pthread.h on windows
154 return pthread_atfork(prepare, parent, child);
158 static void *wrapper_start_routine(void *s)
160 xbt_os_thread_t t = s;
163 if ((errcode = pthread_setspecific(xbt_self_thread_key, t)))
164 THROWF(system_error, errcode,
165 "pthread_setspecific failed for xbt_self_thread_key");
167 void *res = t->start_routine(t->param);
169 xbt_os_thread_free_thread_data(t);
174 xbt_os_thread_t xbt_os_thread_create(const char *name,
175 pvoid_f_pvoid_t start_routine,
181 xbt_os_thread_t res_thread = xbt_new(s_xbt_os_thread_t, 1);
182 res_thread->detached = 0;
183 res_thread->name = xbt_strdup(name);
184 res_thread->start_routine = start_routine;
185 res_thread->param = param;
186 res_thread->running_ctx = xbt_new(xbt_running_ctx_t, 1);
187 XBT_RUNNING_CTX_INITIALIZE(res_thread->running_ctx);
188 res_thread->extra_data = extra_data;
190 if ((errcode = pthread_create(&(res_thread->t), &thread_attr,
191 wrapper_start_routine, res_thread)))
192 THROWF(system_error, errcode,
193 "pthread_create failed: %s", strerror(errcode));
202 int xbt_os_thread_bind(xbt_os_thread_t thread, int cpu){
203 pthread_t pthread = thread->t;
207 CPU_SET(cpu, &cpuset);
208 errcode = pthread_setaffinity_np(pthread, sizeof(cpu_set_t), &cpuset);
213 void xbt_os_thread_setstacksize(int stack_size)
215 size_t alignment[] = {
217 #ifdef PTHREAD_STACK_MIN
227 xbt_die("stack size %d is negative, maybe it exceeds MAX_INT?", stack_size);
230 res = pthread_attr_setstacksize(&thread_attr, sz);
232 for (i = 0; res == EINVAL && alignment[i] > 0; i++) {
233 /* Invalid size, try again with next multiple of alignment[i]. */
234 size_t rem = sz % alignment[i];
235 if (rem != 0 || sz == 0) {
236 size_t sz2 = sz - rem + alignment[i];
237 XBT_DEBUG("pthread_attr_setstacksize failed for %zd, try again with %zd",
240 res = pthread_attr_setstacksize(&thread_attr, sz);
245 XBT_WARN("invalid stack size (maybe too big): %zd", sz);
247 XBT_WARN("unknown error %d in pthread stacksize setting: %zd", res, sz);
250 void xbt_os_thread_setguardsize(int guard_size)
253 THROW_UNIMPLEMENTED; //pthread_attr_setguardsize is not implemented in pthread.h on windows
255 size_t sz = guard_size;
256 int res = pthread_attr_setguardsize(&thread_attr, sz);
258 XBT_WARN("pthread_attr_setguardsize failed (%d) for size: %zd", res, sz);
262 const char *xbt_os_thread_name(xbt_os_thread_t t)
267 const char *xbt_os_thread_self_name(void)
269 xbt_os_thread_t me = xbt_os_thread_self();
270 return me ? me->name : "main";
273 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
278 if ((errcode = pthread_join(thread->t, thread_return)))
279 THROWF(system_error, errcode, "pthread_join failed: %s",
281 xbt_os_thread_free_thread_data(thread);
284 void xbt_os_thread_exit(int *retval)
286 pthread_exit(retval);
289 xbt_os_thread_t xbt_os_thread_self(void)
293 if (!thread_mod_inited)
296 res = pthread_getspecific(xbt_self_thread_key);
301 void xbt_os_thread_key_create(xbt_os_thread_key_t* key) {
304 if ((errcode = pthread_key_create(key, NULL)))
305 THROWF(system_error, errcode, "pthread_key_create failed");
308 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value) {
311 if ((errcode = pthread_setspecific(key, value)))
312 THROWF(system_error, errcode, "pthread_setspecific failed");
315 void* xbt_os_thread_get_specific(xbt_os_thread_key_t key) {
316 return pthread_getspecific(key);
319 void xbt_os_thread_detach(xbt_os_thread_t thread)
321 thread->detached = 1;
322 pthread_detach(thread->t);
326 void xbt_os_thread_yield(void)
331 void xbt_os_thread_cancel(xbt_os_thread_t t)
333 pthread_cancel(t->t);
336 /****** mutex related functions ******/
337 typedef struct xbt_os_mutex_ {
338 /* KEEP IT IN SYNC WITH xbt_thread.c */
345 xbt_os_mutex_t xbt_os_mutex_init(void)
347 xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
350 if ((errcode = pthread_mutex_init(&(res->m), NULL)))
351 THROWF(system_error, errcode, "pthread_mutex_init() failed: %s",
357 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
361 if ((errcode = pthread_mutex_lock(&(mutex->m))))
362 THROWF(system_error, errcode, "pthread_mutex_lock(%p) failed: %s",
363 mutex, strerror(errcode));
367 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
372 xbt_os_mutex_acquire(mutex);
374 } else if (delay == 0) {
375 errcode = pthread_mutex_trylock(&(mutex->m));
381 THROWF(timeout_error, 0, "mutex %p not ready", mutex);
383 THROWF(system_error, errcode,
384 "xbt_os_mutex_timedacquire(%p) failed: %s", mutex,
391 #ifdef HAVE_MUTEX_TIMEDLOCK
392 struct timespec ts_end;
393 double end = delay + xbt_os_time();
395 ts_end.tv_sec = (time_t) floor(end);
396 ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
397 XBT_DEBUG("pthread_mutex_timedlock(%p,%p)", &(mutex->m), &ts_end);
399 errcode = pthread_mutex_timedlock(&(mutex->m), &ts_end);
401 #else /* Well, let's reimplement it since those lazy libc dudes didn't */
402 double start = xbt_os_time();
404 errcode = pthread_mutex_trylock(&(mutex->m));
405 if (errcode == EBUSY)
406 xbt_os_thread_yield();
407 } while (errcode == EBUSY && xbt_os_time() - start < delay);
409 if (errcode == EBUSY)
412 #endif /* HAVE_MUTEX_TIMEDLOCK */
419 THROWF(timeout_error, delay,
420 "mutex %p wasn't signaled before timeout (%f)", mutex, delay);
423 THROWF(system_error, errcode,
424 "pthread_mutex_timedlock(%p,%f) failed: %s", mutex, delay,
430 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
434 if ((errcode = pthread_mutex_unlock(&(mutex->m))))
435 THROWF(system_error, errcode, "pthread_mutex_unlock(%p) failed: %s",
436 mutex, strerror(errcode));
439 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
446 if ((errcode = pthread_mutex_destroy(&(mutex->m))))
447 THROWF(system_error, errcode, "pthread_mutex_destroy(%p) failed: %s",
448 mutex, strerror(errcode));
452 /***** condition related functions *****/
453 typedef struct xbt_os_cond_ {
454 /* KEEP IT IN SYNC WITH xbt_thread.c */
458 xbt_os_cond_t xbt_os_cond_init(void)
460 xbt_os_cond_t res = xbt_new(s_xbt_os_cond_t, 1);
462 if ((errcode = pthread_cond_init(&(res->c), NULL)))
463 THROWF(system_error, errcode, "pthread_cond_init() failed: %s",
469 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
472 if ((errcode = pthread_cond_wait(&(cond->c), &(mutex->m))))
473 THROWF(system_error, errcode, "pthread_cond_wait(%p,%p) failed: %s",
474 cond, mutex, strerror(errcode));
478 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
482 struct timespec ts_end;
483 double end = delay + xbt_os_time();
486 xbt_os_cond_wait(cond, mutex);
488 ts_end.tv_sec = (time_t) floor(end);
489 ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
490 XBT_DEBUG("pthread_cond_timedwait(%p,%p,%p)", &(cond->c), &(mutex->m),
493 pthread_cond_timedwait(&(cond->c), &(mutex->m), &ts_end))) {
497 THROWF(timeout_error, errcode,
498 "condition %p (mutex %p) wasn't signaled before timeout (%f)",
501 THROWF(system_error, errcode,
502 "pthread_cond_timedwait(%p,%p,%f) failed: %s", cond, mutex,
503 delay, strerror(errcode));
508 void xbt_os_cond_signal(xbt_os_cond_t cond)
511 if ((errcode = pthread_cond_signal(&(cond->c))))
512 THROWF(system_error, errcode, "pthread_cond_signal(%p) failed: %s",
513 cond, strerror(errcode));
516 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
519 if ((errcode = pthread_cond_broadcast(&(cond->c))))
520 THROWF(system_error, errcode, "pthread_cond_broadcast(%p) failed: %s",
521 cond, strerror(errcode));
524 void xbt_os_cond_destroy(xbt_os_cond_t cond)
531 if ((errcode = pthread_cond_destroy(&(cond->c))))
532 THROWF(system_error, errcode, "pthread_cond_destroy(%p) failed: %s",
533 cond, strerror(errcode));
537 void *xbt_os_thread_getparam(void)
539 xbt_os_thread_t t = xbt_os_thread_self();
540 return t ? t->param : NULL;
543 typedef struct xbt_os_sem_ {
544 #ifndef HAVE_SEM_INIT
552 #define SEM_FAILED (-1)
555 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
557 xbt_os_sem_t res = xbt_new(s_xbt_os_sem_t, 1);
559 /* On some systems (MAC OS X), only the stub of sem_init is to be found.
560 * Any attempt to use it leads to ENOSYS (function not implemented).
561 * If such a prehistoric system is detected, do the job with sem_open instead
564 if (sem_init(&(res->s), 0, value) != 0)
565 THROWF(system_error, errno, "sem_init() failed: %s", strerror(errno));
568 #else /* damn, no sem_init(). Reimplement it */
570 xbt_os_mutex_acquire(next_sem_ID_lock);
571 res->name = bprintf("/%d", ++next_sem_ID);
572 xbt_os_mutex_release(next_sem_ID_lock);
574 res->ps = sem_open(res->name, O_CREAT, 0644, value);
575 if ((res->ps == (sem_t *) SEM_FAILED) && (errno == ENAMETOOLONG)) {
576 /* Old darwins only allow 13 chars. Did you create *that* amount of semaphores? */
577 res->name[13] = '\0';
578 res->ps = sem_open(res->name, O_CREAT, 0644, value);
580 if ((res->ps == (sem_t *) SEM_FAILED))
581 THROWF(system_error, errno, "sem_open() failed: %s", strerror(errno));
583 /* Remove the name from the semaphore namespace: we never join on it */
584 if (sem_unlink(res->name) < 0)
585 THROWF(system_error, errno, "sem_unlink() failed: %s",
593 void xbt_os_sem_acquire(xbt_os_sem_t sem)
596 THROWF(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
597 if (sem_wait(sem->ps) < 0)
598 THROWF(system_error, errno, "sem_wait() failed: %s", strerror(errno));
601 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double delay)
606 THROWF(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
609 xbt_os_sem_acquire(sem);
610 } else if (delay == 0) {
611 errcode = sem_trywait(sem->ps);
617 THROWF(timeout_error, 0, "semaphore %p not ready", sem);
619 THROWF(system_error, errcode,
620 "xbt_os_sem_timedacquire(%p) failed: %s", sem,
626 struct timespec ts_end;
627 double end = delay + xbt_os_time();
629 ts_end.tv_sec = (time_t) floor(end);
630 ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
631 XBT_DEBUG("sem_timedwait(%p,%p)", sem->ps, &ts_end);
632 errcode = sem_timedwait(sem->s, &ts_end);
634 #else /* Okay, reimplement this function then */
635 double start = xbt_os_time();
637 errcode = sem_trywait(sem->ps);
638 if (errcode == EBUSY)
639 xbt_os_thread_yield();
640 } while (errcode == EBUSY && xbt_os_time() - start < delay);
642 if (errcode == EBUSY)
651 THROWF(timeout_error, delay,
652 "semaphore %p wasn't signaled before timeout (%f)", sem,
656 THROWF(system_error, errcode, "sem_timedwait(%p,%f) failed: %s", sem,
657 delay, strerror(errcode));
662 void xbt_os_sem_release(xbt_os_sem_t sem)
665 THROWF(arg_error, EINVAL, "Cannot release of the NULL semaphore");
667 if (sem_post(sem->ps) < 0)
668 THROWF(system_error, errno, "sem_post() failed: %s", strerror(errno));
671 void xbt_os_sem_destroy(xbt_os_sem_t sem)
674 THROWF(arg_error, EINVAL, "Cannot destroy the NULL sempahore");
677 if (sem_destroy(sem->ps) < 0)
678 THROWF(system_error, errno, "sem_destroy() failed: %s",
681 if (sem_close(sem->ps) < 0)
682 THROWF(system_error, errno, "sem_close() failed: %s", strerror(errno));
689 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
692 THROWF(arg_error, EINVAL,
693 "Cannot get the value of the NULL semaphore");
695 if (sem_getvalue(&(sem->s), svalue) < 0)
696 THROWF(system_error, errno, "sem_getvalue() failed: %s",
700 /* ********************************* WINDOWS IMPLEMENTATION ************************************ */
702 #elif defined(_XBT_WIN32)
706 typedef struct xbt_os_thread_ {
708 HANDLE handle; /* the win thread handle */
709 unsigned long id; /* the win thread id */
710 pvoid_f_pvoid_t start_routine;
715 /* so we can specify the size of the stack of the threads */
716 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
717 #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
720 /* the default size of the stack of the threads (in bytes)*/
721 #define XBT_DEFAULT_THREAD_STACK_SIZE 4096
722 static int stack_size=0;
723 /* key to the TLS containing the xbt_os_thread_t structure */
724 static unsigned long xbt_self_thread_key;
726 void xbt_os_thread_mod_preinit(void)
728 xbt_self_thread_key = TlsAlloc();
731 void xbt_os_thread_mod_postexit(void)
734 if (!TlsFree(xbt_self_thread_key))
735 THROWF(system_error, (int) GetLastError(),
736 "TlsFree() failed to cleanup the thread submodule");
739 int xbt_os_thread_atfork(void (*prepare)(void),
740 void (*parent)(void), void (*child)(void))
745 static DWORD WINAPI wrapper_start_routine(void *s)
747 xbt_os_thread_t t = (xbt_os_thread_t) s;
750 if (!TlsSetValue(xbt_self_thread_key, t))
751 THROWF(system_error, (int) GetLastError(),
752 "TlsSetValue of data describing the created thread failed");
754 rv = (DWORD *) ((t->start_routine) (t->param));
761 xbt_os_thread_t xbt_os_thread_create(const char *name,
762 pvoid_f_pvoid_t start_routine,
767 xbt_os_thread_t t = xbt_new(s_xbt_os_thread_t, 1);
769 t->name = xbt_strdup(name);
770 t->start_routine = start_routine;
772 t->extra_data = extra_data;
773 t->handle = CreateThread(NULL, stack_size==0 ? XBT_DEFAULT_THREAD_STACK_SIZE : stack_size,
774 (LPTHREAD_START_ROUTINE) wrapper_start_routine,
775 t, STACK_SIZE_PARAM_IS_A_RESERVATION, &(t->id));
779 THROWF(system_error, (int) GetLastError(), "CreateThread failed");
785 void xbt_os_thread_setstacksize(int size)
790 void xbt_os_thread_setguardsize(int size)
792 XBT_WARN("xbt_os_thread_setguardsize is not implemented (%d)", size);
795 const char *xbt_os_thread_name(xbt_os_thread_t t)
800 const char *xbt_os_thread_self_name(void)
802 xbt_os_thread_t t = xbt_os_thread_self();
803 return t ? t->name : "main";
806 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
809 if (WAIT_OBJECT_0 != WaitForSingleObject(thread->handle, INFINITE))
810 THROWF(system_error, (int) GetLastError(),
811 "WaitForSingleObject failed");
815 if (!GetExitCodeThread(thread->handle, (DWORD *) (*thread_return)))
816 THROWF(system_error, (int) GetLastError(),
817 "GetExitCodeThread failed");
820 CloseHandle(thread->handle);
827 void xbt_os_thread_exit(int *retval)
835 void xbt_os_thread_key_create(xbt_os_thread_key_t* key) {
840 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value) {
842 if (!TlsSetValue(key, value))
843 THROWF(system_error, (int) GetLastError(), "TlsSetValue() failed");
846 void* xbt_os_thread_get_specific(xbt_os_thread_key_t key) {
847 return TlsGetValue(key);
850 void xbt_os_thread_detach(xbt_os_thread_t thread)
856 xbt_os_thread_t xbt_os_thread_self(void)
858 return TlsGetValue(xbt_self_thread_key);
861 void *xbt_os_thread_getparam(void)
863 xbt_os_thread_t t = xbt_os_thread_self();
868 void xbt_os_thread_yield(void)
873 void xbt_os_thread_cancel(xbt_os_thread_t t)
875 if (!TerminateThread(t->handle, 0))
876 THROWF(system_error, (int) GetLastError(), "TerminateThread failed");
879 /****** mutex related functions ******/
880 typedef struct xbt_os_mutex_ {
881 /* KEEP IT IN SYNC WITH xbt_thread.c */
882 CRITICAL_SECTION lock;
885 xbt_os_mutex_t xbt_os_mutex_init(void)
887 xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
889 /* initialize the critical section object */
890 InitializeCriticalSection(&(res->lock));
895 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
897 EnterCriticalSection(&mutex->lock);
900 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
905 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
908 LeaveCriticalSection(&mutex->lock);
912 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
918 DeleteCriticalSection(&mutex->lock);
922 /***** condition related functions *****/
923 enum { /* KEEP IT IN SYNC WITH xbt_thread.c */
929 typedef struct xbt_os_cond_ {
930 /* KEEP IT IN SYNC WITH xbt_thread.c */
931 HANDLE events[MAX_EVENTS];
933 unsigned int waiters_count; /* the number of waiters */
934 CRITICAL_SECTION waiters_count_lock; /* protect access to waiters_count */
937 xbt_os_cond_t xbt_os_cond_init(void)
940 xbt_os_cond_t res = xbt_new0(s_xbt_os_cond_t, 1);
942 memset(&res->waiters_count_lock, 0, sizeof(CRITICAL_SECTION));
944 /* initialize the critical section object */
945 InitializeCriticalSection(&res->waiters_count_lock);
947 res->waiters_count = 0;
949 /* Create an auto-reset event */
950 res->events[SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL);
952 if (!res->events[SIGNAL]) {
953 DeleteCriticalSection(&res->waiters_count_lock);
955 THROWF(system_error, 0, "CreateEvent failed for the signals");
958 /* Create a manual-reset event. */
959 res->events[BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
961 if (!res->events[BROADCAST]) {
963 DeleteCriticalSection(&res->waiters_count_lock);
964 CloseHandle(res->events[SIGNAL]);
966 THROWF(system_error, 0, "CreateEvent failed for the broadcasts");
972 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
975 unsigned long wait_result;
978 /* lock the threads counter and increment it */
979 EnterCriticalSection(&cond->waiters_count_lock);
980 cond->waiters_count++;
981 LeaveCriticalSection(&cond->waiters_count_lock);
983 /* unlock the mutex associate with the condition */
984 LeaveCriticalSection(&mutex->lock);
986 /* wait for a signal (broadcast or no) */
987 wait_result = WaitForMultipleObjects(2, cond->events, FALSE, INFINITE);
989 if (wait_result == WAIT_FAILED)
990 THROWF(system_error, 0,
991 "WaitForMultipleObjects failed, so we cannot wait on the condition");
993 /* we have a signal lock the condition */
994 EnterCriticalSection(&cond->waiters_count_lock);
995 cond->waiters_count--;
997 /* it's the last waiter or it's a broadcast ? */
998 is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
999 && (cond->waiters_count == 0));
1001 LeaveCriticalSection(&cond->waiters_count_lock);
1003 /* yes it's the last waiter or it's a broadcast
1004 * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
1008 if (!ResetEvent(cond->events[BROADCAST]))
1009 THROWF(system_error, 0, "ResetEvent failed");
1011 /* relock the mutex associated with the condition in accordance with the posix thread specification */
1012 EnterCriticalSection(&mutex->lock);
1015 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
1019 unsigned long wait_result = WAIT_TIMEOUT;
1021 unsigned long end = (unsigned long) (delay * 1000);
1025 xbt_os_cond_wait(cond, mutex);
1027 XBT_DEBUG("xbt_cond_timedwait(%p,%p,%lu)", &(cond->events),
1028 &(mutex->lock), end);
1030 /* lock the threads counter and increment it */
1031 EnterCriticalSection(&cond->waiters_count_lock);
1032 cond->waiters_count++;
1033 LeaveCriticalSection(&cond->waiters_count_lock);
1035 /* unlock the mutex associate with the condition */
1036 LeaveCriticalSection(&mutex->lock);
1037 /* wait for a signal (broadcast or no) */
1039 wait_result = WaitForMultipleObjects(2, cond->events, FALSE, end);
1041 switch (wait_result) {
1043 THROWF(timeout_error, GetLastError(),
1044 "condition %p (mutex %p) wasn't signaled before timeout (%f)",
1045 cond, mutex, delay);
1047 THROWF(system_error, GetLastError(),
1048 "WaitForMultipleObjects failed, so we cannot wait on the condition");
1051 /* we have a signal lock the condition */
1052 EnterCriticalSection(&cond->waiters_count_lock);
1053 cond->waiters_count--;
1055 /* it's the last waiter or it's a broadcast ? */
1056 is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
1057 && (cond->waiters_count == 0));
1059 LeaveCriticalSection(&cond->waiters_count_lock);
1061 /* yes it's the last waiter or it's a broadcast
1062 * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
1066 if (!ResetEvent(cond->events[BROADCAST]))
1067 THROWF(system_error, 0, "ResetEvent failed");
1069 /* relock the mutex associated with the condition in accordance with the posix thread specification */
1070 EnterCriticalSection(&mutex->lock);
1072 /*THROW_UNIMPLEMENTED; */
1075 void xbt_os_cond_signal(xbt_os_cond_t cond)
1079 EnterCriticalSection(&cond->waiters_count_lock);
1080 have_waiters = cond->waiters_count > 0;
1081 LeaveCriticalSection(&cond->waiters_count_lock);
1084 if (!SetEvent(cond->events[SIGNAL]))
1085 THROWF(system_error, 0, "SetEvent failed");
1087 xbt_os_thread_yield();
1090 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
1094 EnterCriticalSection(&cond->waiters_count_lock);
1095 have_waiters = cond->waiters_count > 0;
1096 LeaveCriticalSection(&cond->waiters_count_lock);
1099 SetEvent(cond->events[BROADCAST]);
1102 void xbt_os_cond_destroy(xbt_os_cond_t cond)
1109 if (!CloseHandle(cond->events[SIGNAL]))
1112 if (!CloseHandle(cond->events[BROADCAST]))
1115 DeleteCriticalSection(&cond->waiters_count_lock);
1120 THROWF(system_error, 0, "Error while destroying the condition");
1123 typedef struct xbt_os_sem_ {
1126 CRITICAL_SECTION value_lock; /* protect access to value of the semaphore */
1130 # define INT_MAX 32767 /* let's be safe by underestimating this value: this is for 16bits only */
1133 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
1137 if (value > INT_MAX)
1138 THROWF(arg_error, value,
1139 "Semaphore initial value too big: %ud cannot be stored as a signed int",
1142 res = (xbt_os_sem_t) xbt_new0(s_xbt_os_sem_t, 1);
1144 if (!(res->h = CreateSemaphore(NULL, value, (long) INT_MAX, NULL))) {
1145 THROWF(system_error, GetLastError(), "CreateSemaphore() failed: %s",
1146 strerror(GetLastError()));
1152 InitializeCriticalSection(&(res->value_lock));
1157 void xbt_os_sem_acquire(xbt_os_sem_t sem)
1160 THROWF(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1163 if (WAIT_OBJECT_0 != WaitForSingleObject(sem->h, INFINITE))
1164 THROWF(system_error, GetLastError(),
1165 "WaitForSingleObject() failed: %s", strerror(GetLastError()));
1166 EnterCriticalSection(&(sem->value_lock));
1168 LeaveCriticalSection(&(sem->value_lock));
1171 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double timeout)
1175 double end = timeout + xbt_os_time();
1178 THROWF(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1181 xbt_os_sem_acquire(sem);
1182 } else { /* timeout can be zero <-> try acquire ) */
1185 seconds = (long) floor(end);
1186 milliseconds = (long) ((end - seconds) * 1000);
1187 milliseconds += (seconds * 1000);
1189 switch (WaitForSingleObject(sem->h, milliseconds)) {
1191 EnterCriticalSection(&(sem->value_lock));
1193 LeaveCriticalSection(&(sem->value_lock));
1197 THROWF(timeout_error, GetLastError(),
1198 "semaphore %p wasn't signaled before timeout (%f)", sem,
1203 THROWF(system_error, GetLastError(),
1204 "WaitForSingleObject(%p,%f) failed: %s", sem, timeout,
1205 strerror(GetLastError()));
1210 void xbt_os_sem_release(xbt_os_sem_t sem)
1213 THROWF(arg_error, EINVAL, "Cannot release the NULL semaphore");
1215 if (!ReleaseSemaphore(sem->h, 1, NULL))
1216 THROWF(system_error, GetLastError(), "ReleaseSemaphore() failed: %s",
1217 strerror(GetLastError()));
1218 EnterCriticalSection(&(sem->value_lock));
1220 LeaveCriticalSection(&(sem->value_lock));
1223 void xbt_os_sem_destroy(xbt_os_sem_t sem)
1226 THROWF(arg_error, EINVAL, "Cannot destroy the NULL semaphore");
1228 if (!CloseHandle(sem->h))
1229 THROWF(system_error, GetLastError(), "CloseHandle() failed: %s",
1230 strerror(GetLastError()));
1232 DeleteCriticalSection(&(sem->value_lock));
1238 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
1241 THROWF(arg_error, EINVAL,
1242 "Cannot get the value of the NULL semaphore");
1244 EnterCriticalSection(&(sem->value_lock));
1245 *svalue = sem->value;
1246 LeaveCriticalSection(&(sem->value_lock));
1253 /** @brief Returns the amount of cores on the current host */
1254 int xbt_os_get_numcores(void) {
1256 SYSTEM_INFO sysinfo;
1257 GetSystemInfo(&sysinfo);
1258 return sysinfo.dwNumberOfProcessors;
1264 nm[0] = CTL_HW; nm[1] = HW_AVAILCPU;
1265 sysctl(nm, 2, &count, &len, NULL, 0);
1269 sysctl(nm, 2, &count, &len, NULL, 0);
1270 if(count < 1) { count = 1; }
1274 return sysconf(_SC_NPROCESSORS_ONLN);
1279 /***** reentrant mutexes *****/
1280 typedef struct xbt_os_rmutex_ {
1281 xbt_os_mutex_t mutex;
1282 xbt_os_thread_t owner;
1284 } s_xbt_os_rmutex_t;
1286 void xbt_os_thread_set_extra_data(void *data)
1288 xbt_os_thread_self()->extra_data = data;
1291 void *xbt_os_thread_get_extra_data(void)
1293 xbt_os_thread_t self = xbt_os_thread_self();
1294 return self? self->extra_data : NULL;
1297 xbt_os_rmutex_t xbt_os_rmutex_init(void)
1299 xbt_os_rmutex_t rmutex = xbt_new0(struct xbt_os_rmutex_, 1);
1300 rmutex->mutex = xbt_os_mutex_init();
1301 rmutex->owner = NULL;
1306 void xbt_os_rmutex_acquire(xbt_os_rmutex_t rmutex)
1308 xbt_os_thread_t self = xbt_os_thread_self();
1311 /* the thread module is not initialized yet */
1312 rmutex->owner = NULL;
1316 if (self != rmutex->owner) {
1317 xbt_os_mutex_acquire(rmutex->mutex);
1318 rmutex->owner = self;
1325 void xbt_os_rmutex_release(xbt_os_rmutex_t rmutex)
1327 if (rmutex->owner == NULL) {
1328 /* the thread module was not initialized */
1332 xbt_assert(rmutex->owner == xbt_os_thread_self());
1334 if (--rmutex->count == 0) {
1335 rmutex->owner = NULL;
1336 xbt_os_mutex_release(rmutex->mutex);
1340 void xbt_os_rmutex_destroy(xbt_os_rmutex_t rmutex)
1342 xbt_os_mutex_destroy(rmutex->mutex);