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-2015. 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. */
12 #elif defined(__MACH__) && defined(__APPLE__)
14 #include <sys/types.h>
15 #include <sys/sysctl.h>
20 #include "src/internal_config.h"
21 #include "xbt/sysdep.h"
23 #include "src/xbt/ex_interface.h" /* We play crude games with exceptions */
24 #include "src/portable.h"
25 #include "xbt/xbt_os_time.h" /* Portable time facilities */
26 #include "xbt/xbt_os_thread.h" /* This module */
27 #include "src/xbt_modinter.h" /* Initialization/finalization of this module */
29 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_sync_os, xbt,
30 "Synchronization mechanism (OS-level)");
32 /* ********************************* PTHREAD IMPLEMENTATION ************************************ */
37 #include <semaphore.h>
44 /* use named sempahore when sem_init() does not work */
46 static int next_sem_ID = 0;
47 static xbt_os_mutex_t next_sem_ID_lock;
50 typedef struct xbt_os_thread_ {
55 pvoid_f_pvoid_t start_routine;
56 xbt_running_ctx_t *running_ctx;
59 static xbt_os_thread_t main_thread = NULL;
61 /* thread-specific data containing the xbt_os_thread_t structure */
62 static pthread_key_t xbt_self_thread_key;
63 static int thread_mod_inited = 0;
65 /* defaults attribute for pthreads */
66 //FIXME: find where to put this
67 static pthread_attr_t thread_attr;
69 /* frees the xbt_os_thread_t corresponding to the current thread */
70 static void xbt_os_thread_free_thread_data(xbt_os_thread_t thread)
72 if (thread == main_thread) /* just killed main thread */
75 free(thread->running_ctx);
80 /* callback: context fetching */
81 static xbt_running_ctx_t *_os_thread_get_running_ctx(void)
83 return xbt_os_thread_self()->running_ctx;
86 /* callback: termination */
87 static void _os_thread_ex_terminate(xbt_ex_t * e)
91 /* FIXME: there should be a configuration variable to choose to kill everyone or only this one */
94 void xbt_os_thread_mod_preinit(void)
98 if (thread_mod_inited)
101 if ((errcode = pthread_key_create(&xbt_self_thread_key, NULL)))
102 THROWF(system_error, errcode,
103 "pthread_key_create failed for xbt_self_thread_key");
105 main_thread = xbt_new(s_xbt_os_thread_t, 1);
106 main_thread->name = (char *) "main";
107 main_thread->start_routine = NULL;
108 main_thread->param = NULL;
109 main_thread->running_ctx = xbt_new(xbt_running_ctx_t, 1);
110 XBT_RUNNING_CTX_INITIALIZE(main_thread->running_ctx);
112 if ((errcode = pthread_setspecific(xbt_self_thread_key, main_thread)))
113 THROWF(system_error, errcode,
114 "Impossible to set the SimGrid identity descriptor to the main thread (pthread_setspecific failed)");
116 __xbt_running_ctx_fetch = _os_thread_get_running_ctx;
117 __xbt_ex_terminate = _os_thread_ex_terminate;
119 pthread_attr_init(&thread_attr);
121 thread_mod_inited = 1;
123 #ifndef HAVE_SEM_INIT
124 next_sem_ID_lock = xbt_os_mutex_init();
129 void xbt_os_thread_mod_postexit(void)
131 /* FIXME: don't try to free our key on shutdown.
132 Valgrind detects no leak if we don't, and whine if we try to */
135 // if ((errcode=pthread_key_delete(xbt_self_thread_key)))
136 // THROWF(system_error,errcode,"pthread_key_delete failed for xbt_self_thread_key");
137 free(main_thread->running_ctx);
140 thread_mod_inited = 0;
141 #ifndef HAVE_SEM_INIT
142 xbt_os_mutex_destroy(next_sem_ID_lock);
145 /* Restore the default exception setup */
146 __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
147 __xbt_ex_terminate = &__xbt_ex_terminate_default;
150 /* this function is critical to tesh+mmalloc, don't mess with it */
151 int xbt_os_thread_atfork(void (*prepare)(void),
152 void (*parent)(void), void (*child)(void))
155 THROW_UNIMPLEMENTED; //pthread_atfork is not implemented in pthread.h on windows
157 return pthread_atfork(prepare, parent, child);
161 static void *wrapper_start_routine(void *s)
163 xbt_os_thread_t t = s;
166 if ((errcode = pthread_setspecific(xbt_self_thread_key, t)))
167 THROWF(system_error, errcode,
168 "pthread_setspecific failed for xbt_self_thread_key");
170 void *res = t->start_routine(t->param);
172 xbt_os_thread_free_thread_data(t);
177 xbt_os_thread_t xbt_os_thread_create(const char *name,
178 pvoid_f_pvoid_t start_routine,
184 xbt_os_thread_t res_thread = xbt_new(s_xbt_os_thread_t, 1);
185 res_thread->detached = 0;
186 res_thread->name = xbt_strdup(name);
187 res_thread->start_routine = start_routine;
188 res_thread->param = param;
189 res_thread->running_ctx = xbt_new(xbt_running_ctx_t, 1);
190 XBT_RUNNING_CTX_INITIALIZE(res_thread->running_ctx);
191 res_thread->extra_data = extra_data;
193 if ((errcode = pthread_create(&(res_thread->t), &thread_attr,
194 wrapper_start_routine, res_thread)))
195 THROWF(system_error, errcode,
196 "pthread_create failed: %s", strerror(errcode));
205 int xbt_os_thread_bind(xbt_os_thread_t thread, int cpu){
206 pthread_t pthread = thread->t;
210 CPU_SET(cpu, &cpuset);
211 errcode = pthread_setaffinity_np(pthread, sizeof(cpu_set_t), &cpuset);
216 void xbt_os_thread_setstacksize(int stack_size)
218 size_t alignment[] = {
220 #ifdef PTHREAD_STACK_MIN
230 xbt_die("stack size %d is negative, maybe it exceeds MAX_INT?", stack_size);
233 res = pthread_attr_setstacksize(&thread_attr, sz);
235 for (i = 0; res == EINVAL && alignment[i] > 0; i++) {
236 /* Invalid size, try again with next multiple of alignment[i]. */
237 size_t rem = sz % alignment[i];
238 if (rem != 0 || sz == 0) {
239 size_t sz2 = sz - rem + alignment[i];
240 XBT_DEBUG("pthread_attr_setstacksize failed for %zd, try again with %zd",
243 res = pthread_attr_setstacksize(&thread_attr, sz);
248 XBT_WARN("invalid stack size (maybe too big): %zd", sz);
250 XBT_WARN("unknown error %d in pthread stacksize setting: %zd", res, sz);
253 void xbt_os_thread_setguardsize(int guard_size)
256 THROW_UNIMPLEMENTED; //pthread_attr_setguardsize is not implemented in pthread.h on windows
258 size_t sz = guard_size;
259 int res = pthread_attr_setguardsize(&thread_attr, sz);
261 XBT_WARN("pthread_attr_setguardsize failed (%d) for size: %zd", res, sz);
265 const char *xbt_os_thread_name(xbt_os_thread_t t)
270 const char *xbt_os_thread_self_name(void)
272 xbt_os_thread_t me = xbt_os_thread_self();
273 return me ? me->name : "main";
276 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
281 if ((errcode = pthread_join(thread->t, thread_return)))
282 THROWF(system_error, errcode, "pthread_join failed: %s",
284 xbt_os_thread_free_thread_data(thread);
287 void xbt_os_thread_exit(int *retval)
289 pthread_exit(retval);
292 xbt_os_thread_t xbt_os_thread_self(void)
294 if (!thread_mod_inited)
297 return pthread_getspecific(xbt_self_thread_key);
300 void xbt_os_thread_key_create(xbt_os_thread_key_t* key) {
303 if ((errcode = pthread_key_create(key, NULL)))
304 THROWF(system_error, errcode, "pthread_key_create failed");
307 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value) {
310 if ((errcode = pthread_setspecific(key, value)))
311 THROWF(system_error, errcode, "pthread_setspecific failed");
314 void* xbt_os_thread_get_specific(xbt_os_thread_key_t key) {
315 return pthread_getspecific(key);
318 void xbt_os_thread_detach(xbt_os_thread_t thread)
320 thread->detached = 1;
321 pthread_detach(thread->t);
325 void xbt_os_thread_yield(void)
330 void xbt_os_thread_cancel(xbt_os_thread_t t)
332 pthread_cancel(t->t);
335 /****** mutex related functions ******/
336 typedef struct xbt_os_mutex_ {
337 /* KEEP IT IN SYNC WITH xbt_thread.c */
344 xbt_os_mutex_t xbt_os_mutex_init(void)
346 xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
349 if ((errcode = pthread_mutex_init(&(res->m), NULL)))
350 THROWF(system_error, errcode, "pthread_mutex_init() failed: %s",
356 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
360 if ((errcode = pthread_mutex_lock(&(mutex->m))))
361 THROWF(system_error, errcode, "pthread_mutex_lock(%p) failed: %s",
362 mutex, strerror(errcode));
366 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
371 xbt_os_mutex_acquire(mutex);
373 } else if (delay == 0) {
374 errcode = pthread_mutex_trylock(&(mutex->m));
380 THROWF(timeout_error, 0, "mutex %p not ready", mutex);
382 THROWF(system_error, errcode,
383 "xbt_os_mutex_timedacquire(%p) failed: %s", mutex,
390 #ifdef HAVE_MUTEX_TIMEDLOCK
391 struct timespec ts_end;
392 double end = delay + xbt_os_time();
394 ts_end.tv_sec = (time_t) floor(end);
395 ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
396 XBT_DEBUG("pthread_mutex_timedlock(%p,%p)", &(mutex->m), &ts_end);
398 errcode = pthread_mutex_timedlock(&(mutex->m), &ts_end);
400 #else /* Well, let's reimplement it since those lazy libc dudes didn't */
401 double start = xbt_os_time();
403 errcode = pthread_mutex_trylock(&(mutex->m));
404 if (errcode == EBUSY)
405 xbt_os_thread_yield();
406 } while (errcode == EBUSY && xbt_os_time() - start < delay);
408 if (errcode == EBUSY)
411 #endif /* HAVE_MUTEX_TIMEDLOCK */
418 THROWF(timeout_error, delay,
419 "mutex %p wasn't signaled before timeout (%f)", mutex, delay);
422 THROWF(system_error, errcode,
423 "pthread_mutex_timedlock(%p,%f) failed: %s", mutex, delay,
429 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
433 if ((errcode = pthread_mutex_unlock(&(mutex->m))))
434 THROWF(system_error, errcode, "pthread_mutex_unlock(%p) failed: %s",
435 mutex, strerror(errcode));
438 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
445 if ((errcode = pthread_mutex_destroy(&(mutex->m))))
446 THROWF(system_error, errcode, "pthread_mutex_destroy(%p) failed: %s",
447 mutex, strerror(errcode));
451 /***** condition related functions *****/
452 typedef struct xbt_os_cond_ {
453 /* KEEP IT IN SYNC WITH xbt_thread.c */
457 xbt_os_cond_t xbt_os_cond_init(void)
459 xbt_os_cond_t res = xbt_new(s_xbt_os_cond_t, 1);
461 if ((errcode = pthread_cond_init(&(res->c), NULL)))
462 THROWF(system_error, errcode, "pthread_cond_init() failed: %s",
468 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
471 if ((errcode = pthread_cond_wait(&(cond->c), &(mutex->m))))
472 THROWF(system_error, errcode, "pthread_cond_wait(%p,%p) failed: %s",
473 cond, mutex, strerror(errcode));
477 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
481 struct timespec ts_end;
482 double end = delay + xbt_os_time();
485 xbt_os_cond_wait(cond, mutex);
487 ts_end.tv_sec = (time_t) floor(end);
488 ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
489 XBT_DEBUG("pthread_cond_timedwait(%p,%p,%p)", &(cond->c), &(mutex->m),
492 pthread_cond_timedwait(&(cond->c), &(mutex->m), &ts_end))) {
496 THROWF(timeout_error, errcode,
497 "condition %p (mutex %p) wasn't signaled before timeout (%f)",
500 THROWF(system_error, errcode,
501 "pthread_cond_timedwait(%p,%p,%f) failed: %s", cond, mutex,
502 delay, strerror(errcode));
507 void xbt_os_cond_signal(xbt_os_cond_t cond)
510 if ((errcode = pthread_cond_signal(&(cond->c))))
511 THROWF(system_error, errcode, "pthread_cond_signal(%p) failed: %s",
512 cond, strerror(errcode));
515 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
518 if ((errcode = pthread_cond_broadcast(&(cond->c))))
519 THROWF(system_error, errcode, "pthread_cond_broadcast(%p) failed: %s",
520 cond, strerror(errcode));
523 void xbt_os_cond_destroy(xbt_os_cond_t cond)
530 if ((errcode = pthread_cond_destroy(&(cond->c))))
531 THROWF(system_error, errcode, "pthread_cond_destroy(%p) failed: %s",
532 cond, strerror(errcode));
536 void *xbt_os_thread_getparam(void)
538 xbt_os_thread_t t = xbt_os_thread_self();
539 return t ? t->param : NULL;
542 typedef struct xbt_os_sem_ {
543 #ifndef HAVE_SEM_INIT
551 #define SEM_FAILED (-1)
554 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
556 xbt_os_sem_t res = xbt_new(s_xbt_os_sem_t, 1);
558 /* On some systems (MAC OS X), only the stub of sem_init is to be found.
559 * Any attempt to use it leads to ENOSYS (function not implemented).
560 * If such a prehistoric system is detected, do the job with sem_open instead
563 if (sem_init(&(res->s), 0, value) != 0)
564 THROWF(system_error, errno, "sem_init() failed: %s", strerror(errno));
567 #else /* damn, no sem_init(). Reimplement it */
569 xbt_os_mutex_acquire(next_sem_ID_lock);
570 res->name = bprintf("/%d", ++next_sem_ID);
571 xbt_os_mutex_release(next_sem_ID_lock);
573 res->ps = sem_open(res->name, O_CREAT, 0644, value);
574 if ((res->ps == (sem_t *) SEM_FAILED) && (errno == ENAMETOOLONG)) {
575 /* Old darwins only allow 13 chars. Did you create *that* amount of semaphores? */
576 res->name[13] = '\0';
577 res->ps = sem_open(res->name, O_CREAT, 0644, value);
579 if (res->ps == (sem_t *) SEM_FAILED)
580 THROWF(system_error, errno, "sem_open() failed: %s", strerror(errno));
582 /* Remove the name from the semaphore namespace: we never join on it */
583 if (sem_unlink(res->name) < 0)
584 THROWF(system_error, errno, "sem_unlink() failed: %s",
592 void xbt_os_sem_acquire(xbt_os_sem_t sem)
595 THROWF(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
596 if (sem_wait(sem->ps) < 0)
597 THROWF(system_error, errno, "sem_wait() failed: %s", strerror(errno));
600 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double delay)
605 THROWF(arg_error, EINVAL, "Cannot acquire of the NULL semaphore");
608 xbt_os_sem_acquire(sem);
609 } else if (delay == 0) {
610 errcode = sem_trywait(sem->ps);
616 THROWF(timeout_error, 0, "semaphore %p not ready", sem);
618 THROWF(system_error, errcode,
619 "xbt_os_sem_timedacquire(%p) failed: %s", sem,
625 struct timespec ts_end;
626 double end = delay + xbt_os_time();
628 ts_end.tv_sec = (time_t) floor(end);
629 ts_end.tv_nsec = (long) ((end - ts_end.tv_sec) * 1000000000);
630 XBT_DEBUG("sem_timedwait(%p,%p)", sem->ps, &ts_end);
631 errcode = sem_timedwait(sem->s, &ts_end);
633 #else /* Okay, reimplement this function then */
634 double start = xbt_os_time();
636 errcode = sem_trywait(sem->ps);
637 if (errcode == EBUSY)
638 xbt_os_thread_yield();
639 } while (errcode == EBUSY && xbt_os_time() - start < delay);
641 if (errcode == EBUSY)
650 THROWF(timeout_error, delay,
651 "semaphore %p wasn't signaled before timeout (%f)", sem,
655 THROWF(system_error, errcode, "sem_timedwait(%p,%f) failed: %s", sem,
656 delay, strerror(errcode));
661 void xbt_os_sem_release(xbt_os_sem_t sem)
664 THROWF(arg_error, EINVAL, "Cannot release of the NULL semaphore");
666 if (sem_post(sem->ps) < 0)
667 THROWF(system_error, errno, "sem_post() failed: %s", strerror(errno));
670 void xbt_os_sem_destroy(xbt_os_sem_t sem)
673 THROWF(arg_error, EINVAL, "Cannot destroy the NULL sempahore");
676 if (sem_destroy(sem->ps) < 0)
677 THROWF(system_error, errno, "sem_destroy() failed: %s",
680 if (sem_close(sem->ps) < 0)
681 THROWF(system_error, errno, "sem_close() failed: %s", strerror(errno));
688 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
691 THROWF(arg_error, EINVAL,
692 "Cannot get the value of the NULL semaphore");
694 if (sem_getvalue(&(sem->s), svalue) < 0)
695 THROWF(system_error, errno, "sem_getvalue() failed: %s",
699 /* ********************************* WINDOWS IMPLEMENTATION ************************************ */
701 #elif defined(_XBT_WIN32)
705 typedef struct xbt_os_thread_ {
707 HANDLE handle; /* the win thread handle */
708 unsigned long id; /* the win thread id */
709 pvoid_f_pvoid_t start_routine;
714 /* so we can specify the size of the stack of the threads */
715 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
716 #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
719 /* the default size of the stack of the threads (in bytes)*/
720 #define XBT_DEFAULT_THREAD_STACK_SIZE 4096
721 static int stack_size=0;
722 /* key to the TLS containing the xbt_os_thread_t structure */
723 static unsigned long xbt_self_thread_key;
725 void xbt_os_thread_mod_preinit(void)
727 xbt_self_thread_key = TlsAlloc();
729 xbt_os_thread_t main_thread = xbt_new0(s_xbt_os_thread_t, 1);
730 main_thread->name = (char *) "main";
731 main_thread->start_routine = NULL;
732 main_thread->param = NULL;
734 if (!TlsSetValue(xbt_self_thread_key, main_thread))
735 THROWF(system_error, (int)GetLastError(),
736 "Impossible to set the SimGrid identity descriptor to the main thread (TlsSetValue() failed)");
740 void xbt_os_thread_mod_postexit(void)
743 if (!TlsFree(xbt_self_thread_key))
744 THROWF(system_error, (int) GetLastError(),
745 "TlsFree() failed to cleanup the thread submodule");
748 int xbt_os_thread_atfork(void (*prepare)(void),
749 void (*parent)(void), void (*child)(void))
754 static DWORD WINAPI wrapper_start_routine(void *s)
756 xbt_os_thread_t t = (xbt_os_thread_t) s;
759 if (!TlsSetValue(xbt_self_thread_key, t))
760 THROWF(system_error, (int) GetLastError(),
761 "TlsSetValue of data describing the created thread failed");
763 rv = (DWORD *) ((t->start_routine) (t->param));
770 xbt_os_thread_t xbt_os_thread_create(const char *name,
771 pvoid_f_pvoid_t start_routine,
776 xbt_os_thread_t t = xbt_new(s_xbt_os_thread_t, 1);
778 t->name = xbt_strdup(name);
779 t->start_routine = start_routine;
781 t->extra_data = extra_data;
782 t->handle = CreateThread(NULL, stack_size==0 ? XBT_DEFAULT_THREAD_STACK_SIZE : stack_size,
783 (LPTHREAD_START_ROUTINE) wrapper_start_routine,
784 t, STACK_SIZE_PARAM_IS_A_RESERVATION, &(t->id));
788 THROWF(system_error, (int) GetLastError(), "CreateThread failed");
794 void xbt_os_thread_setstacksize(int size)
799 void xbt_os_thread_setguardsize(int size)
801 XBT_WARN("xbt_os_thread_setguardsize is not implemented (%d)", size);
804 const char *xbt_os_thread_name(xbt_os_thread_t t)
809 const char *xbt_os_thread_self_name(void)
811 xbt_os_thread_t t = xbt_os_thread_self();
812 return t ? t->name : "main";
815 void xbt_os_thread_join(xbt_os_thread_t thread, void **thread_return)
818 if (WAIT_OBJECT_0 != WaitForSingleObject(thread->handle, INFINITE))
819 THROWF(system_error, (int) GetLastError(),
820 "WaitForSingleObject failed");
824 if (!GetExitCodeThread(thread->handle, (DWORD *) (*thread_return)))
825 THROWF(system_error, (int) GetLastError(),
826 "GetExitCodeThread failed");
829 CloseHandle(thread->handle);
836 void xbt_os_thread_exit(int *retval)
844 void xbt_os_thread_key_create(xbt_os_thread_key_t* key) {
849 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value) {
851 if (!TlsSetValue(key, value))
852 THROWF(system_error, (int) GetLastError(), "TlsSetValue() failed");
855 void* xbt_os_thread_get_specific(xbt_os_thread_key_t key) {
856 return TlsGetValue(key);
859 void xbt_os_thread_detach(xbt_os_thread_t thread)
865 xbt_os_thread_t xbt_os_thread_self(void)
867 return TlsGetValue(xbt_self_thread_key);
870 void *xbt_os_thread_getparam(void)
872 xbt_os_thread_t t = xbt_os_thread_self();
877 void xbt_os_thread_yield(void)
882 void xbt_os_thread_cancel(xbt_os_thread_t t)
884 if (!TerminateThread(t->handle, 0))
885 THROWF(system_error, (int) GetLastError(), "TerminateThread failed");
888 /****** mutex related functions ******/
889 typedef struct xbt_os_mutex_ {
890 /* KEEP IT IN SYNC WITH xbt_thread.c */
891 CRITICAL_SECTION lock;
894 xbt_os_mutex_t xbt_os_mutex_init(void)
896 xbt_os_mutex_t res = xbt_new(s_xbt_os_mutex_t, 1);
898 /* initialize the critical section object */
899 InitializeCriticalSection(&(res->lock));
904 void xbt_os_mutex_acquire(xbt_os_mutex_t mutex)
906 EnterCriticalSection(&mutex->lock);
909 void xbt_os_mutex_timedacquire(xbt_os_mutex_t mutex, double delay)
914 void xbt_os_mutex_release(xbt_os_mutex_t mutex)
917 LeaveCriticalSection(&mutex->lock);
921 void xbt_os_mutex_destroy(xbt_os_mutex_t mutex)
927 DeleteCriticalSection(&mutex->lock);
931 /***** condition related functions *****/
932 enum { /* KEEP IT IN SYNC WITH xbt_thread.c */
938 typedef struct xbt_os_cond_ {
939 /* KEEP IT IN SYNC WITH xbt_thread.c */
940 HANDLE events[MAX_EVENTS];
942 unsigned int waiters_count; /* the number of waiters */
943 CRITICAL_SECTION waiters_count_lock; /* protect access to waiters_count */
946 xbt_os_cond_t xbt_os_cond_init(void)
949 xbt_os_cond_t res = xbt_new0(s_xbt_os_cond_t, 1);
951 memset(&res->waiters_count_lock, 0, sizeof(CRITICAL_SECTION));
953 /* initialize the critical section object */
954 InitializeCriticalSection(&res->waiters_count_lock);
956 res->waiters_count = 0;
958 /* Create an auto-reset event */
959 res->events[SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL);
961 if (!res->events[SIGNAL]) {
962 DeleteCriticalSection(&res->waiters_count_lock);
964 THROWF(system_error, 0, "CreateEvent failed for the signals");
967 /* Create a manual-reset event. */
968 res->events[BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
970 if (!res->events[BROADCAST]) {
972 DeleteCriticalSection(&res->waiters_count_lock);
973 CloseHandle(res->events[SIGNAL]);
975 THROWF(system_error, 0, "CreateEvent failed for the broadcasts");
981 void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex)
984 unsigned long wait_result;
987 /* lock the threads counter and increment it */
988 EnterCriticalSection(&cond->waiters_count_lock);
989 cond->waiters_count++;
990 LeaveCriticalSection(&cond->waiters_count_lock);
992 /* unlock the mutex associate with the condition */
993 LeaveCriticalSection(&mutex->lock);
995 /* wait for a signal (broadcast or no) */
996 wait_result = WaitForMultipleObjects(2, cond->events, FALSE, INFINITE);
998 if (wait_result == WAIT_FAILED)
999 THROWF(system_error, 0,
1000 "WaitForMultipleObjects failed, so we cannot wait on the condition");
1002 /* we have a signal lock the condition */
1003 EnterCriticalSection(&cond->waiters_count_lock);
1004 cond->waiters_count--;
1006 /* it's the last waiter or it's a broadcast ? */
1007 is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
1008 && (cond->waiters_count == 0));
1010 LeaveCriticalSection(&cond->waiters_count_lock);
1012 /* yes it's the last waiter or it's a broadcast
1013 * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
1017 if (!ResetEvent(cond->events[BROADCAST]))
1018 THROWF(system_error, 0, "ResetEvent failed");
1020 /* relock the mutex associated with the condition in accordance with the posix thread specification */
1021 EnterCriticalSection(&mutex->lock);
1024 void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex,
1028 unsigned long wait_result = WAIT_TIMEOUT;
1030 unsigned long end = (unsigned long) (delay * 1000);
1034 xbt_os_cond_wait(cond, mutex);
1036 XBT_DEBUG("xbt_cond_timedwait(%p,%p,%lu)", &(cond->events),
1037 &(mutex->lock), end);
1039 /* lock the threads counter and increment it */
1040 EnterCriticalSection(&cond->waiters_count_lock);
1041 cond->waiters_count++;
1042 LeaveCriticalSection(&cond->waiters_count_lock);
1044 /* unlock the mutex associate with the condition */
1045 LeaveCriticalSection(&mutex->lock);
1046 /* wait for a signal (broadcast or no) */
1048 wait_result = WaitForMultipleObjects(2, cond->events, FALSE, end);
1050 switch (wait_result) {
1052 THROWF(timeout_error, GetLastError(),
1053 "condition %p (mutex %p) wasn't signaled before timeout (%f)",
1054 cond, mutex, delay);
1056 THROWF(system_error, GetLastError(),
1057 "WaitForMultipleObjects failed, so we cannot wait on the condition");
1060 /* we have a signal lock the condition */
1061 EnterCriticalSection(&cond->waiters_count_lock);
1062 cond->waiters_count--;
1064 /* it's the last waiter or it's a broadcast ? */
1065 is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1)
1066 && (cond->waiters_count == 0));
1068 LeaveCriticalSection(&cond->waiters_count_lock);
1070 /* yes it's the last waiter or it's a broadcast
1071 * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
1075 if (!ResetEvent(cond->events[BROADCAST]))
1076 THROWF(system_error, 0, "ResetEvent failed");
1078 /* relock the mutex associated with the condition in accordance with the posix thread specification */
1079 EnterCriticalSection(&mutex->lock);
1081 /*THROW_UNIMPLEMENTED; */
1084 void xbt_os_cond_signal(xbt_os_cond_t cond)
1088 EnterCriticalSection(&cond->waiters_count_lock);
1089 have_waiters = cond->waiters_count > 0;
1090 LeaveCriticalSection(&cond->waiters_count_lock);
1093 if (!SetEvent(cond->events[SIGNAL]))
1094 THROWF(system_error, 0, "SetEvent failed");
1096 xbt_os_thread_yield();
1099 void xbt_os_cond_broadcast(xbt_os_cond_t cond)
1103 EnterCriticalSection(&cond->waiters_count_lock);
1104 have_waiters = cond->waiters_count > 0;
1105 LeaveCriticalSection(&cond->waiters_count_lock);
1108 SetEvent(cond->events[BROADCAST]);
1111 void xbt_os_cond_destroy(xbt_os_cond_t cond)
1118 if (!CloseHandle(cond->events[SIGNAL]))
1121 if (!CloseHandle(cond->events[BROADCAST]))
1124 DeleteCriticalSection(&cond->waiters_count_lock);
1129 THROWF(system_error, 0, "Error while destroying the condition");
1132 typedef struct xbt_os_sem_ {
1135 CRITICAL_SECTION value_lock; /* protect access to value of the semaphore */
1139 # define INT_MAX 32767 /* let's be safe by underestimating this value: this is for 16bits only */
1142 xbt_os_sem_t xbt_os_sem_init(unsigned int value)
1146 if (value > INT_MAX)
1147 THROWF(arg_error, value,
1148 "Semaphore initial value too big: %ud cannot be stored as a signed int",
1151 res = (xbt_os_sem_t) xbt_new0(s_xbt_os_sem_t, 1);
1153 if (!(res->h = CreateSemaphore(NULL, value, (long) INT_MAX, NULL))) {
1154 THROWF(system_error, GetLastError(), "CreateSemaphore() failed: %s",
1155 strerror(GetLastError()));
1161 InitializeCriticalSection(&(res->value_lock));
1166 void xbt_os_sem_acquire(xbt_os_sem_t sem)
1169 THROWF(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1172 if (WAIT_OBJECT_0 != WaitForSingleObject(sem->h, INFINITE))
1173 THROWF(system_error, GetLastError(),
1174 "WaitForSingleObject() failed: %s", strerror(GetLastError()));
1175 EnterCriticalSection(&(sem->value_lock));
1177 LeaveCriticalSection(&(sem->value_lock));
1180 void xbt_os_sem_timedacquire(xbt_os_sem_t sem, double timeout)
1184 double end = timeout + xbt_os_time();
1187 THROWF(arg_error, EINVAL, "Cannot acquire the NULL semaphore");
1190 xbt_os_sem_acquire(sem);
1191 } else { /* timeout can be zero <-> try acquire ) */
1194 seconds = (long) floor(end);
1195 milliseconds = (long) ((end - seconds) * 1000);
1196 milliseconds += (seconds * 1000);
1198 switch (WaitForSingleObject(sem->h, milliseconds)) {
1200 EnterCriticalSection(&(sem->value_lock));
1202 LeaveCriticalSection(&(sem->value_lock));
1206 THROWF(timeout_error, GetLastError(),
1207 "semaphore %p wasn't signaled before timeout (%f)", sem,
1212 THROWF(system_error, GetLastError(),
1213 "WaitForSingleObject(%p,%f) failed: %s", sem, timeout,
1214 strerror(GetLastError()));
1219 void xbt_os_sem_release(xbt_os_sem_t sem)
1222 THROWF(arg_error, EINVAL, "Cannot release the NULL semaphore");
1224 if (!ReleaseSemaphore(sem->h, 1, NULL))
1225 THROWF(system_error, GetLastError(), "ReleaseSemaphore() failed: %s",
1226 strerror(GetLastError()));
1227 EnterCriticalSection(&(sem->value_lock));
1229 LeaveCriticalSection(&(sem->value_lock));
1232 void xbt_os_sem_destroy(xbt_os_sem_t sem)
1235 THROWF(arg_error, EINVAL, "Cannot destroy the NULL semaphore");
1237 if (!CloseHandle(sem->h))
1238 THROWF(system_error, GetLastError(), "CloseHandle() failed: %s",
1239 strerror(GetLastError()));
1241 DeleteCriticalSection(&(sem->value_lock));
1247 void xbt_os_sem_get_value(xbt_os_sem_t sem, int *svalue)
1250 THROWF(arg_error, EINVAL,
1251 "Cannot get the value of the NULL semaphore");
1253 EnterCriticalSection(&(sem->value_lock));
1254 *svalue = sem->value;
1255 LeaveCriticalSection(&(sem->value_lock));
1262 /** @brief Returns the amount of cores on the current host */
1263 int xbt_os_get_numcores(void) {
1265 SYSTEM_INFO sysinfo;
1266 GetSystemInfo(&sysinfo);
1267 return sysinfo.dwNumberOfProcessors;
1268 #elif defined(__APPLE__) && defined(__MACH__)
1273 nm[0] = CTL_HW; nm[1] = HW_AVAILCPU;
1274 sysctl(nm, 2, &count, &len, NULL, 0);
1278 sysctl(nm, 2, &count, &len, NULL, 0);
1279 if(count < 1) { count = 1; }
1283 return sysconf(_SC_NPROCESSORS_ONLN);
1288 /***** reentrant mutexes *****/
1289 typedef struct xbt_os_rmutex_ {
1290 xbt_os_mutex_t mutex;
1291 xbt_os_thread_t owner;
1293 } s_xbt_os_rmutex_t;
1295 void xbt_os_thread_set_extra_data(void *data)
1297 xbt_os_thread_self()->extra_data = data;
1300 void *xbt_os_thread_get_extra_data(void)
1302 return xbt_os_thread_self()->extra_data;
1305 xbt_os_rmutex_t xbt_os_rmutex_init(void)
1307 xbt_os_rmutex_t rmutex = xbt_new0(struct xbt_os_rmutex_, 1);
1308 rmutex->mutex = xbt_os_mutex_init();
1309 rmutex->owner = NULL;
1314 void xbt_os_rmutex_acquire(xbt_os_rmutex_t rmutex)
1316 xbt_os_thread_t self = xbt_os_thread_self();
1319 /* the thread module is not initialized yet */
1320 rmutex->owner = NULL;
1324 if (self != rmutex->owner) {
1325 xbt_os_mutex_acquire(rmutex->mutex);
1326 rmutex->owner = self;
1333 void xbt_os_rmutex_release(xbt_os_rmutex_t rmutex)
1335 if (rmutex->owner == NULL) {
1336 /* the thread module was not initialized */
1340 xbt_assert(rmutex->owner == xbt_os_thread_self());
1342 if (--rmutex->count == 0) {
1343 rmutex->owner = NULL;
1344 xbt_os_mutex_release(rmutex->mutex);
1348 void xbt_os_rmutex_destroy(xbt_os_rmutex_t rmutex)
1350 xbt_os_mutex_destroy(rmutex->mutex);