summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrpj <rpj>1999-01-20 00:01:23 +0000
committerrpj <rpj>1999-01-20 00:01:23 +0000
commit1f803d2545ae17d35ad40f3f2969b2af7a6382b2 (patch)
tree7fd1af9f7c52e49e290849dd14d91e738b8ccaca
parent20f77eda55f874b939719ac0abda4405ecd20bf8 (diff)
Wed Jan 20 09:31:28 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
* pthread.h (pthread_mutexattr_t): Changed to a pointer. * mutex.c (pthread_mutex_init): Conditionally create Win32 mutex - from John Bossom's implementation. (pthread_mutex_destroy): Conditionally close Win32 mutex - from John Bossom's implementation. (pthread_mutexattr_init): Replaced by John Bossom's version. (pthread_mutexattr_destroy): Ditto. (pthread_mutexattr_getpshared): New function from John Bossom's implementation. (pthread_mutexattr_setpshared): New function from John Bossom's implementation. Tue Jan 19 18:27:42 1999 Ross Johnson <rpj@swan.canberra.edu.au> * pthread.h (pthreadCancelableTimedWait): New prototype. (pthreadCancelableWait): Remove second argument. * misc.c (CancelableWait): New static function is pthreadCancelableWait() renamed. (pthreadCancelableWait): Now just calls CancelableWait() with INFINITE timeout. (pthreadCancelableTimedWait): Just calls CancelableWait() with passed in timeout. * private.c (_pthread_sem_timedwait): 'abstime' arg really is absolute time. Calculate relative time to wait from current time before passing timeout to new routine pthreadCancelableTimedWait(). - Scott Lightner <scott@curriculum.com> Tue Jan 19 10:27:39 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au> * pthread.h (pthread_mutexattr_setforcecs_np): New prototype. * mutex.c (pthread_mutexattr_init): Init 'pshared' and 'forcecs' attributes to 0. (pthread_mutexattr_setforcecs_np): New function (not portable). * pthread.h (pthread_mutex_t): Add 'mutex' element. Set to NULL in PTHREAD_MUTEX_INITIALIZER. The pthread_mutex_*() routines will try to optimise performance by choosing either mutexes or critical sections as the basis for pthread mutexes for each indevidual mutex. (pthread_mutexattr_t_): Add 'forcecs' element. Some applications may choose to force use of critical sections if they know that:- the mutex is PROCESS_PRIVATE and, either the OS supports TryEnterCriticalSection() or pthread_mutex_trylock() will never be called on the mutex. This attribute will be setable via a non-portable routine. Note: We don't yet support PROCESS_SHARED mutexes, so the implementation as it stands will default to Win32 mutexes only if the OS doesn't support TryEnterCriticalSection. On Win9x, and early versions of NT 'forcecs' will need to be set in order to get critical section based mutexes. Sun Jan 17 12:01:26 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au> * pthread.h (PTHREAD_MUTEX_INITIALIZER): Init new 'staticinit' value to '1' and existing 'valid' value to '1'. * global.c (_pthread_mutex_test_init_lock): Add. * implement.h (_pthread_mutex_test_init_lock.): Add extern. * private.c (_pthread_processInitialize): Init critical section for global lock used by _mutex_check_need_init(). (_pthread_processTerminate): Ditto (:s/Init/Destroy/). * dll.c (dllMain): Move call to FreeLibrary() so that it is only called once when the process detaches. * mutex.c (_mutex_check_need_init): New static function to test and init PTHREAD_MUTEX_INITIALIZER mutexes. Provides serialised access to the internal state of the uninitialised static mutex. Called from pthread_mutex_trylock() and pthread_mutex_lock() which do a quick unguarded test to check if _mutex_check_need_init() needs to be called. This is safe as the test is conservative and is repeated inside the guarded section of _mutex_check_need_init(). Thus in all calls except the first calls to lock static mutexes, the additional overhead to lock any mutex is a single memory fetch and test for zero. * pthread.h (pthread_mutex_t_): Add 'staticinit' member. Mutexes initialised by PTHREAD_MUTEX_INITIALIZER aren't really initialised until the first attempt to lock it. Using the 'valid' flag (which flags the mutex as destroyed or not) to record this information would be messy. It is possible for a statically initialised mutex such as this to be destroyed before ever being used. * mutex.c (pthread_mutex_trylock): Call _mutex_check_need_init() to test/init PTHREAD_MUTEX_INITIALIZER mutexes. (pthread_mutex_lock): Ditto. (pthread_mutex_unlock): Add check to ensure we don't try to unlock an unitialised static mutex. (pthread_mutex_destroy): Add check to ensure we don't try to delete a critical section that we never created. Allows us to destroy a static mutex that has never been locked (and hence initialised). (pthread_mutex_init): Set 'staticinit' flag to 0 for the new mutex.
-rw-r--r--ChangeLog87
-rw-r--r--dll.c13
-rw-r--r--global.c7
-rw-r--r--implement.h5
-rw-r--r--mutex.c508
-rw-r--r--private.c14
-rw-r--r--pthread.h20
-rw-r--r--tests/eyal1.c1
8 files changed, 613 insertions, 42 deletions
diff --git a/ChangeLog b/ChangeLog
index fde297e..9460c56 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+Wed Jan 20 09:31:28 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h (pthread_mutexattr_t): Changed to a pointer.
+
+ * mutex.c (pthread_mutex_init): Conditionally create Win32 mutex
+ - from John Bossom's implementation.
+ (pthread_mutex_destroy): Conditionally close Win32 mutex
+ - from John Bossom's implementation.
+ (pthread_mutexattr_init): Replaced by John Bossom's version.
+ (pthread_mutexattr_destroy): Ditto.
+ (pthread_mutexattr_getpshared): New function from John Bossom's
+ implementation.
+ (pthread_mutexattr_setpshared): New function from John Bossom's
+ implementation.
+
Tue Jan 19 18:27:42 1999 Ross Johnson <rpj@swan.canberra.edu.au>
* pthread.h (pthreadCancelableTimedWait): New prototype.
@@ -16,6 +31,78 @@ Tue Jan 19 18:27:42 1999 Ross Johnson <rpj@swan.canberra.edu.au>
pthreadCancelableTimedWait().
- Scott Lightner <scott@curriculum.com>
+Tue Jan 19 10:27:39 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h (pthread_mutexattr_setforcecs_np): New prototype.
+
+ * mutex.c (pthread_mutexattr_init): Init 'pshared' and 'forcecs'
+ attributes to 0.
+ (pthread_mutexattr_setforcecs_np): New function (not portable).
+
+ * pthread.h (pthread_mutex_t):
+ Add 'mutex' element. Set to NULL in PTHREAD_MUTEX_INITIALIZER.
+ The pthread_mutex_*() routines will try to optimise performance
+ by choosing either mutexes or critical sections as the basis
+ for pthread mutexes for each indevidual mutex.
+ (pthread_mutexattr_t_): Add 'forcecs' element.
+ Some applications may choose to force use of critical sections
+ if they know that:-
+ the mutex is PROCESS_PRIVATE and,
+ either the OS supports TryEnterCriticalSection() or
+ pthread_mutex_trylock() will never be called on the mutex.
+ This attribute will be setable via a non-portable routine.
+
+ Note: We don't yet support PROCESS_SHARED mutexes, so the
+ implementation as it stands will default to Win32 mutexes only if
+ the OS doesn't support TryEnterCriticalSection. On Win9x, and early
+ versions of NT 'forcecs' will need to be set in order to get
+ critical section based mutexes.
+
+Sun Jan 17 12:01:26 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h (PTHREAD_MUTEX_INITIALIZER): Init new 'staticinit'
+ value to '1' and existing 'valid' value to '1'.
+
+ * global.c (_pthread_mutex_test_init_lock): Add.
+
+ * implement.h (_pthread_mutex_test_init_lock.): Add extern.
+
+ * private.c (_pthread_processInitialize): Init critical section for
+ global lock used by _mutex_check_need_init().
+ (_pthread_processTerminate): Ditto (:s/Init/Destroy/).
+
+ * dll.c (dllMain): Move call to FreeLibrary() so that it is only
+ called once when the process detaches.
+
+ * mutex.c (_mutex_check_need_init): New static function to test
+ and init PTHREAD_MUTEX_INITIALIZER mutexes. Provides serialised
+ access to the internal state of the uninitialised static mutex.
+ Called from pthread_mutex_trylock() and pthread_mutex_lock() which
+ do a quick unguarded test to check if _mutex_check_need_init()
+ needs to be called. This is safe as the test is conservative
+ and is repeated inside the guarded section of
+ _mutex_check_need_init(). Thus in all calls except the first
+ calls to lock static mutexes, the additional overhead to lock any
+ mutex is a single memory fetch and test for zero.
+
+ * pthread.h (pthread_mutex_t_): Add 'staticinit' member. Mutexes
+ initialised by PTHREAD_MUTEX_INITIALIZER aren't really initialised
+ until the first attempt to lock it. Using the 'valid'
+ flag (which flags the mutex as destroyed or not) to record this
+ information would be messy. It is possible for a statically
+ initialised mutex such as this to be destroyed before ever being
+ used.
+
+ * mutex.c (pthread_mutex_trylock): Call _mutex_check_need_init()
+ to test/init PTHREAD_MUTEX_INITIALIZER mutexes.
+ (pthread_mutex_lock): Ditto.
+ (pthread_mutex_unlock): Add check to ensure we don't try to unlock
+ an unitialised static mutex.
+ (pthread_mutex_destroy): Add check to ensure we don't try to delete
+ a critical section that we never created. Allows us to destroy
+ a static mutex that has never been locked (and hence initialised).
+ (pthread_mutex_init): Set 'staticinit' flag to 0 for the new mutex.
+
Sun Jan 17 12:01:26 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
* private.c (_pthread_sem_timedwait): Move from semaphore.c.
diff --git a/dll.c b/dll.c
index d26f8fd..f2b3505 100644
--- a/dll.c
+++ b/dll.c
@@ -10,12 +10,17 @@
#include "implement.h"
-/* Function pointer to TryEnterCriticalSection if it exists; otherwise NULL */
+/*
+ * Function pointer to TryEnterCriticalSection if it exists; otherwise NULL
+ */
BOOL (WINAPI *_pthread_try_enter_critical_section)(LPCRITICAL_SECTION) = NULL;
-/* Handle to kernel32.dll */
+/*
+ * Handle to kernel32.dll
+ */
static HINSTANCE _pthread_h_kernel32;
+
#ifdef _MSC_VER
/*
* lpvReserved yields an unreferenced formal parameter;
@@ -89,11 +94,11 @@ DllMain (
* The DLL is being unmapped into the process's address space
*/
_pthread_processTerminate ();
+
+ (void) FreeLibrary(_pthread_h_kernel32);
}
}
- (void) FreeLibrary(_pthread_h_kernel32);
-
result = TRUE;
}
break;
diff --git a/global.c b/global.c
index 56a26f3..a8bd69a 100644
--- a/global.c
+++ b/global.c
@@ -14,4 +14,11 @@ int _pthread_processInitialized = FALSE;
pthread_key_t _pthread_selfThreadKey = NULL;
pthread_key_t _pthread_cleanupKey = NULL;
+/*
+ * Global lock for testing internal state of PTHREAD_MUTEX_INITIALIZER
+ * created mutexes.
+ */
+CRITICAL_SECTION _pthread_mutex_test_init_lock;
+
+
diff --git a/implement.h b/implement.h
index be71b7e..f897033 100644
--- a/implement.h
+++ b/implement.h
@@ -135,6 +135,7 @@ extern BOOL (WINAPI *_pthread_try_enter_critical_section)(LPCRITICAL_SECTION);
extern int _pthread_processInitialized;
extern pthread_key_t _pthread_selfThreadKey;
extern pthread_key_t _pthread_cleanupKey;
+extern CRITICAL_SECTION _pthread_mutex_test_init_lock;
#ifdef __cplusplus
@@ -183,7 +184,8 @@ int _pthread_sem_timedwait (sem_t * sem, const struct timespec * abstime);
*/
#if defined(__CYGWIN32__) || defined(__CYGWIN__)
-/* Macro uses args so we can cast start_proc to LPTHREAD_START_ROUTINE
+/*
+ * Macro uses args so we can cast start_proc to LPTHREAD_START_ROUTINE
* in order to avoid warnings because of return type
*/
@@ -206,3 +208,4 @@ int _pthread_sem_timedwait (sem_t * sem, const struct timespec * abstime);
#endif /* _IMPLEMENT_H */
+
diff --git a/mutex.c b/mutex.c
index aabee9e..b800512 100644
--- a/mutex.c
+++ b/mutex.c
@@ -10,85 +10,505 @@
#include "pthread.h"
#include "implement.h"
+
+static int
+_mutex_check_need_init(pthread_mutex_t *mutex)
+{
+ int result = 0;
+
+ /*
+ * The following guarded test is specifically for statically
+ * initialised mutexes (via PTHREAD_MUTEX_INITIALIZER).
+ *
+ * Note that by not providing this synchronisation we risk
+ * introducing race conditions into applications which are
+ * correctly written.
+ *
+ * Approach
+ * --------
+ * We know that static mutexes will not be PROCESS_SHARED
+ * so we can serialise access to internal state using
+ * Win32 Critical Sections rather than Win32 Mutexes.
+ *
+ * We still have a problem in that we would like a per-mutex
+ * lock, but attempting to create one will again lead
+ * to a race condition. We are forced to use a global
+ * lock in this instance.
+ *
+ * If using a single global lock slows applications down too much,
+ * multiple global locks could be created and hashed on some random
+ * value associated with each mutex, the pointer perhaps. At a guess,
+ * a good value for the optimal number of global locks might be
+ * the number of processors + 1.
+ *
+ * We need to maintain the following per-mutex state independently:
+ * - mutex staticinit (true iff static mutex and still
+ * needs to be initialised)
+ * - mutex valid (false iff mutex has been destroyed)
+ *
+ * For example, a mutex initialised by PTHREAD_MUTEX_INITIALIZER
+ * in this implementation will be valid but uninitialised until the thread
+ * attempts to lock it. It can also be destroyed (made invalid) before
+ * ever being locked.
+ */
+ EnterCriticalSection(&_pthread_mutex_test_init_lock);
+
+ /*
+ * We got here because staticinit tested true.
+ * Check staticinit again inside the critical section
+ * and only initialise if the mutex is valid (not been destroyed).
+ * If a static mutex has been destroyed, the application can
+ * re-initialise it only by calling pthread_mutex_init()
+ * explicitly.
+ */
+ if (mutex->staticinit && mutex->valid)
+ {
+ result = pthread_mutex_init(mutex, NULL);
+ }
+
+ LeaveCriticalSection(&_pthread_mutex_test_init_lock);
+
+ return(result);
+}
+
int
pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
{
+ int result = 0;
+
if (mutex == NULL)
{
return EINVAL;
}
- /* Create a critical section. */
- InitializeCriticalSection(&mutex->cs);
+ mutex->mutex = 0;
- /* Mark as valid. */
- mutex->valid = 1;
+ /*
+ * Assuming any race condition here is harmless.
+ */
+ if (mutex->valid && !mutex->staticinit)
+ {
+ return EBUSY;
+ }
- return 0;
+ if (attr != NULL
+ && *attr != NULL
+ && (*attr)->pshared == PTHREAD_PROCESS_SHARED
+ )
+ {
+ /*
+ * Creating mutex that can be shared between
+ * processes.
+ */
+#if _POSIX_THREAD_PROCESS_SHARED
+
+ /*
+ * Not implemented yet.
+ */
+
+#error ERROR [__FILE__, line __LINE__]: Process shared mutexes are not supported yet.
+
+ mutex->mutex = CreateMutex (
+ NULL,
+ FALSE,
+ ????);
+ result = (mutex->mutex == 0) ? EAGAIN : 0;
+
+#else
+
+ result = ENOSYS;
+
+#endif /* _POSIX_THREAD_PROCESS_SHARED */
+ }
+ else
+ {
+ if (_pthread_try_enter_critical_section != NULL
+ || (attr != NULL
+ && *attr != NULL
+ && (*attr)->forcecs == 1)
+ )
+ {
+ /*
+ * Create a critical section.
+ */
+ InitializeCriticalSection(&mutex->cs);
+ }
+ else
+ {
+ /*
+ * Create a mutex that can only be used within the
+ * current process
+ */
+ mutex->mutex = CreateMutex (NULL,
+ FALSE,
+ NULL);
+ result = (mutex->mutex == 0) ? EAGAIN : 0;
+ }
+ }
+
+ if (result == 0)
+ {
+ mutex->staticinit = 0;
+
+ /* Mark as valid. */
+ mutex->valid = 1;
+ }
+
+ return(result);
}
int
pthread_mutex_destroy(pthread_mutex_t *mutex)
{
+ int result = 0;
+
if (mutex == NULL)
{
return EINVAL;
}
- DeleteCriticalSection(&mutex->cs);
-
- /* Mark as invalid. */
- mutex->valid = 0;
+ /*
+ * Check to see if we have something to delete.
+ */
+ if (!mutex->staticinit)
+ {
+ if (mutex->mutex == 0)
+ {
+ DeleteCriticalSection(&mutex->cs);
+ }
+ else
+ {
+ result = (CloseHandle (mutex->mutex) ? 0 : EINVAL);
+ }
+ }
- return 0;
+ if (result == 0)
+ {
+ mutex->mutex = 0;
+
+ /* Mark as invalid. */
+ mutex->valid = 0;
+ }
+
+ return(result);
}
int
-pthread_mutexattr_init(pthread_mutexattr_t *attr)
+pthread_mutexattr_init (pthread_mutexattr_t * attr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Initializes a mutex attributes object with default
+ * attributes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_mutexattr_t
+ *
+ *
+ * DESCRIPTION
+ * Initializes a mutex attributes object with default
+ * attributes.
+ *
+ * NOTES:
+ * 1) Used to define mutex types
+ *
+ * RESULTS
+ * 0 successfully initialized attr,
+ * ENOMEM insufficient memory for attr.
+ *
+ * ------------------------------------------------------
+ */
+{
+ pthread_mutexattr_t attr_result;
+ int result = 0;
+
+ attr_result = calloc (1, sizeof (*attr_result));
+
+ result = (attr_result == NULL)
+ ? ENOMEM
+ : 0;
+
+ *attr = attr_result;
+
+ return (result);
+
+} /* pthread_mutexattr_init */
+
+
+int
+pthread_mutexattr_destroy (pthread_mutexattr_t * attr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Destroys a mutex attributes object. The object can
+ * no longer be used.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_mutexattr_t
+ *
+ *
+ * DESCRIPTION
+ * Destroys a mutex attributes object. The object can
+ * no longer be used.
+ *
+ * NOTES:
+ * 1) Does not affect mutexes created using 'attr'
+ *
+ * RESULTS
+ * 0 successfully released attr,
+ * EINVAL 'attr' is invalid.
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+
+ if (attr == NULL || *attr == NULL)
+ {
+ result = EINVAL;
+
+ }
+ else
+ {
+ free (*attr);
+
+ *attr = NULL;
+ result = 0;
+ }
+
+ return (result);
+
+} /* pthread_mutexattr_destroy */
+
+
+int
+pthread_mutexattr_setforcecs_np(pthread_mutexattr_t *attr,
+ int forcecs)
{
- if (attr == NULL)
+ if (attr == NULL || *attr == NULL)
{
/* This is disallowed. */
return EINVAL;
}
- /* None of the optional attributes are supported yet. */
+ (*attr)->forcecs = forcecs;
+
return 0;
}
+
int
-pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
+pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr,
+ int *pshared)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Determine whether mutexes created with 'attr' can be
+ * shared between processes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_mutexattr_t
+ *
+ * pshared
+ * will be set to one of:
+ *
+ * PTHREAD_PROCESS_SHARED
+ * May be shared if in shared memory
+ *
+ * PTHREAD_PROCESS_PRIVATE
+ * Cannot be shared.
+ *
+ *
+ * DESCRIPTION
+ * Mutexes creatd with 'attr' can be shared between
+ * 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
+ *
+ * RESULTS
+ * 0 successfully retrieved attribute,
+ * EINVAL 'attr' is invalid,
+ *
+ * ------------------------------------------------------
+ */
{
- /* Nothing to do. */
- return 0;
-}
+ int result;
+
+ if ((attr != NULL && *attr != NULL) &&
+ (pshared != NULL))
+ {
+ *pshared = (*attr)->pshared;
+ result = 0;
+ }
+ else
+ {
+ *pshared = PTHREAD_PROCESS_PRIVATE;
+ result = EINVAL;
+ }
+
+ return (result);
+
+} /* pthread_mutexattr_getpshared */
+
+
+int
+pthread_mutexattr_setpshared (pthread_mutexattr_t * attr,
+ int pshared)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Mutexes created with 'attr' can be shared between
+ * processes if pthread_mutex_t variable is allocated
+ * in memory shared by these processes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_mutexattr_t
+ *
+ * pshared
+ * must be one of:
+ *
+ * PTHREAD_PROCESS_SHARED
+ * May be shared if in shared memory
+ *
+ * PTHREAD_PROCESS_PRIVATE
+ * Cannot be shared.
+ *
+ * DESCRIPTION
+ * Mutexes creatd with 'attr' can be shared between
+ * 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
+ *
+ * RESULTS
+ * 0 successfully set attribute,
+ * EINVAL 'attr' or pshared is invalid,
+ * ENOSYS PTHREAD_PROCESS_SHARED not supported,
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result;
+
+ if ((attr != NULL && *attr != NULL) &&
+ ((pshared == PTHREAD_PROCESS_SHARED) ||
+ (pshared == PTHREAD_PROCESS_PRIVATE)))
+ {
+ if (pshared == PTHREAD_PROCESS_SHARED)
+ {
+
+#if !defined( _POSIX_THREAD_PROCESS_SHARED )
+
+ result = ENOSYS;
+ pshared = PTHREAD_PROCESS_PRIVATE;
+
+#else
+
+ result = 0;
+
+#endif /* _POSIX_THREAD_PROCESS_SHARED */
+
+ }
+ else
+ {
+ result = 0;
+ }
+ (*attr)->pshared = pshared;
+ }
+ else
+ {
+ result = EINVAL;
+ }
+
+ return (result);
+
+} /* pthread_mutexattr_setpshared */
+
int
pthread_mutex_lock(pthread_mutex_t *mutex)
{
- if (!mutex->valid)
+ int result = 0;
+
+ /*
+ * We do a quick check to see if we need to do more work
+ * to initialise a static mutex. We check 'staticinit'
+ * again inside the guarded section of _mutex_check_need_init()
+ * to avoid race conditions.
+ */
+ if (mutex->staticinit)
{
- pthread_mutex_init(mutex, NULL);
+ result = _mutex_check_need_init(mutex);
}
- EnterCriticalSection(&mutex->cs);
- return 0;
+
+ if (result == 0)
+ {
+ if (mutex->mutex == 0)
+ {
+ EnterCriticalSection(&mutex->cs);
+ }
+ else
+ {
+ result = (WaitForSingleObject(mutex->mutex, INFINITE)
+ == WAIT_OBJECT_0)
+ ? 0
+ : EINVAL;
+ }
+ }
+
+ return(result);
}
int
pthread_mutex_unlock(pthread_mutex_t *mutex)
{
- if (!mutex->valid)
+ int result = 0;
+
+ /*
+ * If the thread calling us holds the mutex then there is no
+ * race condition. If another thread holds the
+ * lock then we shouldn't be in here.
+ */
+ if (!mutex->staticinit && mutex->valid)
{
- return EINVAL;
+ if (mutex->mutex == 0)
+ {
+ LeaveCriticalSection(&mutex->cs);
+ }
+ else
+ {
+ result = (ReleaseMutex (mutex->mutex) ? 0 : EINVAL);
+ }
}
- LeaveCriticalSection(&mutex->cs);
- return 0;
+ else
+ {
+ result = EINVAL;
+ }
+
+ return(result);
}
int
pthread_mutex_trylock(pthread_mutex_t *mutex)
{
- if (_pthread_try_enter_critical_section == NULL)
+ int result = 0;
+
+ if (mutex->mutex == 0 && _pthread_try_enter_critical_section == NULL)
{
/* TryEnterCriticalSection does not exist in the OS; return ENOSYS. */
return ENOSYS;
@@ -99,10 +519,40 @@ pthread_mutex_trylock(pthread_mutex_t *mutex)
return EINVAL;
}
- if (!mutex->valid)
+ /*
+ * We do a quick check to see if we need to do more work
+ * to initialise a static mutex. We check 'staticinit'
+ * again inside the guarded section of _mutex_check_need_init()
+ * to avoid race conditions.
+ */
+ if (mutex->staticinit)
+ {
+ result = _mutex_check_need_init(mutex);
+ }
+
+ if (result == 0)
{
- pthread_mutex_init(mutex, NULL);
+ if (mutex->mutex == 0)
+ {
+ if ((*_pthread_try_enter_critical_section)(&mutex->cs) != TRUE)
+ {
+ result = EBUSY;
+ }
+ }
+ else
+ {
+ DWORD status;
+
+ status = WaitForSingleObject (mutex->mutex, 0);
+
+ if (status != WAIT_OBJECT_0)
+ {
+ result = ((status == WAIT_TIMEOUT)
+ ? EBUSY
+ : EINVAL);
+ }
+ }
}
- return ((*_pthread_try_enter_critical_section)(&mutex->cs) != TRUE) ? EBUSY : 0;
+ return(result);
}
diff --git a/private.c b/private.c
index 1039d81..dd32ccd 100644
--- a/private.c
+++ b/private.c
@@ -9,6 +9,8 @@
#include "pthread.h"
#include "implement.h"
+#include <sys/timeb.h>
+
/*
* Code contributed by John E. Bossom <JEB>.
*/
@@ -49,6 +51,11 @@ _pthread_processInitialize (void)
_pthread_processTerminate ();
}
+ /*
+ * Set up the global mutex test and init check lock.
+ */
+ InitializeCriticalSection(&_pthread_mutex_test_init_lock);
+
return (_pthread_processInitialized);
} /* processInitialize */
@@ -99,6 +106,11 @@ _pthread_processTerminate (void)
_pthread_cleanupKey = NULL;
}
+ /*
+ * Destroy up the global mutex test and init check lock.
+ */
+ DeleteCriticalSection(&_pthread_mutex_test_init_lock);
+
_pthread_processInitialized = FALSE;
}
@@ -483,7 +495,7 @@ _pthread_sem_timedwait (sem_t * sem, const struct timespec * abstime)
if (abstime == NULL)
{
- msecs = INFINITE;
+ milliseconds = INFINITE;
}
else
{
diff --git a/pthread.h b/pthread.h
index aa48b32..29e691f 100644
--- a/pthread.h
+++ b/pthread.h
@@ -415,7 +415,7 @@ extern "C"
typedef struct pthread_once_t_ pthread_once_t;
typedef struct pthread_key_t_ *pthread_key_t;
typedef struct pthread_mutex_t_ pthread_mutex_t;
- typedef struct pthread_mutexattr_t_ pthread_mutexattr_t;
+ typedef struct pthread_mutexattr_t_ *pthread_mutexattr_t;
typedef struct pthread_cond_t_ *pthread_cond_t;
typedef struct pthread_condattr_t_ *pthread_condattr_t;
@@ -460,10 +460,10 @@ extern "C"
* ====================
*/
-/* FIXME: Replace the NULL with a valid critical section initializer
- * and then also change the 0 (first element) to 1.
+/*
+ *
*/
-#define PTHREAD_MUTEX_INITIALIZER { 0, NULL }
+#define PTHREAD_MUTEX_INITIALIZER { 1, 1, 0, NULL }
/*
@@ -569,13 +569,16 @@ struct pthread_attr_t_ {
struct pthread_mutex_t_ {
- int valid;
- CRITICAL_SECTION cs;
- };
+ int staticinit;
+ int valid;
+ HANDLE mutex;
+ CRITICAL_SECTION cs;
+};
struct pthread_mutexattr_t_ {
int pshared;
+ int forcecs;
};
@@ -838,6 +841,9 @@ int pthread_mutexattr_getpshared (const pthread_mutexattr_t
int pthread_mutexattr_setpshared (pthread_mutexattr_t * attr,
int pshared);
+int pthread_mutexattr_setforcecs_np(pthread_mutexattr_t *attr,
+ int forcecs);
+
/*
* Mutex Functions
*/
diff --git a/tests/eyal1.c b/tests/eyal1.c
index e32d29e..f51bc9c 100644
--- a/tests/eyal1.c
+++ b/tests/eyal1.c
@@ -161,6 +161,7 @@ print_server (void *ptr)
*/
if (pthread_mutex_lock (&mutex_todo))
return (-6);
+
mywork = todo;
if (todo >= 0) {
++todo;