From e4b6e4d4a63c036be326e3e933fb7f7c6787275b Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Fri, 17 Oct 2008 21:24:19 +0000 Subject: [PATCH] windows-pthread-rwlock-20081017 LICENSE MIT Adds pthread rwlock support to the library. --- src/WINNT/pthread/pthread.c | 196 ++++++++++++++++++++++++++++++++++++++++++ src/WINNT/pthread/pthread.def | 7 ++ src/WINNT/pthread/pthread.h | 18 ++++ 3 files changed, 221 insertions(+) diff --git a/src/WINNT/pthread/pthread.c b/src/WINNT/pthread/pthread.c index 24949a2..739c7b9 100644 --- a/src/WINNT/pthread/pthread.c +++ b/src/WINNT/pthread/pthread.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -213,6 +214,201 @@ int pthread_mutex_destroy(pthread_mutex_t *mp) { return rc; } +int pthread_rwlock_destroy(pthread_rwlock_t *rwp) +{ + int rc = 0; + + if (rwp != NULL) { + pthread_mutex_destroy(&rwp->read_access_completion_mutex); + pthread_mutex_destroy(&rwp->write_access_mutex); + pthread_cond_destroy(&rwp->read_access_completion_wait); + } else { +#ifdef PTHREAD_DEBUG + DebugBreak(); +#endif + rc = EINVAL; + } + + return rc; +} + +int pthread_rwlock_init(pthread_rwlock_t *rwp, const pthread_rwlockattr_t *attr) +{ + int rc = 0; + + if (rwp == NULL) + return EINVAL; + + rwp->readers = 0; + + rc = pthread_mutex_init(&rwp->write_access_mutex, NULL); + if (rc) + return rc; + + rc = pthread_mutex_init(&rwp->read_access_completion_mutex, NULL); + if (rc) + goto error1; + + rc = pthread_cond_init(&rwp->read_access_completion_wait, NULL); + if (rc == 0) + return 0; /* success */ + + pthread_mutex_destroy(&rwp->read_access_completion_mutex); + + error1: + pthread_mutex_destroy(&rwp->write_access_mutex); + + return rc; +} + +int pthread_rwlock_wrlock(pthread_rwlock_t *rwp) +{ + int rc = 0; + + if (rwp == NULL) + return EINVAL; + + if ((rc = pthread_mutex_lock(&rwp->write_access_mutex)) != 0) + return rc; + + if ((rc = pthread_mutex_lock(&rwp->read_access_completion_mutex)) != 0) + { + pthread_mutex_unlock(&rwp->write_access_mutex); + return rc; + } + + while (rc == 0 && rwp->readers > 0) { + rc = pthread_cond_wait( &rwp->read_access_completion_wait, + &rwp->read_access_completion_mutex); + } + + pthread_mutex_unlock(&rwp->read_access_completion_mutex); + + if (rc) + pthread_mutex_unlock(&rwp->write_access_mutex); + + return rc; +} + +int pthread_rwlock_rdlock(pthread_rwlock_t *rwp) +{ + int rc = 0; + + if (rwp == NULL) + return EINVAL; + + if ((rc = pthread_mutex_lock(&rwp->write_access_mutex)) != 0) + return rc; + + if ((rc = pthread_mutex_lock(&rwp->read_access_completion_mutex)) != 0) + { + pthread_mutex_unlock(&rwp->write_access_mutex); + return rc; + } + + rwp->readers++; + + pthread_mutex_unlock(&rwp->read_access_completion_mutex); + + pthread_mutex_unlock(&rwp->write_access_mutex); + + return rc; + +} + +int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwp) +{ + int rc = 0; + + if (rwp == NULL) + return EINVAL; + + if ((rc = pthread_mutex_trylock(&rwp->write_access_mutex)) != 0) + return rc; + + if ((rc = pthread_mutex_trylock(&rwp->read_access_completion_mutex)) != 0) { + pthread_mutex_unlock(&rwp->write_access_mutex); + return rc; + } + + rwp->readers++; + + pthread_mutex_unlock(&rwp->read_access_completion_mutex); + + pthread_mutex_unlock(&rwp->write_access_mutex); + + return rc; +} + +int pthread_rwlock_trywrlock(pthread_rwlock_t *rwp) +{ + int rc = 0; + + if (rwp == NULL) + return EINVAL; + + if ((rc = pthread_mutex_trylock(&rwp->write_access_mutex)) != 0) + return rc; + + if ((rc = pthread_mutex_trylock(&rwp->read_access_completion_mutex)) != 0) + { + pthread_mutex_unlock(&rwp->write_access_mutex); + return rc; + } + + if (rwp->readers > 0) + rc = EBUSY; + + pthread_mutex_unlock(&rwp->read_access_completion_mutex); + + if (rc) + pthread_mutex_unlock(&rwp->write_access_mutex); + + return rc; +} + +int pthread_rwlock_unlock(pthread_rwlock_t *rwp) +{ + int rc = 0; + + if (rwp == NULL) + return EINVAL; + + rc = pthread_mutex_trylock(&rwp->write_access_mutex); + if (rc != EDEADLK) + { + /* unlock a read lock */ + if (rc == 0) + pthread_mutex_unlock(&rwp->write_access_mutex); + + if ((rc = pthread_mutex_lock(&rwp->read_access_completion_mutex)) != 0) + { + pthread_mutex_unlock(&rwp->write_access_mutex); + return rc; + } + + if (rwp->readers <= 0) + { + rc = EINVAL; + } + else + { + if (--rwp->readers == 0) + pthread_cond_broadcast(&rwp->read_access_completion_wait); + } + + pthread_mutex_unlock(&rwp->read_access_completion_mutex); + } + else + { + /* unlock a write lock */ + rc = pthread_mutex_unlock(&rwp->write_access_mutex); + } + + return rc; +} + + /* * keys is used to keep track of which keys are currently * in use by the threads library. pthread_tsd_mutex is used diff --git a/src/WINNT/pthread/pthread.def b/src/WINNT/pthread/pthread.def index 45e33d7..387c1bf 100644 --- a/src/WINNT/pthread/pthread.def +++ b/src/WINNT/pthread/pthread.def @@ -26,3 +26,10 @@ EXPORTS pthread_attr_setdetachstate @24 pthread_exit @25 DllMain @26 + pthread_rwlock_destroy @27 + pthread_rwlock_init @28 + pthread_rwlock_rdlock @29 + pthread_rwlock_wrlock @30 + pthread_rwlock_tryrdlock @31 + pthread_rwlock_trywrlock @32 + pthread_rwlock_unlock @33 diff --git a/src/WINNT/pthread/pthread.h b/src/WINNT/pthread/pthread.h index d0dc019..dbd39c5 100644 --- a/src/WINNT/pthread/pthread.h +++ b/src/WINNT/pthread/pthread.h @@ -31,6 +31,7 @@ typedef struct { typedef int pthread_condattr_t; typedef int pthread_mutexattr_t; +typedef int pthread_rwlockattr_t; typedef int pthread_key_t; typedef void *pthread_t; @@ -56,6 +57,13 @@ typedef struct { struct rx_queue waiting_threads; } pthread_cond_t; +typedef struct { + pthread_mutex_t write_access_mutex; + pthread_mutex_t read_access_completion_mutex; + pthread_cond_t read_access_completion_wait; + int readers; +} pthread_rwlock_t; + #define PTHREAD_ONCE_INIT {0,1} extern int pthread_cond_broadcast(pthread_cond_t *cond); @@ -69,11 +77,21 @@ extern void *pthread_getspecific(pthread_key_t key); extern int pthread_join(pthread_t target_thread, void **status); extern int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *value)); extern int pthread_key_delete(pthread_key_t key); + extern int pthread_mutex_destroy(pthread_mutex_t *mp); extern int pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr); extern int pthread_mutex_lock(pthread_mutex_t *mp); extern int pthread_mutex_trylock(pthread_mutex_t *mp); extern int pthread_mutex_unlock(pthread_mutex_t *mp); + +extern int pthread_rwlock_destroy(pthread_rwlock_t *rwp); +extern int pthread_rwlock_init(pthread_rwlock_t *rwp, const pthread_rwlockattr_t *attr); +extern int pthread_rwlock_rdlock(pthread_rwlock_t *rwp); +extern int pthread_rwlock_wrlock(pthread_rwlock_t *rwp); +extern int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwp); +extern int pthread_rwlock_trywrlock(pthread_rwlock_t *rwp); +extern int pthread_rwlock_unlock(pthread_rwlock_t *rwp); + extern int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)); extern int pthread_setspecific(pthread_key_t key, const void *value); extern pthread_t pthread_self(void); -- 1.9.4