From 75f8ad67d45d48b9cdde5a298083881790c76c73 Mon Sep 17 00:00:00 2001 From: rpj Date: Thu, 31 Jan 2002 06:56:03 +0000 Subject: 2002-01-27 Ross Johnson * mutex.c (pthread_mutex_timedlock): New function suggested by Alexander Terekhov. The logic required to implement this properly came from Alexander, with some collaboration with Thomas Pfaff. (pthread_mutex_unlock): Wrap the waiters check and sema post in a critical section to prevent a race with pthread_mutex_timedlock. (ptw32_timed_semwait): New function; returns a special result if the absolute timeout parameter represents a time already passed when called; used by pthread_mutex_timedwait(). Have deliberately not reused the name "ptw32_sem_timedwait" because they are not the same routine. * condvar.c (ptw32_cond_timedwait): Use the new sem_timedwait() instead of ptw32_sem_timedwait(), which now has a different function. See previous. * implement.h: Remove prototype for ptw32_sem_timedwait. See next. (pthread_mutex_t_): Add critical section element for access to lock_idx during mutex post-timeout processing. * semaphore.h (sem_timedwait): See next. * semaphore.c (sem_timedwait): See next. * private.c (ptw32_sem_timedwait): Move to semaphore.c and rename as sem_timedwait(). 2002-01-18 Ross Johnson * sync.c (pthread_join): Was getting the exit code from the calling thread rather than the joined thread if defined(__MINGW32__) && !defined(__MSVCRT__). 2002-01-15 Ross Johnson * pthread.h: Unless the build explicitly defines __CLEANUP_SEH, __CLEANUP_CXX, or __CLEANUP_C, then the build defaults to __CLEANUP_C style cleanup. This style uses setjmp/longjmp in the cancelation and thread exit implementations and therefore won't do stack unwinding if linked to applications that have it (e.g. C++ apps). This is currently consistent with most/all commercial Unix POSIX threads implementations. * spin.c (pthread_spin_init): Edit renamed function call. * nonportable.c (pthread_num_processors_np): New. (pthread_getprocessors_np): Renamed to ptw32_getprocessors and moved to private.c. * private.c (pthread_getprocessors): Moved here from nonportable.c. * pthread.def (pthread_getprocessors_np): Removed from export list. * rwlock.c (pthread_rwlockattr_init): New. (pthread_rwlockattr_destroy): New. (pthread_rwlockattr_getpshared): New. (pthread_rwlockattr_setpshared): New. --- mutex.c | 702 +++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 498 insertions(+), 204 deletions(-) (limited to 'mutex.c') diff --git a/mutex.c b/mutex.c index d1d7aad..e493b7f 100644 --- a/mutex.c +++ b/mutex.c @@ -26,6 +26,12 @@ * MA 02111-1307, USA */ +#ifndef _UWIN +# include +#endif +#ifndef NEED_FTIME +#include +#endif #include "pthread.h" #include "implement.h" @@ -132,12 +138,11 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) mx->lock_idx = PTW32_MUTEX_LOCK_IDX_INIT; mx->recursive_count = 0; mx->kind = (attr == NULL || *attr == NULL - ? PTHREAD_MUTEX_DEFAULT - : (*attr)->kind); + ? PTHREAD_MUTEX_DEFAULT + : (*attr)->kind); mx->ownerThread = NULL; - mx->wait_sema = CreateSemaphore( NULL, 0, 1, NULL ); - if( NULL == mx->wait_sema ) + if( 0 != sem_init( &mx->wait_sema, 0, 0 )) { result = EAGAIN; } @@ -149,6 +154,7 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) } FAIL0: + InitializeCriticalSection( &mx->wait_cs ); *mutex = mx; return(result); @@ -185,33 +191,34 @@ pthread_mutex_destroy(pthread_mutex_t *mutex) * owner, if the mutex is owned at all. */ if (result == 0 - || mx->ownerThread == (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS - || pthread_equal( mx->ownerThread, pthread_self() ) ) - { - /* - * FIXME!!! - * The mutex isn't held by another thread but we could still - * be too late invalidating the mutex below since another thread - * may alredy have entered mutex_lock and the check for a valid - * *mutex != NULL. - */ - *mutex = NULL; - - result = pthread_mutex_unlock(&mx); - - if (result == 0) - { - CloseHandle( mx->wait_sema ); - free(mx); - } - else - { - /* - * Restore the mutex before we return the error. - */ - *mutex = mx; - } - } + || mx->ownerThread == (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS + || pthread_equal( mx->ownerThread, pthread_self() ) ) + { + /* + * FIXME!!! + * The mutex isn't held by another thread but we could still + * be too late invalidating the mutex below since another thread + * may already have entered mutex_lock and the check for a valid + * *mutex != NULL. + */ + *mutex = NULL; + + result = pthread_mutex_unlock(&mx); + + if (result == 0) + { + (void) sem_destroy( &mx->wait_sema ); + DeleteCriticalSection( &mx->wait_cs ); + free(mx); + } + else + { + /* + * Restore the mutex before we return the error. + */ + *mutex = mx; + } + } } else { @@ -224,23 +231,23 @@ pthread_mutex_destroy(pthread_mutex_t *mutex) * Check again. */ if (*mutex == PTHREAD_MUTEX_INITIALIZER) - { - /* - * This is all we need to do to destroy a statically - * initialised mutex that has not yet been used (initialised). - * If we get to here, another thread - * waiting to initialise this mutex will get an EINVAL. - */ - *mutex = NULL; - } + { + /* + * This is all we need to do to destroy a statically + * initialised mutex that has not yet been used (initialised). + * If we get to here, another thread + * waiting to initialise this mutex will get an EINVAL. + */ + *mutex = NULL; + } else - { - /* - * The mutex has been initialised while we were waiting - * so assume it's in use. - */ - result = EBUSY; - } + { + /* + * The mutex has been initialised while we were waiting + * so assume it's in use. + */ + result = EBUSY; + } LeaveCriticalSection(&ptw32_mutex_test_init_lock); } @@ -258,7 +265,7 @@ pthread_mutexattr_init (pthread_mutexattr_t * attr) * * PARAMETERS * attr - * pointer to an instance of pthread_mutexattr_t + * pointer to an instance of pthread_mutexattr_t * * * DESCRIPTION @@ -266,11 +273,11 @@ pthread_mutexattr_init (pthread_mutexattr_t * attr) * attributes. * * NOTES: - * 1) Used to define mutex types + * 1) Used to define mutex types * * RESULTS - * 0 successfully initialized attr, - * ENOMEM insufficient memory for attr. + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. * * ------------------------------------------------------ */ @@ -293,7 +300,7 @@ pthread_mutexattr_init (pthread_mutexattr_t * attr) *attr = ma; return(result); -} /* pthread_mutexattr_init */ +} /* pthread_mutexattr_init */ int @@ -306,7 +313,7 @@ pthread_mutexattr_destroy (pthread_mutexattr_t * attr) * * PARAMETERS * attr - * pointer to an instance of pthread_mutexattr_t + * pointer to an instance of pthread_mutexattr_t * * * DESCRIPTION @@ -314,11 +321,11 @@ pthread_mutexattr_destroy (pthread_mutexattr_t * attr) * no longer be used. * * NOTES: - * 1) Does not affect mutexes created using 'attr' + * 1) Does not affect mutexes created using 'attr' * * RESULTS - * 0 successfully released attr, - * EINVAL 'attr' is invalid. + * 0 successfully released attr, + * EINVAL 'attr' is invalid. * * ------------------------------------------------------ */ @@ -338,7 +345,7 @@ pthread_mutexattr_destroy (pthread_mutexattr_t * attr) } return(result); -} /* pthread_mutexattr_destroy */ +} /* pthread_mutexattr_destroy */ int @@ -352,16 +359,16 @@ pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr, * * PARAMETERS * attr - * pointer to an instance of pthread_mutexattr_t + * pointer to an instance of pthread_mutexattr_t * * pshared - * will be set to one of: + * will be set to one of: * - * PTHREAD_PROCESS_SHARED - * May be shared if in shared memory + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory * - * PTHREAD_PROCESS_PRIVATE - * Cannot be shared. + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. * * * DESCRIPTION @@ -369,15 +376,15 @@ pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr, * processes if pthread_mutex_t variable is allocated * in memory shared by these processes. * NOTES: - * 1) pshared mutexes MUST be allocated in shared - * memory. - * 2) The following macro is defined if shared mutexes - * are supported: - * _POSIX_THREAD_PROCESS_SHARED + * 1) pshared mutexes MUST be allocated in shared + * memory. + * 2) The following macro is defined if shared mutexes + * are supported: + * _POSIX_THREAD_PROCESS_SHARED * * RESULTS - * 0 successfully retrieved attribute, - * EINVAL 'attr' is invalid, + * 0 successfully retrieved attribute, + * EINVAL 'attr' is invalid, * * ------------------------------------------------------ */ @@ -397,7 +404,7 @@ pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr, return (result); -} /* pthread_mutexattr_getpshared */ +} /* pthread_mutexattr_getpshared */ int @@ -412,16 +419,16 @@ pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, * * PARAMETERS * attr - * pointer to an instance of pthread_mutexattr_t + * pointer to an instance of pthread_mutexattr_t * * pshared - * must be one of: + * must be one of: * - * PTHREAD_PROCESS_SHARED - * May be shared if in shared memory + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory * - * PTHREAD_PROCESS_PRIVATE - * Cannot be shared. + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. * * DESCRIPTION * Mutexes creatd with 'attr' can be shared between @@ -429,17 +436,17 @@ pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, * in memory shared by these processes. * * NOTES: - * 1) pshared mutexes MUST be allocated in shared - * memory. + * 1) pshared mutexes MUST be allocated in shared + * memory. * - * 2) The following macro is defined if shared mutexes - * are supported: - * _POSIX_THREAD_PROCESS_SHARED + * 2) The following macro is defined if shared mutexes + * are supported: + * _POSIX_THREAD_PROCESS_SHARED * * RESULTS - * 0 successfully set attribute, - * EINVAL 'attr' or pshared is invalid, - * ENOSYS PTHREAD_PROCESS_SHARED not supported, + * 0 successfully set attribute, + * EINVAL 'attr' or pshared is invalid, + * ENOSYS PTHREAD_PROCESS_SHARED not supported, * * ------------------------------------------------------ */ @@ -451,24 +458,24 @@ pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, (pshared == PTHREAD_PROCESS_PRIVATE))) { if (pshared == PTHREAD_PROCESS_SHARED) - { + { #if !defined( _POSIX_THREAD_PROCESS_SHARED ) - result = ENOSYS; - pshared = PTHREAD_PROCESS_PRIVATE; + result = ENOSYS; + pshared = PTHREAD_PROCESS_PRIVATE; #else - result = 0; + result = 0; #endif /* _POSIX_THREAD_PROCESS_SHARED */ - } + } else - { - result = 0; - } + { + result = 0; + } (*attr)->pshared = pshared; } @@ -479,7 +486,7 @@ pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, return (result); -} /* pthread_mutexattr_setpshared */ +} /* pthread_mutexattr_setpshared */ int @@ -496,18 +503,18 @@ pthread_mutexattr_settype (pthread_mutexattr_t * attr, * * PARAMETERS * attr - * pointer to an instance of pthread_mutexattr_t + * pointer to an instance of pthread_mutexattr_t * * type - * must be one of: + * must be one of: * - * PTHREAD_MUTEX_DEFAULT + * PTHREAD_MUTEX_DEFAULT * - * PTHREAD_MUTEX_NORMAL + * PTHREAD_MUTEX_NORMAL * - * PTHREAD_MUTEX_ERRORCHECK + * PTHREAD_MUTEX_ERRORCHECK * - * PTHREAD_MUTEX_RECURSIVE + * PTHREAD_MUTEX_RECURSIVE * * DESCRIPTION * The pthread_mutexattr_settype() and @@ -520,45 +527,45 @@ pthread_mutexattr_settype (pthread_mutexattr_t * attr, * mutex attributes. Valid mutex types include: * * PTHREAD_MUTEX_NORMAL - * This type of mutex does not detect deadlock. A - * thread attempting to relock this mutex without - * first unlocking it will deadlock. Attempting to - * unlock a mutex locked by a different thread - * results in undefined behavior. Attempting to - * unlock an unlocked mutex results in undefined - * behavior. + * This type of mutex does not detect deadlock. A + * thread attempting to relock this mutex without + * first unlocking it will deadlock. Attempting to + * unlock a mutex locked by a different thread + * results in undefined behavior. Attempting to + * unlock an unlocked mutex results in undefined + * behavior. * * PTHREAD_MUTEX_ERRORCHECK - * This type of mutex provides error checking. A - * thread attempting to relock this mutex without - * first unlocking it will return with an error. A - * thread attempting to unlock a mutex which another - * thread has locked will return with an error. A - * thread attempting to unlock an unlocked mutex will - * return with an error. + * This type of mutex provides error checking. A + * thread attempting to relock this mutex without + * first unlocking it will return with an error. A + * thread attempting to unlock a mutex which another + * thread has locked will return with an error. A + * thread attempting to unlock an unlocked mutex will + * return with an error. * * PTHREAD_MUTEX_DEFAULT - * Same as PTHREAD_MUTEX_NORMAL. + * Same as PTHREAD_MUTEX_NORMAL. * * PTHREAD_MUTEX_RECURSIVE - * A thread attempting to relock this mutex without - * first unlocking it will succeed in locking the - * mutex. The relocking deadlock which can occur with - * mutexes of type PTHREAD_MUTEX_NORMAL cannot occur - * with this type of mutex. Multiple locks of this - * mutex require the same number of unlocks to - * release the mutex before another thread can - * acquire the mutex. A thread attempting to unlock a - * mutex which another thread has locked will return - * with an error. A thread attempting to unlock an - * unlocked mutex will return with an error. This - * type of mutex is only supported for mutexes whose - * process shared attribute is - * PTHREAD_PROCESS_PRIVATE. + * A thread attempting to relock this mutex without + * first unlocking it will succeed in locking the + * mutex. The relocking deadlock which can occur with + * mutexes of type PTHREAD_MUTEX_NORMAL cannot occur + * with this type of mutex. Multiple locks of this + * mutex require the same number of unlocks to + * release the mutex before another thread can + * acquire the mutex. A thread attempting to unlock a + * mutex which another thread has locked will return + * with an error. A thread attempting to unlock an + * unlocked mutex will return with an error. This + * type of mutex is only supported for mutexes whose + * process shared attribute is + * PTHREAD_PROCESS_PRIVATE. * * RESULTS - * 0 successfully set attribute, - * EINVAL 'attr' or 'type' is invalid, + * 0 successfully set attribute, + * EINVAL 'attr' or 'type' is invalid, * * ------------------------------------------------------ */ @@ -568,16 +575,16 @@ pthread_mutexattr_settype (pthread_mutexattr_t * attr, if ((attr != NULL && *attr != NULL)) { switch (kind) - { - case PTHREAD_MUTEX_FAST_NP: - case PTHREAD_MUTEX_RECURSIVE_NP: - case PTHREAD_MUTEX_ERRORCHECK_NP: - (*attr)->kind = kind; - break; - default: - result = EINVAL; - break; - } + { + case PTHREAD_MUTEX_FAST_NP: + case PTHREAD_MUTEX_RECURSIVE_NP: + case PTHREAD_MUTEX_ERRORCHECK_NP: + (*attr)->kind = kind; + break; + default: + result = EINVAL; + break; + } } else { @@ -585,12 +592,12 @@ pthread_mutexattr_settype (pthread_mutexattr_t * attr, } return (result); -} /* pthread_mutexattr_settype */ +} /* pthread_mutexattr_settype */ int pthread_mutexattr_gettype (pthread_mutexattr_t * attr, - int *kind) + int *kind) { int result = 0; @@ -607,6 +614,155 @@ pthread_mutexattr_gettype (pthread_mutexattr_t * attr, } +static INLINE int +ptw32_timed_semwait (sem_t * sem, const struct timespec * abstime) + /* + * ------------------------------------------------------ + * DESCRIPTION + * This function waits on a POSIX semaphore. If the + * semaphore value is greater than zero, it decreases + * its value by one. If the semaphore value is zero, then + * the calling thread (or process) is blocked until it can + * successfully decrease the value or until abstime. + * If abstime has passed when this routine is called then + * it returns a result to indicate this. + * + * If 'abstime' is a NULL pointer then this function will + * block until it can successfully decrease the value or + * until interrupted by a signal. + * + * RESULTS + * 2 abstime has passed already + * 1 abstime timed out while waiting + * 0 successfully decreased semaphore, + * -1 failed, error in errno. + * ERRNO + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + +#ifdef NEED_FTIME + + struct timespec currSysTime; + +#else /* NEED_FTIME */ + + struct _timeb currSysTime; + +#endif /* NEED_FTIME */ + + const DWORD NANOSEC_PER_MILLISEC = 1000000; + const DWORD MILLISEC_PER_SEC = 1000; + DWORD milliseconds; + DWORD status; + + if (sem == NULL) + { + result = EINVAL; + } + else + { + if (abstime == NULL) + { + milliseconds = INFINITE; + } + else + { + /* + * Calculate timeout as milliseconds from current system time. + */ + + /* get current system time */ + +#ifdef NEED_FTIME + + { + FILETIME ft; + SYSTEMTIME st; + + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + /* + * GetSystemTimeAsFileTime(&ft); would be faster, + * but it does not exist on WinCE + */ + + filetime_to_timespec(&ft, &currSysTime); + } + + /* + * subtract current system time from abstime + */ + milliseconds = (abstime->tv_sec - currSysTime.tv_sec) * MILLISEC_PER_SEC; + milliseconds += ((abstime->tv_nsec - currSysTime.tv_nsec) + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC; + +#else /* NEED_FTIME */ + _ftime(&currSysTime); + + /* + * subtract current system time from abstime + */ + milliseconds = (abstime->tv_sec - currSysTime.time) * MILLISEC_PER_SEC; + milliseconds += ((abstime->tv_nsec + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC) - + currSysTime.millitm; + +#endif /* NEED_FTIME */ + + + if (((int) milliseconds) < 0) + { + return 2; + } + } + +#ifdef NEED_SEM + + status = WaitForSingleObject( (*sem)->event, milliseconds ); + +#else /* NEED_SEM */ + + status = WaitForSingleObject( (*sem)->sem, milliseconds ); + +#endif + + if (status == WAIT_OBJECT_0) + { + +#ifdef NEED_SEM + + ptw32_decrease_semaphore(sem); + +#endif /* NEED_SEM */ + + return 0; + } + else if (status == WAIT_TIMEOUT) + { + return 1; + } + else + { + result = EINVAL; + } + } + + if (result != 0) + { + errno = result; + return -1; + } + + return 0; + +} /* ptw32_timed_semwait */ + + int pthread_mutex_lock(pthread_mutex_t *mutex) { @@ -628,9 +784,9 @@ pthread_mutex_lock(pthread_mutex_t *mutex) if (*mutex == PTHREAD_MUTEX_INITIALIZER) { if ((result = ptw32_mutex_check_need_init(mutex)) != 0) - { - return(result); - } + { + return(result); + } } mx = *mutex; @@ -639,38 +795,169 @@ pthread_mutex_lock(pthread_mutex_t *mutex) { mx->recursive_count = 1; mx->ownerThread = (mx->kind != PTHREAD_MUTEX_FAST_NP - ? pthread_self() - : (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS); + ? pthread_self() + : (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS); } else { if( mx->kind != PTHREAD_MUTEX_FAST_NP && - pthread_equal( mx->ownerThread, pthread_self() ) ) + pthread_equal( mx->ownerThread, pthread_self() ) ) { - (void) InterlockedDecrement( &mx->lock_idx ); - - if( mx->kind == PTHREAD_MUTEX_RECURSIVE_NP ) - { - mx->recursive_count++; - } - else - { - result = EDEADLK; - } - } + (void) InterlockedDecrement( &mx->lock_idx ); + + if( mx->kind == PTHREAD_MUTEX_RECURSIVE_NP ) + { + mx->recursive_count++; + } + else + { + result = EDEADLK; + } + } else - { - WaitForSingleObject( mx->wait_sema, INFINITE ); - mx->recursive_count = 1; - mx->ownerThread = (mx->kind != PTHREAD_MUTEX_FAST_NP - ? pthread_self() - : (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS); - } + { + if ((result = sem_wait( &mx->wait_sema )) == 0) + { + mx->recursive_count = 1; + mx->ownerThread = (mx->kind != PTHREAD_MUTEX_FAST_NP + ? pthread_self() + : (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS); + } + } } return(result); } + +int +pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime) +{ + int result = 0; + pthread_mutex_t mx; + + + if (mutex == NULL || *mutex == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static mutex. We check + * again inside the guarded section of ptw32_mutex_check_need_init() + * to avoid race conditions. + */ + if (*mutex == PTHREAD_MUTEX_INITIALIZER) + { + if ((result = ptw32_mutex_check_need_init(mutex)) != 0) + { + return(result); + } + } + + mx = *mutex; + + if( 0 == InterlockedIncrement( &mx->lock_idx ) ) + { + mx->recursive_count = 1; + mx->ownerThread = (mx->kind != PTHREAD_MUTEX_FAST_NP + ? pthread_self() + : (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS); + } + else + { + if( mx->kind != PTHREAD_MUTEX_FAST_NP && + pthread_equal( mx->ownerThread, pthread_self() ) ) + { + (void) InterlockedDecrement( &mx->lock_idx ); + + if( mx->kind == PTHREAD_MUTEX_RECURSIVE_NP ) + { + mx->recursive_count++; + } + else + { + result = EDEADLK; + } + } + else + { + if (abstime == NULL) + { + result = EINVAL; + } + else + { + switch (ptw32_timed_semwait( &mx->wait_sema, abstime )) + { + case 0: /* We got the mutex. */ + { + mx->recursive_count = 1; + mx->ownerThread = (mx->kind != PTHREAD_MUTEX_FAST_NP + ? pthread_self() + : (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS); + break; + } + case 1: /* Timedout, try a second grab. */ + { + EnterCriticalSection(&mx->wait_cs); + + /* + * If we timeout, it is up to us to adjust lock_idx to say + * we're no longer waiting. If the mutex was also unlocked + * while we were timing out, and we simply return ETIMEDOUT, + * then wait_sema would be left in a state that is not consistent + * with the state of lock_idx. + * + * We must check to see if wait_sema has just been posted + * but we can't just call sem_getvalue - we must compete for + * the semaphore using sem_trywait(), otherwise we would need + * additional critical sections elsewhere, which would make the + * logic too inefficient. + * + * If sem_trywait returns EAGAIN then either wait_sema + * was given directly to another waiting thread or + * another thread has called sem_*wait() before us and + * taken the lock. Then we MUST decrement lock_idx and return + * ETIMEDOUT. + * + * Otherwise we MUST return success (because we have effectively + * acquired the lock that would have been ours had we not + * timed out), and NOT decrement lock_idx. + * + * We can almost guarrantee that EAGAIN is the only + * possible error, so no need to test errno. + */ + + if (-1 == sem_trywait( &mx->wait_sema )) + { + (void) InterlockedDecrement( &mx->lock_idx ); + result = ETIMEDOUT; + } + + LeaveCriticalSection(&mx->wait_cs); + break; + } + case 2: /* abstime had passed before we started to wait. */ + { + result = ETIMEDOUT; + break; + } + default: + { + result = errno; + break; + } + } + } + } + } + + return(result); +} + + int pthread_mutex_unlock(pthread_mutex_t *mutex) { @@ -692,19 +979,25 @@ pthread_mutex_unlock(pthread_mutex_t *mutex) if (mx != PTHREAD_MUTEX_INITIALIZER) { if (mx->ownerThread == (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS - || pthread_equal(mx->ownerThread, pthread_self())) + || pthread_equal(mx->ownerThread, pthread_self())) { - if( mx->kind != PTHREAD_MUTEX_RECURSIVE_NP - || 0 == --mx->recursive_count ) + if( mx->kind != PTHREAD_MUTEX_RECURSIVE_NP + || 0 == --mx->recursive_count ) { mx->ownerThread = NULL; - - if( InterlockedDecrement( &mx->lock_idx ) >= 0 ) - { - /* Someone is waiting on that mutex */ - ReleaseSemaphore( mx->wait_sema, 1, NULL ); - } - } + EnterCriticalSection( &mx->wait_cs ); + + if( InterlockedDecrement( &mx->lock_idx ) >= 0 ) + { + /* Someone is waiting on that mutex */ + if (sem_post( &mx->wait_sema ) != 0) + { + result = errno; + } + } + + LeaveCriticalSection( &mx->wait_cs ); + } } else { @@ -746,36 +1039,37 @@ pthread_mutex_trylock(pthread_mutex_t *mutex) if (result == 0) { if ( (PTW32_INTERLOCKED_LONG) PTW32_MUTEX_LOCK_IDX_INIT == - ptw32_interlocked_compare_exchange((PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, - (PTW32_INTERLOCKED_LONG) 0, - (PTW32_INTERLOCKED_LONG) PTW32_MUTEX_LOCK_IDX_INIT)) - { - mx->recursive_count = 1; - mx->ownerThread = (mx->kind != PTHREAD_MUTEX_FAST_NP - ? pthread_self() - : (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS); - } + ptw32_interlocked_compare_exchange((PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 0, + (PTW32_INTERLOCKED_LONG) PTW32_MUTEX_LOCK_IDX_INIT)) + { + mx->recursive_count = 1; + mx->ownerThread = (mx->kind != PTHREAD_MUTEX_FAST_NP + ? pthread_self() + : (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS); + } else - { - if( mx->kind != PTHREAD_MUTEX_FAST_NP && - pthread_equal( mx->ownerThread, pthread_self() ) ) - { - if( mx->kind == PTHREAD_MUTEX_RECURSIVE_NP ) - { - mx->recursive_count++; - } - else - { - result = EDEADLK; - } - } - else - { - result = EBUSY; - } - } + { + if( mx->kind != PTHREAD_MUTEX_FAST_NP && + pthread_equal( mx->ownerThread, pthread_self() ) ) + { + if( mx->kind == PTHREAD_MUTEX_RECURSIVE_NP ) + { + mx->recursive_count++; + } + else + { + result = EDEADLK; + } + } + else + { + result = EBUSY; + } + } } return(result); } + -- cgit v1.2.3