From: cherierm Date: Mon, 22 Oct 2007 08:51:31 +0000 (+0000) Subject: This change concerne the usage of the semaphore object instead the variable condition... X-Git-Tag: v3.3~962 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/dfe761f4bc8d35a74c3da5fabe99630c0788001f This change concerne the usage of the semaphore object instead the variable condition to synchronize the msg processes during a simulation. The xbt_os_sem_t type represents a semaphore and you' ll find its declaration in the header xbt_os_thread.h and its implementation in the file xbt_os_thread.c. The file portable.h is modified to declare the function gettimeofday() used by many several other functions such the function xbt_os_sem_timedwait() declared in the header xbt_os_thread.h. The context structure declared in the header context_private.h is modified to use the semaphore instead the condition variable. git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@4838 48e7efb5-ca39-0410-a469-dd3cf9ba447f --- diff --git a/src/include/xbt/xbt_os_thread.h b/src/include/xbt/xbt_os_thread.h index e42d2ec0f4..b39fcec63e 100644 --- a/src/include/xbt/xbt_os_thread.h +++ b/src/include/xbt/xbt_os_thread.h @@ -14,6 +14,11 @@ #include "xbt/misc.h" /* SG_BEGIN_DECL */ #include "xbt/function_types.h" +#ifndef WIN32 /* HAVE_SEMAPHOR_H */ +#include +#endif + + SG_BEGIN_DECL() /** @addtogroup XBT_thread @@ -61,6 +66,19 @@ SG_BEGIN_DECL() XBT_PUBLIC(void) xbt_os_cond_signal(xbt_os_cond_t cond); XBT_PUBLIC(void) xbt_os_cond_broadcast(xbt_os_cond_t cond); XBT_PUBLIC(void) xbt_os_cond_destroy(xbt_os_cond_t cond); + + /** \brief Semaphore data type (opaque structure) */ + typedef struct xbt_os_sem_* xbt_os_sem_t; + + XBT_PUBLIC(xbt_os_sem_t) xbt_os_sem_init(int pshared, unsigned int value); + XBT_PUBLIC(xbt_os_sem_t) xbt_os_sem_open(const char *name, int oflag, mode_t mode, unsigned int value); + XBT_PUBLIC(void) xbt_os_sem_wait(xbt_os_sem_t sem); + XBT_PUBLIC(void) xbt_os_sem_timedwait(xbt_os_sem_t sem,const struct timespec* abs_timeout); + XBT_PUBLIC(void) xbt_os_sem_post(xbt_os_sem_t sem); + XBT_PUBLIC(void) xbt_os_sem_close(xbt_os_sem_t sem); + XBT_PUBLIC(void) xbt_os_sem_destroy(xbt_os_sem_t sem); + XBT_PUBLIC(void) xbt_os_sem_get_value(xbt_os_sem_t sem, int* svalue); + /** @} */ diff --git a/src/portable.h b/src/portable.h index f56b81db8f..537d24cff6 100644 --- a/src/portable.h +++ b/src/portable.h @@ -156,4 +156,11 @@ extern int vasnprintf(char **ptr, size_t str_m, const char *fmt, va_list ap); void hexa_print(const char*name, unsigned char *data, int size); const char *hexa_str(unsigned char *data, int size, int downside); + +#if defined(WIN32) +/* Visual C++ does not implements the gettimeofday() function */ +XBT_PUBLIC(int) +gettimeofday(struct timeval *tv, struct timezone *tz); +#endif + #endif /* GRAS_PORTABLE_H */ diff --git a/src/win32/compiler/visualc.h b/src/win32/compiler/visualc.h index cb19849449..a8af217c66 100644 --- a/src/win32/compiler/visualc.h +++ b/src/win32/compiler/visualc.h @@ -399,8 +399,6 @@ the double. For now, GRAS requires the structures to be compacted. */ * Replace winsock2.h,ws2tcpip.h and winsock.h header files */ #include -/* types */ -typedef unsigned int uint32_t; /* Choose setjmp as exception implementation */ #ifndef __EX_MCTX_SJLJ__ @@ -408,6 +406,50 @@ typedef unsigned int uint32_t; #endif + +#include + +#define S_IWUSR _S_IWRITE +#define S_IRUSR _S_IREAD + +#define HAVE_STRUCT_TIMESPEC 0 + +#define HAVE_STRUCT_TM 1 + +#define HAVE_GETTIMEOFDAY 1 + +#ifdef _WIN32_WINNT + #if _WIN32_WINNT < 0x0400 + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0400 + #endif +#else + #define _WIN32_WINNT 0x0400 +#endif + +/* Visual C++ does not declare the ssize_t type */ typedef int ssize_t; +/* Visual C++ does not declare the mode_t type */ +typedef unsigned int mode_t; + +/* Visual C++ does not declare the uint32_t type */ +typedef unsigned int uint32_t; + +/* Visual C++ doesn't declare the structure timespec */ +struct timespec +{ + long tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; + +/* Visual C++ doesn't declare the structure timezone : + *(a structure used to indicate the local time zone) + */ +struct timezone +{ + int tz_minuteswest; /* of Greenwich */ + int tz_dsttime; /* type of dst correction to apply */ +}; + #endif /* #ifndef __XBT_VISUALC_COMPILER_CONFIG_H__ */ diff --git a/src/xbt/context.c b/src/xbt/context.c index 4629739f2d..4f4edcaf46 100644 --- a/src/xbt/context.c +++ b/src/xbt/context.c @@ -25,19 +25,6 @@ static xbt_context_t init_context = NULL; static xbt_swag_t context_to_destroy = NULL; static xbt_swag_t context_living = NULL; -#ifdef CONTEXT_THREADS -static xbt_os_mutex_t creation_mutex; -static xbt_os_cond_t creation_cond; -static xbt_os_mutex_t master_mutex; -static xbt_os_cond_t master_cond; - -static xbt_os_thread_t current_thread_id; - -static int is_main_thread(void) { - return xbt_os_thread_self() == current_thread_id; -} - -#endif /********************/ @@ -62,6 +49,27 @@ static void _context_ex_terminate(xbt_ex_t * e) } #endif + +static void +schedule(xbt_context_t c); + +static void +unschedule(xbt_context_t c); + + +static void +schedule(xbt_context_t c) +{ + xbt_os_sem_post(c->begin); + xbt_os_sem_wait(c->end); +} + +static void unschedule(xbt_context_t c) +{ + xbt_os_sem_post(c->end); + xbt_os_sem_wait(c->begin); +} + /** \name Functions * \ingroup XBT_context */ @@ -80,19 +88,8 @@ void xbt_context_init(void) xbt_swag_new(xbt_swag_offset(*current_context, hookup)); context_living = xbt_swag_new(xbt_swag_offset(*current_context, hookup)); xbt_swag_insert(init_context, context_living); - -#ifdef CONTEXT_THREADS - /* only used during the creation of the processes */ - creation_mutex = xbt_os_mutex_init(); - creation_cond = xbt_os_cond_init(); - - /* used to schedule/unschedule the processes */ - master_mutex = xbt_os_mutex_init(); - master_cond = xbt_os_cond_init(); - - current_thread_id = xbt_os_thread_self(); - -#else + + #ifndef CONTEXT_THREADS init_context->exception = xbt_new(ex_ctx_t, 1); XBT_CTX_INITIALIZE(init_context->exception); __xbt_ex_ctx = _context_ex_ctx; @@ -117,12 +114,7 @@ void xbt_context_exit(void) } } -#ifdef CONTEXT_THREADS - xbt_os_mutex_destroy(creation_mutex); - xbt_os_cond_destroy(creation_cond); - xbt_os_mutex_destroy(master_mutex); - xbt_os_cond_destroy(master_cond); -#else +#ifndef CONTEXT_THREADS free(init_context->exception); #endif @@ -135,6 +127,7 @@ void xbt_context_exit(void) } + /*******************************/ /* Object creation/destruction */ /*******************************/ @@ -166,8 +159,12 @@ xbt_context_new(const char *name, res->name = xbt_strdup(name); #ifdef CONTEXT_THREADS - res->mutex = xbt_os_mutex_init(); - res->cond = xbt_os_cond_init(); + /* + * initialize the semaphores used to schedule/unschedule + * the process associated to the newly created context + */ + res->begin = xbt_os_sem_init(0,0); + res->end = xbt_os_sem_init(0,0); #else xbt_assert2(getcontext(&(res->uc)) == 0, @@ -219,6 +216,7 @@ xbt_context_new(const char *name, * (same than first case afterward) */ + /* Argument must be stopped first -- runs in maestro context */ static void xbt_context_free(xbt_context_t context) { @@ -244,12 +242,13 @@ static void xbt_context_free(xbt_context_t context) xbt_os_thread_join(context->thread, NULL); - xbt_os_mutex_destroy(context->mutex); - xbt_os_cond_destroy(context->cond); + /* destroy the semaphore used to schedule/unshedule the process */ + xbt_os_sem_destroy(context->begin); + xbt_os_sem_destroy(context->end); context->thread = NULL; - context->mutex = NULL; - context->cond = NULL; + context->begin = NULL; + context->end = NULL; #else if (context->exception) free(context->exception); @@ -270,27 +269,10 @@ static void *__context_wrapper(void *c) #ifdef CONTEXT_THREADS context = (xbt_context_t) c; - context->thread = xbt_os_thread_self(); - - DEBUG3("**[ctx:%p;self:%p]** Lock creation_mutex %p ****", context, - (void *) xbt_os_thread_self(), creation_mutex); - xbt_os_mutex_lock(creation_mutex); - xbt_os_mutex_lock(context->mutex); - - DEBUG4 - ("**[ctx:%p;self:%p]** Releasing the creator (creation_cond %p,%p) ****", - context, (void *) xbt_os_thread_self(), creation_cond, creation_mutex); - xbt_os_cond_signal(creation_cond); - xbt_os_mutex_unlock(creation_mutex); - - DEBUG4("**[ctx:%p;self:%p]** Going to Jail on lock %p and cond %p ****", - context, (void *) xbt_os_thread_self(), context->mutex, - context->cond); - xbt_os_cond_wait(context->cond, context->mutex); + /*context->thread = xbt_os_thread_self();*/ - DEBUG3("**[ctx:%p;self:%p]** Unlocking individual %p ****", context, - (void *) xbt_os_thread_self(), context->mutex); - xbt_os_mutex_unlock(context->mutex); + /* signal its starting to the maestro and wait to start its job*/ + unschedule(context); #endif @@ -302,7 +284,6 @@ static void *__context_wrapper(void *c) xbt_context_stop((context->code) (context->argc, context->argv)); return NULL; } - /** * \param context the context to start * @@ -312,26 +293,11 @@ static void *__context_wrapper(void *c) void xbt_context_start(xbt_context_t context) { #ifdef CONTEXT_THREADS - /* Launch the thread */ - - DEBUG3("**[ctx:%p;self:%p]** Locking creation_mutex %p ****", context, - xbt_os_thread_self(), creation_mutex); - xbt_os_mutex_lock(creation_mutex); - - DEBUG2("**[ctx:%p;self:%p]** Thread create ****", context, - xbt_os_thread_self()); - context->thread = - xbt_os_thread_create(context->name, __context_wrapper, context); - DEBUG3("**[ctx:%p;self:%p]** Thread created : %p ****", context, - xbt_os_thread_self(), context->thread); - - DEBUG4 - ("**[ctx:%p;self:%p]** Going to jail on creation_cond/mutex (%p,%p) ****", - context, xbt_os_thread_self(), creation_cond, creation_mutex); - xbt_os_cond_wait(creation_cond, creation_mutex); - DEBUG3("**[ctx:%p;self:%p]** Unlocking creation %p ****", context, - xbt_os_thread_self(), creation_mutex); - xbt_os_mutex_unlock(creation_mutex); + /* create the process and start it */ + context->thread = xbt_os_thread_create(context->name,__context_wrapper, context); + + /* wait the starting of the newly created process */ + xbt_os_sem_wait(context->end); #else makecontext(&(context->uc), (void (*)(void)) __context_wrapper, 1, context); #endif @@ -354,19 +320,10 @@ static void xbt_context_stop(int retvalue) DEBUG0("Yielding"); #ifdef CONTEXT_THREADS - /* a java thread has called this function - * - update the current context - * - signal the condition of the main thread - * - wait on its condition - * - restore thr current contex - */ - - xbt_os_mutex_lock(master_mutex); - xbt_os_cond_signal(master_cond); - xbt_os_mutex_unlock(master_mutex); - xbt_os_thread_exit(NULL); /* We should provide return value in case other wants it */ - - + /* signal to the maestro that it has finished */ + xbt_os_sem_post(current_context->end); + /* exit*/ + xbt_os_thread_exit(NULL); /* We should provide return value in case other wants it */ #else __xbt_context_yield(current_context); #endif @@ -397,10 +354,6 @@ void xbt_context_empty_trash(void) static void __xbt_context_yield(xbt_context_t context) { -#ifdef CONTEXT_THREADS - xbt_context_t self; -#endif - xbt_assert0(current_context, "You have to call context_init() first."); xbt_assert0(context, "Invalid argument"); @@ -416,48 +369,36 @@ static void __xbt_context_yield(xbt_context_t context) #ifdef CONTEXT_THREADS - self = current_context; - - if (is_main_thread()) { - /* the main thread has called this function - * - update the current context - * - signal the condition of the process to run - * - wait on its condition - * - restore thr current contex - */ - - xbt_os_mutex_lock(master_mutex); - xbt_os_mutex_lock(context->mutex); - - /* update the current context */ - current_context = context; - xbt_os_cond_signal(context->cond); - xbt_os_mutex_unlock(context->mutex); - - xbt_os_cond_wait(master_cond, master_mutex); - xbt_os_mutex_unlock(master_mutex); - /* retore the current context */ - current_context = self; - - } else { - /* a java thread has called this function - * - update the current context - * - signal the condition of the main thread - * - wait on its condition - * - restore thr current contex - */ - - xbt_os_mutex_lock(master_mutex); - xbt_os_mutex_lock(context->mutex); - /* update the current context */ - current_context = context; - xbt_os_cond_signal(master_cond); - xbt_os_mutex_unlock(master_mutex); - xbt_os_cond_wait(context->cond, context->mutex); - xbt_os_mutex_unlock(context->mutex); - /* retore the current context */ - current_context = self; - } + if(current_context != init_context && !context->iwannadie) + {/* it's a process and it doesn't wants to die (xbt_context_yield()) */ + + /* save the current context */ + xbt_context_t self = current_context; + + /* update the current context to this context */ + current_context = context; + + /* yield itself */ + unschedule(context); + + /* restore the current context to the previously saved context */ + current_context = self; + } + else + { /* maestro wants to schedule a process or a process wants to die (xbt_context_schedule() or xbt_context_kill())*/ + + /* save the current context */ + xbt_context_t self = current_context; + + /* update the current context */ + current_context = context; + + /* schedule the process associated with this context */ + schedule(context); + + /* restore the current context to the previously saved context */ + current_context = self; + } #else /* use SUSv2 contexts */ VOIRP(current_context); @@ -502,10 +443,6 @@ static void __xbt_context_yield(xbt_context_t context) xbt_context_stop(1); } - - - - /** * Calling this function makes the current context yield. The context * that scheduled it returns from xbt_context_schedule as if nothing @@ -554,19 +491,9 @@ void xbt_context_kill(xbt_context_t context) } /* Java cruft I'm gonna kill in the next cleanup round */ -void xbt_context_set_jprocess(xbt_context_t context, void *jp) -{ -} -void *xbt_context_get_jprocess(xbt_context_t context) -{ - return NULL; -} -void xbt_context_set_jenv(xbt_context_t context, void *je) -{ -} -void *xbt_context_get_jenv(xbt_context_t context) -{ - return NULL; -} +void xbt_context_set_jprocess(xbt_context_t context, void *jp){} +void* xbt_context_get_jprocess(xbt_context_t context){return NULL;} +void xbt_context_set_jenv(xbt_context_t context,void* je){} +void* xbt_context_get_jenv(xbt_context_t context){return NULL;} /* @} */ diff --git a/src/xbt/context_private.h b/src/xbt/context_private.h index 7c82066c7c..75d378a0d6 100644 --- a/src/xbt/context_private.h +++ b/src/xbt/context_private.h @@ -38,8 +38,8 @@ typedef struct s_xbt_context { #else # ifdef CONTEXT_THREADS xbt_os_thread_t thread; /* a plain dumb thread (portable to posix or windows) */ - xbt_os_cond_t cond; /* the condition used to synchronize the process */ - xbt_os_mutex_t mutex; /* the mutex used to synchronize the process */ + xbt_os_sem_t begin; /* this semaphore is used to schedule/unschedule the process */ + xbt_os_sem_t end; /* this semaphore is used to schedule/unschedule the process */ # else ucontext_t uc; /* the thread that execute the code */ char stack[STACK_SIZE]; @@ -58,9 +58,7 @@ typedef struct s_xbt_context { void *startup_arg; void_f_pvoid_t cleanup_func; void *cleanup_arg; - int iwannadie; /* Set to true by the context when it wants to commit suicide */ - } s_xbt_context_t; diff --git a/src/xbt/xbt_os_thread.c b/src/xbt/xbt_os_thread.c index 4a793e4eec..0405622652 100644 --- a/src/xbt/xbt_os_thread.c +++ b/src/xbt/xbt_os_thread.c @@ -23,7 +23,7 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_sync_os,xbt,"Synchronization mechanism (OS-l /* ********************************* PTHREAD IMPLEMENTATION ************************************ */ #ifdef HAVE_PTHREAD_H #include - +#include typedef struct xbt_os_thread_ { pthread_t t; @@ -93,7 +93,8 @@ static void * wrapper_start_routine(void *s) { if ((errcode=pthread_setspecific(xbt_self_thread_key,t))) THROW0(system_error,errcode, "pthread_setspecific failed for xbt_self_thread_key"); - return (*t->start_routine)(t->param); + + return (*(t->start_routine))(t->param); } xbt_os_thread_t xbt_os_thread_create(const char*name, pvoid_f_pvoid_t start_routine, @@ -286,6 +287,118 @@ void *xbt_os_thread_getparam(void) { return t?t->param:NULL; } +typedef struct xbt_os_sem_ { + sem_t s; + int pshared; + unsigned int value; + const char* name; +}s_xbt_os_sem_t ; + +xbt_os_sem_t +xbt_os_sem_init(int pshared, unsigned int value) +{ + xbt_os_sem_t res = xbt_new(s_xbt_os_sem_t,1); + + if(sem_init(&(res->s),pshared,value) < 0) + THROW1(system_error,errno,"sem_init() failed: %s", + strerror(errno)); + + res->pshared = pshared; + res->value = value; + + return res; +} + +void +xbt_os_sem_wait(xbt_os_sem_t sem) +{ + if(!sem) + THROW1(arg_error,EINVAL,"xbt_os_sem_wait() failed: %s", + strerror(EINVAL)); + + if(sem_wait(&(sem->s)) < 0) + THROW1(system_error,errno,"sem_wait() failed: %s", + strerror(errno)); +} + +void xbt_os_sem_timedwait(xbt_os_sem_t sem,const struct timespec* abs_timeout) +{ + if(!sem) + THROW1(arg_error,EINVAL,"xbt_os_sem_timedwait() failed: %s", + strerror(EINVAL)); + + /* only throw an exception if the global variable errno is different than ETIMEDOUT : + * (the semaphore could not be locked before the specified timeout expired) + */ + if((sem_timedwait(&(sem->s),abs_timeout) < 0) && (ETIMEDOUT != errno)) + THROW1(system_error,errno,"sem_wait() failed: %s", + strerror(errno)); +} + +void +xbt_os_sem_post(xbt_os_sem_t sem) +{ + if(!sem) + THROW1(arg_error,EINVAL,"xbt_os_sem_post() failed: %s", + strerror(EINVAL)); + + if(sem_post(&(sem->s)) < 0) + THROW1(system_error,errno,"sem_post() failed: %s", + strerror(errno)); +} + +void +xbt_os_sem_close(xbt_os_sem_t sem) +{ + if(!sem) + THROW1(arg_error,EINVAL,"xbt_os_sem_close() failed: %s", + strerror(EINVAL)); + + if(sem_close(&(sem->s)) < 0) + THROW1(system_error,errno,"sem_close() failed: %s", + strerror(errno)); +} + +xbt_os_sem_t +xbt_os_sem_open(const char *name, int oflag, mode_t mode, unsigned int value) +{ + sem_t* ps; + xbt_os_sem_t res = xbt_new(s_xbt_os_sem_t,1); + + if(SEM_FAILED == (ps = sem_open(name,oflag, mode, value))) + THROW1(system_error,errno,"sem_open() failed: %s", + strerror(errno)); + + res->s = *ps; + res->value = value; + + return res; +} + +void +xbt_os_sem_destroy(xbt_os_sem_t sem) +{ + if(!sem) + THROW1(arg_error,EINVAL,"xbt_os_sem_destroy() failed: %s", + strerror(EINVAL)); + + if(sem_destroy(&(sem->s)) < 0) + THROW1(system_error,errno,"sem_destroy() failed: %s", + strerror(errno)); +} + +void +xbt_os_sem_get_value(xbt_os_sem_t sem, int* svalue) +{ + if(!sem) + THROW1(arg_error,EINVAL,"xbt_os_sem_getvalue() failed: %s", + strerror(EINVAL)); + + if(sem_getvalue(&(sem->s),svalue) < 0) + THROW1(system_error,errno,"sem_getvalue() failed: %s", + strerror(errno)); +} + /* ********************************* WINDOWS IMPLEMENTATION ************************************ */ #elif defined(WIN32) @@ -298,6 +411,14 @@ typedef struct xbt_os_thread_ { void* param; } s_xbt_os_thread_t ; +/* so we can specify the size of the stack of the threads */ +#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION +#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 +#endif + +/* the default size of the stack of the threads (in bytes)*/ +#define XBT_DEFAULT_THREAD_STACK_SIZE 4096 + /* key to the TLS containing the xbt_os_thread_t structure */ static unsigned long xbt_self_thread_key; @@ -312,11 +433,14 @@ void xbt_os_thread_mod_exit(void) { static DWORD WINAPI wrapper_start_routine(void *s) { xbt_os_thread_t t = (xbt_os_thread_t)s; + void* rv; if(!TlsSetValue(xbt_self_thread_key,t)) THROW0(system_error,(int)GetLastError(),"TlsSetValue of data describing the created thread failed"); - return (DWORD)t->start_routine(t->param); + rv = (*(t->start_routine))(t->param); + + return *((DWORD*)rv); } @@ -329,9 +453,9 @@ xbt_os_thread_t xbt_os_thread_create(const char *name,pvoid_f_pvoid_t start_rout t->start_routine = start_routine ; t->param = param; - t->handle = CreateThread(NULL,0, + t->handle = CreateThread(NULL,XBT_DEFAULT_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)wrapper_start_routine, - t,0,&(t->id)); + t,STACK_SIZE_PARAM_IS_A_RESERVATION,&(t->id)); if(!t->handle) { xbt_free(t); @@ -514,7 +638,56 @@ void xbt_os_cond_wait(xbt_os_cond_t cond, xbt_os_mutex_t mutex) { EnterCriticalSection (& mutex->lock); } void xbt_os_cond_timedwait(xbt_os_cond_t cond, xbt_os_mutex_t mutex, double delay) { - THROW_UNIMPLEMENTED; + + unsigned long wait_result = WAIT_TIMEOUT; + int is_last_waiter; + unsigned long end = (unsigned long)(delay * 1000); + + + if (delay < 0) { + xbt_os_cond_wait(cond,mutex); + } else { + DEBUG3("xbt_cond_timedwait(%p,%p,%ul)",&(cond->events),&(mutex->lock),end); + + /* lock the threads counter and increment it */ + EnterCriticalSection (& cond->waiters_count_lock); + cond->waiters_count++; + LeaveCriticalSection (& cond->waiters_count_lock); + + /* unlock the mutex associate with the condition */ + LeaveCriticalSection (& mutex->lock); + /* wait for a signal (broadcast or no) */ + + wait_result = WaitForMultipleObjects (2, cond->events, FALSE, end); + + switch(wait_result) { + case WAIT_TIMEOUT: + THROW3(timeout_error,GetLastError(),"condition %p (mutex %p) wasn't signaled before timeout (%f)",cond,mutex, delay); + case WAIT_FAILED: + THROW0(system_error,GetLastError(),"WaitForMultipleObjects failed, so we cannot wait on the condition"); + } + + /* we have a signal lock the condition */ + EnterCriticalSection (& cond->waiters_count_lock); + cond->waiters_count--; + + /* it's the last waiter or it's a broadcast ? */ + is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1) && (cond->waiters_count == 0)); + + LeaveCriticalSection (& cond->waiters_count_lock); + + /* yes it's the last waiter or it's a broadcast + * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function + * by the system. + */ + if (is_last_waiter) + if(!ResetEvent (cond->events[BROADCAST])) + THROW0(system_error,0,"ResetEvent failed"); + + /* relock the mutex associated with the condition in accordance with the posix thread specification */ + EnterCriticalSection (& mutex->lock); + } + /*THROW_UNIMPLEMENTED;*/ } void xbt_os_cond_signal(xbt_os_cond_t cond) { @@ -561,4 +734,152 @@ void xbt_os_cond_destroy(xbt_os_cond_t cond){ THROW0(system_error,0,"Error while destroying the condition"); } +typedef struct xbt_os_sem_ { + HANDLE h; + unsigned int value; + const char* name; + CRITICAL_SECTION value_lock; /* protect access to value of the semaphore */ +}s_xbt_os_sem_t ; + +xbt_os_sem_t +xbt_os_sem_init(int pshared, unsigned int value) +{ + xbt_os_sem_t res; + + if(0 != pshared) + THROW1(arg_error,EPERM,"xbt_os_sem_init() failed: %s", + strerror(EPERM)); + + if(value > INT_MAX) + THROW1(arg_error,EINVAL,"xbt_os_sem_init() failed: %s", + strerror(EINVAL)); + + res = (xbt_os_sem_t)xbt_new0(s_xbt_os_sem_t,1); + + if(!(res->h = CreateSemaphore(NULL,value,(long)INT_MAX,NULL))) { + THROW1(system_error,GetLastError(),"CreateSemaphore() failed: %s", + strerror(GetLastError())); + return NULL; + } + + res->value = value; + + InitializeCriticalSection(&(res->value_lock)); + + return res; +} + +void +xbt_os_sem_wait(xbt_os_sem_t sem) +{ + if(!sem) + THROW1(arg_error,EINVAL,"xbt_os_sem_wait() failed: %s", + strerror(EINVAL)); + + /* wait failure */ + if(WAIT_OBJECT_0 != WaitForSingleObject(sem->h,INFINITE)) + THROW1(system_error,GetLastError(),"WaitForSingleObject() failed: %s", + strerror(GetLastError())); + EnterCriticalSection(&(sem->value_lock)); + sem->value--; + LeaveCriticalSection(&(sem->value_lock)); +} + +void xbt_os_sem_timedwait(xbt_os_sem_t sem,const struct timespec* abs_timeout) +{ + long timeout; + struct timeval tv; + + if(!sem) + THROW1(arg_error,EINVAL,"xbt_os_sem_timedwait() failed: %s", + strerror(EINVAL)); + + if(!abs_timeout) + timeout = INFINITE; + else + { + if(gettimeofday(&tv, NULL) < 0) + THROW1(system_error,errno,"gettimeofday() failed: %s", + strerror(errno)); + + timeout = ((long) (abs_timeout->tv_sec - tv.tv_sec) * 1e3 + (long)((abs_timeout->tv_nsec / 1e3) - tv.tv_usec) / 1e3); + } + + switch(WaitForSingleObject(sem->h,timeout)) + { + case WAIT_OBJECT_0: + EnterCriticalSection(&(sem->value_lock)); + sem->value--; + LeaveCriticalSection(&(sem->value_lock)); + return; + + case WAIT_TIMEOUT: + /* it's not an exception : + * (semaphore could not be locked before the specified timeout expired) + */ + return; + + default: + + THROW1(system_error,GetLastError(),"WaitForSingleObject() failed: %s", + strerror(GetLastError())); + } +} + +void +xbt_os_sem_post(xbt_os_sem_t sem) +{ + if(!sem) + THROW1(arg_error,EINVAL,"xbt_os_sem_post() failed: %s", + strerror(EINVAL)); + + if(!ReleaseSemaphore(sem->h,1, NULL)) + THROW1(system_error,GetLastError(),"ReleaseSemaphore() failed: %s", + strerror(GetLastError())); + EnterCriticalSection (&(sem->value_lock)); + sem->value++; + LeaveCriticalSection(&(sem->value_lock)); +} + +xbt_os_sem_t +xbt_os_sem_open(const char *name, int oflag, mode_t mode, unsigned int value) +{ + THROW_UNIMPLEMENTED; +} + +void +xbt_os_sem_close(xbt_os_sem_t sem) +{ + THROW_UNIMPLEMENTED; +} + +void +xbt_os_sem_destroy(xbt_os_sem_t sem) +{ + if(!sem) + THROW1(arg_error,EINVAL,"xbt_os_sem_destroy() failed: %s", + strerror(EINVAL)); + + if(!CloseHandle(sem->h)) + THROW1(system_error,GetLastError(),"CloseHandle() failed: %s", + strerror(GetLastError())); + + DeleteCriticalSection(&(sem->value_lock)); + + xbt_free(sem); + +} + +void +xbt_os_sem_get_value(xbt_os_sem_t sem, int* svalue) +{ + if(!sem) + THROW1(arg_error,EINVAL,"xbt_os_sem_get_value() failed: %s", + strerror(EINVAL)); + + EnterCriticalSection(&(sem->value_lock)); + *svalue = sem->value; + LeaveCriticalSection(&(sem->value_lock)); +} + #endif