summaryrefslogtreecommitdiff
path: root/mutex.c
diff options
context:
space:
mode:
authorrpj <rpj>2002-01-31 06:56:03 +0000
committerrpj <rpj>2002-01-31 06:56:03 +0000
commit75f8ad67d45d48b9cdde5a298083881790c76c73 (patch)
tree0d793e00b40a3292f1fee2b302eb6eccdf15d113 /mutex.c
parent30a1e9738593302fa26e0a668f517bc7f5800190 (diff)
2002-01-27 Ross Johnson <rpj@special.ise.canberra.edu.au>
* 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 <rpj@special.ise.canberra.edu.au> * 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 <rpj@special.ise.canberra.edu.au> * 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.
Diffstat (limited to 'mutex.c')
-rw-r--r--mutex.c702
1 files changed, 498 insertions, 204 deletions
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 <process.h>
+#endif
+#ifndef NEED_FTIME
+#include <sys/timeb.h>
+#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);
}
+