diff -urp src.old/winsup/cygwin/include/pthread.h src/winsup/cygwin/include/pthread.h --- src.old/winsup/cygwin/include/pthread.h Wed Aug 14 14:19:59 2002 +++ src/winsup/cygwin/include/pthread.h Wed Aug 14 14:32:08 2002 @@ -50,12 +50,11 @@ extern "C" #define PTHREAD_CREATE_JOINABLE 0 #define PTHREAD_EXPLICIT_SCHED 1 #define PTHREAD_INHERIT_SCHED 0 -#define PTHREAD_MUTEX_DEFAULT 0 -#define PTHREAD_MUTEX_ERRORCHECK 1 -#define PTHREAD_MUTEX_NORMAL 2 +#define PTHREAD_MUTEX_ERRORCHECK 0 +#define PTHREAD_MUTEX_RECURSIVE 1 +#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_ERRORCHECK /* this should be too low to ever be a valid address */ #define PTHREAD_MUTEX_INITIALIZER (void *)20 -#define PTHREAD_MUTEX_RECURSIVE 0 #define PTHREAD_ONCE_INIT { PTHREAD_MUTEX_INITIALIZER, 0 } #define PTHREAD_PRIO_INHERIT #define PTHREAD_PRIO_NONE diff -urp src.old/winsup/cygwin/thread.cc src/winsup/cygwin/thread.cc --- src.old/winsup/cygwin/thread.cc Wed Aug 14 14:31:13 2002 +++ src/winsup/cygwin/thread.cc Wed Aug 14 14:32:08 2002 @@ -1042,39 +1042,40 @@ pthread_key::fixup_after_fork () *Isn't duplicated, it's reopened. */ -pthread_mutex::pthread_mutex (pthread_mutexattr *attr):verifyable_object (PTHREAD_MUTEX_MAGIC) +pthread_mutex::pthread_mutex (pthread_mutexattr *attr) : + verifyable_object (PTHREAD_MUTEX_MAGIC), + lock_counter (MUTEX_LOCK_COUNTER_INITIAL), + recursion_counter (0), win32_obj_id(NULL), + condwaits (0), owner (NULL), type (PTHREAD_MUTEX_DEFAULT), + pshared(PTHREAD_PROCESS_PRIVATE) { - /*attr checked in the C call */ - if (attr && attr->pshared == PTHREAD_PROCESS_SHARED) + win32_obj_id = ::CreateSemaphore (&sec_none_nih, 0, LONG_MAX, NULL); + if (!win32_obj_id) { - // fail magic = 0; return; } - if (wincap.has_try_enter_critical_section ()) - InitializeCriticalSection (&criticalsection); - else + /*attr checked in the C call */ + if (attr) { - this->win32_obj_id = ::CreateMutex (&sec_none_nih, false, NULL); - if (!win32_obj_id) - magic = 0; + if (attr->pshared == PTHREAD_PROCESS_SHARED) + { + // fail + magic = 0; + return; + } + + type = attr->mutextype; } - condwaits = 0; - pshared = PTHREAD_PROCESS_PRIVATE; + /* threadsafe addition is easy */ next = (pthread_mutex *) InterlockedExchangePointer (&MT_INTERFACE->mutexs, this); } pthread_mutex::~pthread_mutex () { - if (wincap.has_try_enter_critical_section ()) - DeleteCriticalSection (&criticalsection); - else - { - if (win32_obj_id) - CloseHandle (win32_obj_id); - win32_obj_id = NULL; - } + if (win32_obj_id) + CloseHandle (win32_obj_id); /* I'm not 100% sure the next bit is threadsafe. I think it is... */ if (MT_INTERFACE->mutexs == this) /* TODO: printf an error if the return value != this */ @@ -1083,7 +1084,7 @@ pthread_mutex::~pthread_mutex () { pthread_mutex *tempmutex = MT_INTERFACE->mutexs; while (tempmutex->next && tempmutex->next != this) - tempmutex = tempmutex->next; + tempmutex = tempmutex->next; /* but there may be a race between the loop above and this statement */ /* TODO: printf an error if the return value != this */ InterlockedExchangePointer (&tempmutex->next, this->next); @@ -1093,34 +1094,92 @@ pthread_mutex::~pthread_mutex () int pthread_mutex::Lock () { - if (wincap.has_try_enter_critical_section ()) + int result = 0; + pthread_t self = pthread::self (); + + if (0 == InterlockedIncrement (&lock_counter)) + SetOwner (); + else if (__pthread_equal(&owner, &self)) + { + InterlockedDecrement (&lock_counter); + if (PTHREAD_MUTEX_RECURSIVE == type) + if (UINT_MAX != recursion_counter) + ++recursion_counter; + else + result = EAGAIN; + else + result = EDEADLK; + } + else { - EnterCriticalSection (&criticalsection); - return 0; + WaitForSingleObject (win32_obj_id, INFINITE); + SetOwner (); } - /* FIXME: Return 0 on success */ - WaitForSingleObject (win32_obj_id, INFINITE); - return 0; + + return result; } -/* returns non-zero on failure */ int pthread_mutex::TryLock () { - if (wincap.has_try_enter_critical_section ()) - return (!TryEnterCriticalSection (&criticalsection)); - return (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT); + int result = 0; + pthread_t self = pthread::self (); + + if (MUTEX_LOCK_COUNTER_INITIAL == + InterlockedCompareExchange (&lock_counter, 0, MUTEX_LOCK_COUNTER_INITIAL )) + SetOwner (); + else if (__pthread_equal (&owner, &self) && PTHREAD_MUTEX_RECURSIVE == type) + if (UINT_MAX != recursion_counter) + ++recursion_counter; + else + result = EAGAIN; + else + result = EBUSY; + + return result; } int pthread_mutex::UnLock () { - if (wincap.has_try_enter_critical_section ()) + pthread_t self = pthread::self (); + + if (!__pthread_equal (&owner, &self)) + return EPERM; + + if (0 == --recursion_counter) { - LeaveCriticalSection (&criticalsection); - return 0; + owner = NULL; + if (MUTEX_LOCK_COUNTER_INITIAL != InterlockedDecrement (&lock_counter)) + // Another thread is waiting + ::ReleaseSemaphore (win32_obj_id, 1, NULL); } - return (!ReleaseMutex (win32_obj_id)); + + return 0; +} + +int +pthread_mutex::Destroy () +{ + if (condwaits || TryLock ()) + // Do not destroy a condwaited or locked mutex + return EBUSY; + else if (recursion_counter != 1) + { + // Do not destroy a recursive locked mutex + --recursion_counter; + return EBUSY; + } + + delete this; + return 0; +} + +void +pthread_mutex::SetOwner () +{ + recursion_counter = 1; + owner = pthread::self (); } void @@ -1129,15 +1188,15 @@ pthread_mutex::fixup_after_fork () debug_printf ("mutex %x in fixup_after_fork", this); if (pshared != PTHREAD_PROCESS_PRIVATE) api_fatal ("pthread_mutex::fixup_after_fork () doesn'tunderstand PROCESS_SHARED mutex's"); - /* FIXME: duplicate code here and in the constructor. */ - if (wincap.has_try_enter_critical_section ()) - InitializeCriticalSection (&criticalsection); - else - { - win32_obj_id = ::CreateMutex (&sec_none_nih, false, NULL); - if (!win32_obj_id) - api_fatal ("pthread_mutex::fixup_after_fork () failed to create new win32 mutex"); - } + + // State is preserved with one exception : All waiting threads are gone after fork + if (lock_counter != MUTEX_LOCK_COUNTER_INITIAL) + lock_counter = 0; + + win32_obj_id = ::CreateSemaphore (&sec_none_nih, 0, LONG_MAX, NULL); + if (!win32_obj_id) + api_fatal ("failed to recreate win32 semaphore for mutex"); + #if DETECT_BAD_APPS if (condwaits) api_fatal ("Forked () while a mutex has condition variables waiting on it.\nReport to cygwin@cygwin.com"); @@ -2184,16 +2243,17 @@ __pthread_mutex_unlock (pthread_mutex_t int __pthread_mutex_destroy (pthread_mutex_t *mutex) { + int rv; + if (check_valid_pointer (mutex) && (*mutex == PTHREAD_MUTEX_INITIALIZER)) return 0; if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) return EINVAL; - /*reading a word is atomic */ - if ((*mutex)->condwaits) - return EBUSY; + rv = (*mutex)->Destroy (); + if (rv) + return rv; - delete (*mutex); *mutex = NULL; return 0; } @@ -2227,10 +2287,6 @@ __pthread_mutexattr_getpshared (const pt return 0; } -/*Win32 mutex's are equivalent to posix RECURSIVE mutexs. - *We need to put glue in place to support other types of mutex's. We map - *PTHREAD_MUTEX_DEFAULT to PTHREAD_MUTEX_RECURSIVE and return EINVAL for other types. - */ int __pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type) { @@ -2240,10 +2296,7 @@ __pthread_mutexattr_gettype (const pthre return 0; } -/*Currently pthread_mutex_init ignores the attr variable, this is because - *none of the variables have any impact on it's behaviour. - * - *FIXME: write and test process shared mutex's. +/*FIXME: write and test process shared mutex's. */ int __pthread_mutexattr_init (pthread_mutexattr_t *attr) @@ -2314,15 +2367,21 @@ __pthread_mutexattr_setpshared (pthread_ return 0; } -/*see __pthread_mutex_gettype */ int __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type) { if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) return EINVAL; - if (type != PTHREAD_MUTEX_RECURSIVE) - return EINVAL; - (*attr)->mutextype = type; + + switch (type) + { + case PTHREAD_MUTEX_ERRORCHECK: + case PTHREAD_MUTEX_RECURSIVE: + (*attr)->mutextype = type; + break; + default: + return EINVAL; + } return 0; } diff -urp src.old/winsup/cygwin/thread.h src/winsup/cygwin/thread.h --- src.old/winsup/cygwin/thread.h Wed Aug 14 14:31:13 2002 +++ src/winsup/cygwin/thread.h Wed Aug 14 14:32:08 2002 @@ -152,6 +152,8 @@ private: #define SEM_MAGIC PTHREAD_MAGIC+7 #define PTHREAD_ONCE_MAGIC PTHREAD_MAGIC+8; +#define MUTEX_LOCK_COUNTER_INITIAL (-1) + /* verifyable_object should not be defined here - it's a general purpose class */ class verifyable_object @@ -217,15 +219,20 @@ public: class pthread_mutex:public verifyable_object { public: - CRITICAL_SECTION criticalsection; + LONG lock_counter; + unsigned int recursion_counter; HANDLE win32_obj_id; LONG condwaits; + pthread_t owner; + int type; int pshared; class pthread_mutex * next; int Lock (); int TryLock (); int UnLock (); + int Destroy (); + void SetOwner (); void fixup_after_fork (); pthread_mutex (pthread_mutexattr * = NULL);