From 00d296a3f9528ab64f6efc3e9c45bbb823db4227 Mon Sep 17 00:00:00 2001 From: Thomas Pfaff Date: Tue, 18 Mar 2003 20:01:07 +0000 Subject: [PATCH] * cygwin.din: Add pthread_rwlock_destroy, pthread_rwlock_init, pthread_rwlock_rdlock, pthread_rwlock_tryrdlock, pthread_rwlock_wrlock, pthread_rwlock_trywrlock, pthread_rwlock_unlock, pthread_rwlockattr_init, pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared, and pthread_rwlockattr_destroy. * include/cygwin/version.h: Bump API minor number. * include/pthread.h (PTHREAD_RWLOCK_INITIALIZER): Define a reasonable value. Add prototypes for pthread_rwlock_destroy, pthread_rwlock_init, pthread_rwlock_rdlock, pthread_rwlock_tryrdlock, pthread_rwlock_wrlock, pthread_rwlock_trywrlock, pthread_rwlock_unlock, pthread_rwlockattr_init, pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared, and pthread_rwlockattr_destroy. * thread.h (PTHREAD_ONCE_MAGIC): Remove superflous semicolon. (PTHREAD_RWLOCK_MAGIC): New define. (PTHREAD_RWLOCKATTR_MAGIC): Ditto. (pthread_rwlockattr): New class. (pthread_rwlock): Ditto. (MTinterface::rwlocks): New member. (MTinterface::MTinterface): Initialize rwlocks. Add prototypes for __pthread_rwlock_destroy, __pthread_rwlock_wrlock, __pthread_rwlock_trywrlock, __pthread_rwlock_unlock, __pthread_rwlockattr_init, __pthread_rwlockattr_getpshared, __pthread_rwlockattr_setpshared, and __pthread_rwlockattr_destroy. * thread.cc (MTinterface::Init): Initialize rwlock internal mutex. (MTinterface::fixup_after_fork): Fixup rwlocks after fork. (pthread_rwlockattr::isGoodObject): Implement. (pthread_rwlockattr::pthread_rwlockattr): Ditto. (pthread_rwlockattr::~pthread_rwlockattr): Ditto. (pthread_rwlock::initMutex): Ditto. (pthread_rwlock::pthread_rwlock): Ditto. (pthread_rwlock::~pthread_rwlock): Ditto. (pthread_rwlock::RdLock): Ditto. (pthread_rwlock::TryRdLock): Ditto. (pthread_rwlock::WrLock): Ditto. (pthread_rwlock::TryWrLock): Ditto. (pthread_rwlock::UnLock): Ditto. (pthread_rwlock::addReader): Ditto. (pthread_rwlock::removeReader): Ditto. (pthread_rwlock::lookupReader): Ditto. (pthread_rwlock::RdLockCleanup): Ditto. (pthread_rwlock::WrLockCleanup): Ditto. (pthread_rwlock::fixup_after_fork): Ditto. (pthread_rwlock::isGoodObject): Ditto. (pthread_rwlock::isGoodInitializer): Ditto. (pthread_rwlock::isGoodInitializerOrObject): Ditto. (pthread_rwlock::isGoodInitializerOrBadObject): Ditto. (__pthread_rwlock_destroy): Ditto. (pthread_rwlock::init): Ditto. (__pthread_rwlock_rdlock): Ditto. (__pthread_rwlock_tryrdlock): Ditto. (__pthread_rwlock_wrlock): Ditto. (__pthread_rwlock_trywrlock): Ditto. --- winsup/cygwin/ChangeLog | 59 +++ winsup/cygwin/cygwin.din | 11 + winsup/cygwin/include/cygwin/version.h | 3 +- winsup/cygwin/include/pthread.h | 16 +- winsup/cygwin/pthread.cc | 68 ++++ winsup/cygwin/thread.cc | 528 +++++++++++++++++++++++++ winsup/cygwin/thread.h | 79 +++- 7 files changed, 761 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 6903aaf64..af71f9bdd 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,62 @@ +2003-03-18 Thomas Pfaff + + * cygwin.din: Add pthread_rwlock_destroy, pthread_rwlock_init, + pthread_rwlock_rdlock, pthread_rwlock_tryrdlock, + pthread_rwlock_wrlock, pthread_rwlock_trywrlock, + pthread_rwlock_unlock, pthread_rwlockattr_init, + pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared, + and pthread_rwlockattr_destroy. + * include/cygwin/version.h: Bump API minor number. + * include/pthread.h (PTHREAD_RWLOCK_INITIALIZER): Define a + reasonable value. + Add prototypes for pthread_rwlock_destroy, pthread_rwlock_init, + pthread_rwlock_rdlock, pthread_rwlock_tryrdlock, + pthread_rwlock_wrlock, pthread_rwlock_trywrlock, + pthread_rwlock_unlock, pthread_rwlockattr_init, + pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared, + and pthread_rwlockattr_destroy. + * thread.h (PTHREAD_ONCE_MAGIC): Remove superflous semicolon. + (PTHREAD_RWLOCK_MAGIC): New define. + (PTHREAD_RWLOCKATTR_MAGIC): Ditto. + (pthread_rwlockattr): New class. + (pthread_rwlock): Ditto. + (MTinterface::rwlocks): New member. + (MTinterface::MTinterface): Initialize rwlocks. + Add prototypes for __pthread_rwlock_destroy, + __pthread_rwlock_wrlock, __pthread_rwlock_trywrlock, + __pthread_rwlock_unlock, __pthread_rwlockattr_init, + __pthread_rwlockattr_getpshared, __pthread_rwlockattr_setpshared, + and __pthread_rwlockattr_destroy. + * thread.cc (MTinterface::Init): Initialize rwlock internal mutex. + (MTinterface::fixup_after_fork): Fixup rwlocks after fork. + (pthread_rwlockattr::isGoodObject): Implement. + (pthread_rwlockattr::pthread_rwlockattr): Ditto. + (pthread_rwlockattr::~pthread_rwlockattr): Ditto. + (pthread_rwlock::initMutex): Ditto. + (pthread_rwlock::pthread_rwlock): Ditto. + (pthread_rwlock::~pthread_rwlock): Ditto. + (pthread_rwlock::RdLock): Ditto. + (pthread_rwlock::TryRdLock): Ditto. + (pthread_rwlock::WrLock): Ditto. + (pthread_rwlock::TryWrLock): Ditto. + (pthread_rwlock::UnLock): Ditto. + (pthread_rwlock::addReader): Ditto. + (pthread_rwlock::removeReader): Ditto. + (pthread_rwlock::lookupReader): Ditto. + (pthread_rwlock::RdLockCleanup): Ditto. + (pthread_rwlock::WrLockCleanup): Ditto. + (pthread_rwlock::fixup_after_fork): Ditto. + (pthread_rwlock::isGoodObject): Ditto. + (pthread_rwlock::isGoodInitializer): Ditto. + (pthread_rwlock::isGoodInitializerOrObject): Ditto. + (pthread_rwlock::isGoodInitializerOrBadObject): Ditto. + (__pthread_rwlock_destroy): Ditto. + (pthread_rwlock::init): Ditto. + (__pthread_rwlock_rdlock): Ditto. + (__pthread_rwlock_tryrdlock): Ditto. + (__pthread_rwlock_wrlock): Ditto. + (__pthread_rwlock_trywrlock): Ditto. + 2003-03-18 Thomas Pfaff * thread.h (pthread_cond::ExitingWait): Remove. diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 131192376..df78b04b8 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -954,6 +954,17 @@ pthread_mutexattr_setprotocol pthread_mutexattr_setpshared pthread_mutexattr_settype pthread_once +pthread_rwlock_destroy +pthread_rwlock_init +pthread_rwlock_rdlock +pthread_rwlock_tryrdlock +pthread_rwlock_wrlock +pthread_rwlock_trywrlock +pthread_rwlock_unlock +pthread_rwlockattr_init +pthread_rwlockattr_getpshared +pthread_rwlockattr_setpshared +pthread_rwlockattr_destroy pthread_self pthread_setcancelstate pthread_setcanceltype diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index d667d8207..60cfd10b4 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -192,12 +192,13 @@ details. */ aclsort32 acltomode32 acltopbits32 acltotext32 facl32 fgetpos64 fopen64 freopen64 fseeko64 fsetpos64 ftello64 _open64 _lseek64 _fstat64 _stat64 mknod32 + 80: Export pthread_rwlock stuff */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 79 +#define CYGWIN_VERSION_API_MINOR 80 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h index 7ac683487..5f12cbbda 100644 --- a/winsup/cygwin/include/pthread.h +++ b/winsup/cygwin/include/pthread.h @@ -62,7 +62,7 @@ extern "C" #define PTHREAD_PRIO_PROTECT #define PTHREAD_PROCESS_SHARED 1 #define PTHREAD_PROCESS_PRIVATE 0 -#define PTHREAD_RWLOCK_INITIALIZER +#define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t)22 /* process is the default */ #define PTHREAD_SCOPE_PROCESS 0 #define PTHREAD_SCOPE_SYSTEM 1 @@ -161,6 +161,20 @@ int pthread_mutexattr_setprotocol (pthread_mutexattr_t *, int); int pthread_mutexattr_setpshared (pthread_mutexattr_t *, int); int pthread_mutexattr_settype (pthread_mutexattr_t *, int); +/* RW Locks */ +int pthread_rwlock_destroy (pthread_rwlock_t *rwlock); +int pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); +int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock); +int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock); +int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock); +int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock); +int pthread_rwlock_unlock (pthread_rwlock_t *rwlock); +int pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr); +int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, + int *pshared); +int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared); +int pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr); + int pthread_once (pthread_once_t *, void (*)(void)); /* Concurrency levels - X/Open interface */ diff --git a/winsup/cygwin/pthread.cc b/winsup/cygwin/pthread.cc index 2a15a3b63..8d629a969 100644 --- a/winsup/cygwin/pthread.cc +++ b/winsup/cygwin/pthread.cc @@ -388,6 +388,74 @@ pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared) return __pthread_condattr_setpshared (attr, pshared); } +/* RW Locks */ +int +pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + return __pthread_rwlock_destroy (rwlock); +} + +int +pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) +{ + return pthread_rwlock::init (rwlock, attr); +} + +int +pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + return __pthread_rwlock_rdlock (rwlock); +} + +int +pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +{ + return __pthread_rwlock_tryrdlock (rwlock); +} + +int +pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + return __pthread_rwlock_wrlock (rwlock); +} + +int +pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) +{ + return __pthread_rwlock_trywrlock (rwlock); +} + +int +pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + return __pthread_rwlock_unlock (rwlock); +} + +int +pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr) +{ + return __pthread_rwlockattr_init (rwlockattr); +} + +int +pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, + int *pshared) +{ + return __pthread_rwlockattr_getpshared (attr, pshared); +} + +int +pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared) +{ + return __pthread_rwlockattr_setpshared (attr, pshared); +} + +int +pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr) +{ + return __pthread_rwlockattr_destroy (rwlockattr); +} + /* Scheduling */ int diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 125e7d38f..ab8214e1c 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -199,6 +199,7 @@ MTinterface::Init (int forked) pthread_mutex::initMutex (); pthread_cond::initMutex (); + pthread_rwlock::initMutex (); } void @@ -230,6 +231,13 @@ MTinterface::fixup_after_fork (void) cond->fixup_after_fork (); cond = cond->next; } + pthread_rwlock *rwlock = rwlocks; + debug_printf ("rwlocks is %x",rwlocks); + while (rwlock) + { + rwlock->fixup_after_fork (); + rwlock = rwlock->next; + } semaphore *sem = semaphores; debug_printf ("semaphores is %x",semaphores); while (sem) @@ -998,6 +1006,341 @@ pthread_cond::fixup_after_fork () api_fatal ("pthread_cond::fixup_after_fork () failed to recreate win32 semaphore"); } +bool +pthread_rwlockattr::isGoodObject (pthread_rwlockattr_t const *attr) +{ + if (verifyable_object_isvalid (attr, PTHREAD_RWLOCKATTR_MAGIC) != VALID_OBJECT) + return false; + return true; +} + +pthread_rwlockattr::pthread_rwlockattr ():verifyable_object + (PTHREAD_RWLOCKATTR_MAGIC), shared (PTHREAD_PROCESS_PRIVATE) +{ +} + +pthread_rwlockattr::~pthread_rwlockattr () +{ +} + +/* This is used for rwlock creation protection within a single process only */ +nativeMutex NO_COPY pthread_rwlock::rwlockInitializationLock; + +/* We can only be called once. + TODO: (no rush) use a non copied memory section to + hold an initialization flag. */ +void +pthread_rwlock::initMutex () +{ + if (!rwlockInitializationLock.init ()) + api_fatal ("Could not create win32 Mutex for pthread rwlock static initializer support."); +} + +pthread_rwlock::pthread_rwlock (pthread_rwlockattr *attr) : + verifyable_object (PTHREAD_RWLOCK_MAGIC), + shared (0), waitingReaders (0), waitingWriters (0), writer (NULL), + readers (NULL), mtx (NULL), condReaders (NULL), condWriters (NULL), + next (NULL) +{ + pthread_mutex *verifyable_mutex_obj = &mtx; + pthread_cond *verifyable_cond_obj; + + if (attr) + if (attr->shared != PTHREAD_PROCESS_PRIVATE) + { + magic = 0; + return; + } + + if (!pthread_mutex::isGoodObject (&verifyable_mutex_obj)) + { + thread_printf ("Internal rwlock mutex is not valid. this %p", this); + magic = 0; + return; + } + /* Change the mutex type to NORMAL to speed up mutex operations */ + mtx.type = PTHREAD_MUTEX_NORMAL; + + verifyable_cond_obj = &condReaders; + if (!pthread_cond::isGoodObject (&verifyable_cond_obj)) + { + thread_printf ("Internal rwlock readers cond is not valid. this %p", this); + magic = 0; + return; + } + + verifyable_cond_obj = &condWriters; + if (!pthread_cond::isGoodObject (&verifyable_cond_obj)) + { + thread_printf ("Internal rwlock writers cond is not valid. this %p", this); + magic = 0; + return; + } + + + /* threadsafe addition is easy */ + next = (pthread_rwlock *) InterlockedExchangePointer (&MT_INTERFACE->rwlocks, this); +} + +pthread_rwlock::~pthread_rwlock () +{ + /* I'm not 100% sure the next bit is threadsafe. I think it is... */ + if (MT_INTERFACE->rwlocks == this) + InterlockedExchangePointer (&MT_INTERFACE->rwlocks, this->next); + else + { + pthread_rwlock *temprwlock = MT_INTERFACE->rwlocks; + while (temprwlock->next && temprwlock->next != this) + temprwlock = temprwlock->next; + /* but there may be a race between the loop above and this statement */ + InterlockedExchangePointer (&temprwlock->next, this->next); + } +} + +int +pthread_rwlock::RdLock () +{ + int result = 0; + struct RWLOCK_READER *reader; + pthread_t self = pthread::self (); + + mtx.Lock (); + + if (lookupReader (self)) + { + result = EDEADLK; + goto DONE; + } + + reader = new struct RWLOCK_READER; + if (!reader) + { + result = EAGAIN; + goto DONE; + } + + while (writer || waitingWriters) + { + pthread_cleanup_push (pthread_rwlock::RdLockCleanup, this); + + ++waitingReaders; + condReaders.Wait (&mtx); + --waitingReaders; + + pthread_cleanup_pop (0); + } + + reader->thread = self; + addReader (reader); + + DONE: + mtx.UnLock (); + + return result; +} + +int +pthread_rwlock::TryRdLock () +{ + int result = 0; + pthread_t self = pthread::self (); + + mtx.Lock (); + + if (writer || waitingWriters || lookupReader (self)) + result = EBUSY; + else + { + struct RWLOCK_READER *reader = new struct RWLOCK_READER; + if (reader) + { + reader->thread = self; + addReader (reader); + } + else + result = EAGAIN; + } + + mtx.UnLock (); + + return result; +} + +int +pthread_rwlock::WrLock () +{ + int result = 0; + pthread_t self = pthread::self (); + + mtx.Lock (); + + if (writer == self || lookupReader (self)) + { + result = EDEADLK; + goto DONE; + } + + while (writer || readers) + { + pthread_cleanup_push (pthread_rwlock::WrLockCleanup, this); + + ++waitingWriters; + condWriters.Wait (&mtx); + --waitingWriters; + + pthread_cleanup_pop (0); + } + + writer = self; + + DONE: + mtx.UnLock (); + + return result; +} + +int +pthread_rwlock::TryWrLock () +{ + int result = 0; + pthread_t self = pthread::self (); + + mtx.Lock (); + + if (writer || readers) + result = EBUSY; + else + writer = self; + + mtx.UnLock (); + + return result; +} + +int +pthread_rwlock::UnLock () +{ + int result = 0; + pthread_t self = pthread::self (); + + mtx.Lock (); + + if (writer) + { + if (writer != self) + { + result = EPERM; + goto DONE; + } + + writer = NULL; + } + else + { + struct RWLOCK_READER *reader = lookupReader (self); + + if (!reader) + { + result = EPERM; + goto DONE; + } + + removeReader (reader); + delete reader; + } + + if (waitingWriters) + { + if (!readers) + condWriters.UnBlock (false); + } + else if (waitingReaders) + condReaders.UnBlock (true); + + DONE: + mtx.UnLock (); + + return result; +} + +void +pthread_rwlock::addReader (struct RWLOCK_READER *rd) +{ + rd->next = (struct RWLOCK_READER *) + InterlockedExchangePointer (&readers, rd); +} + +void +pthread_rwlock::removeReader (struct RWLOCK_READER *rd) +{ + if (readers == rd) + InterlockedExchangePointer (&readers, rd->next); + else + { + struct RWLOCK_READER *temp = readers; + while (temp->next && temp->next != rd) + temp = temp->next; + /* but there may be a race between the loop above and this statement */ + InterlockedExchangePointer (&temp->next, rd->next); + } +} + +struct pthread_rwlock::RWLOCK_READER * +pthread_rwlock::lookupReader (pthread_t thread) +{ + struct RWLOCK_READER *temp = readers; + + while (temp && temp->thread != thread) + temp = temp->next; + + return temp; +} + +void +pthread_rwlock::RdLockCleanup (void *arg) +{ + pthread_rwlock *rwlock = (pthread_rwlock *) arg; + + --(rwlock->waitingReaders); + rwlock->mtx.UnLock (); +} + +void +pthread_rwlock::WrLockCleanup (void *arg) +{ + pthread_rwlock *rwlock = (pthread_rwlock *) arg; + + --(rwlock->waitingWriters); + rwlock->mtx.UnLock (); +} + +void +pthread_rwlock::fixup_after_fork () +{ + pthread_t self = pthread::self (); + struct RWLOCK_READER **temp = &readers; + + waitingReaders = 0; + waitingWriters = 0; + + /* Unlock eventually locked mutex */ + mtx.UnLock (); + /* + * Remove all readers except self + */ + while (*temp) + { + if ((*temp)->thread == self) + temp = &((*temp)->next); + else + { + struct RWLOCK_READER *cur = *temp; + *temp = (*temp)->next; + delete cur; + } + } +} + /* pthread_key */ /* static members */ /* This stores pthread_key information across fork() boundaries */ @@ -2292,6 +2635,191 @@ __pthread_condattr_destroy (pthread_condattr_t *condattr) return 0; } +/* RW locks */ +bool +pthread_rwlock::isGoodObject (pthread_rwlock_t const *rwlock) +{ + if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC) != VALID_OBJECT) + return false; + return true; +} + +bool +pthread_rwlock::isGoodInitializer (pthread_rwlock_t const *rwlock) +{ + if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) != VALID_STATIC_OBJECT) + return false; + return true; +} + +bool +pthread_rwlock::isGoodInitializerOrObject (pthread_rwlock_t const *rwlock) +{ + if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) == INVALID_OBJECT) + return false; + return true; +} + +bool +pthread_rwlock::isGoodInitializerOrBadObject (pthread_rwlock_t const *rwlock) +{ + verifyable_object_state objectState = verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER); + if (objectState == VALID_OBJECT) + return false; + return true; +} + +int +__pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + if (pthread_rwlock::isGoodInitializer (rwlock)) + return 0; + if (!pthread_rwlock::isGoodObject (rwlock)) + return EINVAL; + + if ((*rwlock)->writer || (*rwlock)->readers || + (*rwlock)->waitingReaders || (*rwlock)->waitingWriters) + return EBUSY; + + delete (*rwlock); + *rwlock = NULL; + + return 0; +} + +int +pthread_rwlock::init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) +{ + if (attr && !pthread_rwlockattr::isGoodObject (attr)) + return EINVAL; + if (!rwlockInitializationLock.lock ()) + return EINVAL; + + if (!isGoodInitializerOrBadObject (rwlock)) + { + rwlockInitializationLock.unlock (); + return EBUSY; + } + + *rwlock = new pthread_rwlock (attr ? (*attr) : NULL); + if (!isGoodObject (rwlock)) + { + delete (*rwlock); + *rwlock = NULL; + rwlockInitializationLock.unlock (); + return EAGAIN; + } + rwlockInitializationLock.unlock (); + return 0; +} + +int +__pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + pthread_testcancel (); + + if (pthread_rwlock::isGoodInitializer (rwlock)) + pthread_rwlock::init (rwlock, NULL); + if (!pthread_rwlock::isGoodObject (rwlock)) + return EINVAL; + + return (*rwlock)->RdLock (); +} + +int +__pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +{ + if (pthread_rwlock::isGoodInitializer (rwlock)) + pthread_rwlock::init (rwlock, NULL); + if (!pthread_rwlock::isGoodObject (rwlock)) + return EINVAL; + + return (*rwlock)->TryRdLock (); +} + +int +__pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + pthread_testcancel (); + + if (pthread_rwlock::isGoodInitializer (rwlock)) + pthread_rwlock::init (rwlock, NULL); + if (!pthread_rwlock::isGoodObject (rwlock)) + return EINVAL; + + return (*rwlock)->WrLock (); +} + +int +__pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) +{ + if (pthread_rwlock::isGoodInitializer (rwlock)) + pthread_rwlock::init (rwlock, NULL); + if (!pthread_rwlock::isGoodObject (rwlock)) + return EINVAL; + + return (*rwlock)->TryWrLock (); +} + +int +__pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + if (pthread_rwlock::isGoodInitializer (rwlock)) + return 0; + if (!pthread_rwlock::isGoodObject (rwlock)) + return EINVAL; + + return (*rwlock)->UnLock (); +} + +int +__pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr) +{ + if (check_valid_pointer (rwlockattr)) + return EINVAL; + *rwlockattr = new pthread_rwlockattr; + if (!pthread_rwlockattr::isGoodObject (rwlockattr)) + { + delete (*rwlockattr); + *rwlockattr = NULL; + return EAGAIN; + } + return 0; +} + +int +__pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared) +{ + if (!pthread_rwlockattr::isGoodObject (attr)) + return EINVAL; + *pshared = (*attr)->shared; + return 0; +} + +int +__pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared) +{ + if (!pthread_rwlockattr::isGoodObject (attr)) + return EINVAL; + if ((pshared < 0) || (pshared > 1)) + return EINVAL; + /* shared rwlock vars not currently supported */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return EINVAL; + (*attr)->shared = pshared; + return 0; +} + +int +__pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr) +{ + if (!pthread_rwlockattr::isGoodObject (rwlockattr)) + return EINVAL; + delete (*rwlockattr); + *rwlockattr = NULL; + return 0; +} + /* Thread signal */ int __pthread_kill (pthread_t thread, int sig) diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index 1f1afa19c..58be95c7e 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -163,6 +163,8 @@ private: #define PTHREAD_CONDATTR_MAGIC PTHREAD_MAGIC+6 #define SEM_MAGIC PTHREAD_MAGIC+7 #define PTHREAD_ONCE_MAGIC PTHREAD_MAGIC+8 +#define PTHREAD_RWLOCK_MAGIC PTHREAD_MAGIC+9 +#define PTHREAD_RWLOCKATTR_MAGIC PTHREAD_MAGIC+10 #define MUTEX_OWNER_ANONYMOUS ((pthread_t) -1) @@ -517,6 +519,67 @@ private: static nativeMutex condInitializationLock; }; +class pthread_rwlockattr:public verifyable_object +{ +public: + static bool isGoodObject(pthread_rwlockattr_t const *); + int shared; + + pthread_rwlockattr (); + ~pthread_rwlockattr (); +}; + +class pthread_rwlock:public verifyable_object +{ +public: + static bool isGoodObject (pthread_rwlock_t const *); + static bool isGoodInitializer (pthread_rwlock_t const *); + static bool isGoodInitializerOrObject (pthread_rwlock_t const *); + static bool isGoodInitializerOrBadObject (pthread_rwlock_t const *); + static void initMutex (); + static int init (pthread_rwlock_t *, const pthread_rwlockattr_t *); + + int shared; + + unsigned long waitingReaders; + unsigned long waitingWriters; + pthread_t writer; + struct RWLOCK_READER + { + struct RWLOCK_READER *next; + pthread_t thread; + } *readers; + + int RdLock (); + int TryRdLock (); + + int WrLock (); + int TryWrLock (); + + int UnLock (); + + pthread_mutex mtx; + pthread_cond condReaders; + pthread_cond condWriters; + + class pthread_rwlock * next; + + void fixup_after_fork (); + + pthread_rwlock (pthread_rwlockattr *); + ~pthread_rwlock (); + +private: + void addReader (struct RWLOCK_READER *rd); + void removeReader (struct RWLOCK_READER *rd); + struct RWLOCK_READER *lookupReader (pthread_t thread); + + static void RdLockCleanup (void *arg); + static void WrLockCleanup (void *arg); + + static nativeMutex rwlockInitializationLock; +}; + class pthread_once { public: @@ -574,6 +637,7 @@ public: // lists of pthread objects. USE THREADSAFE INSERTS AND DELETES. class pthread_mutex * mutexs; class pthread_cond * conds; + class pthread_rwlock * rwlocks; class semaphore * semaphores; pthread_key reent_key; @@ -586,7 +650,7 @@ public: MTinterface () : concurrency (0), threadcount (1), pthread_prepare (NULL), pthread_child (NULL), pthread_parent (NULL), - mutexs (NULL), conds (NULL), semaphores (NULL), + mutexs (NULL), conds (NULL), rwlocks (NULL), semaphores (NULL), reent_key (NULL), thread_self_key (NULL) { } @@ -632,6 +696,19 @@ int __pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared); int __pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared); +/* RW locks */ +int __pthread_rwlock_destroy (pthread_rwlock_t *rwlock); +int __pthread_rwlock_rdlock (pthread_rwlock_t *rwlock); +int __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock); +int __pthread_rwlock_wrlock (pthread_rwlock_t *rwlock); +int __pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock); +int __pthread_rwlock_unlock (pthread_rwlock_t *rwlock); +int __pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr); +int __pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, + int *pshared); +int __pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared); +int __pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr); + /* Thread signal */ int __pthread_kill (pthread_t thread, int sig); int __pthread_sigmask (int operation, const sigset_t * set,