diff options
author | rpj <rpj> | 2001-05-31 02:01:47 +0000 |
---|---|---|
committer | rpj <rpj> | 2001-05-31 02:01:47 +0000 |
commit | e121b938c9f012958196a3141f04a3fd4f58bdb9 (patch) | |
tree | d1cb950413e3a350606f2a4d9bea687b6680570d /rwlock.c | |
parent | 6bf07e836550f9ffe11e0f38ff1323be731eb250 (diff) |
2001-05-30 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
* pthread.h (rand_r): Fake using _seed argument to quell
compiler warning (compiler should optimise this away later).
* GNUmakefile (OPT): Leave symbolic information out of the library
and increase optimisation level - for smaller faster prebuilt
dlls.
2001-05-29 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
Contributed by - Milan Gardian <Milan.Gardian@LEIBINGER.com>
* Makefile: fix typo.
* pthreads.h: Fix problems with stdcall/cdecl conventions, in particular
remove the need for PT_STDCALL everywhere; remove warning supression.
* (errno): Fix the longstanding "inconsistent dll linkage" problem
with errno; now also works with /MD debugging libs -
warnings emerged when compiling pthreads library with /MD (or /MDd)
compiler switch, instead of /MT (or /MTd) (i.e. when compiling pthreads
using Multithreaded DLL CRT instead of Multithreaded statically linked
CRT).
* create.c (pthread_create): Likewise; fix typo.
* private.c (ptw32_threadStart): Eliminate use of terminate() which doesn't
throw exceptions.
* Remove unnecessary #includes from a number of modules -
[I had to #include malloc.h in implement.h for gcc - rpj].
2001-05-29 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
Contributed by - Thomas Pfaff <tpfaff@gmx.net>
* pthread.h (PTHREAD_MUTEX_DEFAULT): New; equivalent to
PTHREAD_MUTEX_DEFAULT_NP.
* (PTHREAD_MUTEX_NORMAL): Similarly.
* (PTHREAD_MUTEX_ERRORCHECK): Similarly.
* (PTHREAD_MUTEX_RECURSIVE): Similarly.
* (pthread_mutex_setdefaultkind_np): New; Linux compatibility stub
for pthread_mutexattr_settype.
* (pthread_mutexattr_getkind_np): New; Linux compatibility stub
for pthread_mutexattr_gettype.
* mutex.c (pthread_mutexattr_settype): New; allow
the following types of mutex:
PTHREAD_MUTEX_DEFAULT_NP
PTHREAD_MUTEX_NORMAL_NP
PTHREAD_MUTEX_ERRORCHECK_NP
PTHREAD_MUTEX_RECURSIVE_NP
* Note that PTHREAD_MUTEX_DEFAULT is equivalent to
PTHREAD_MUTEX_NORMAL - ie. mutexes should no longer
be recursive by default, and a thread will deadlock if it
tries to relock a mutex it already owns. This is inline with
other pthreads implementations.
* (pthread_mutex_lock): Process the lock request
according to the mutex type.
* (pthread_mutex_init): Eliminate use of Win32 mutexes as the
basis of POSIX mutexes - instead, a combination of one critical section
and one semaphore are used in conjunction with Win32 Interlocked* routines.
* (pthread_mutex_destroy): Likewise.
* (pthread_mutex_lock): Likewise.
* (pthread_mutex_trylock): Likewise.
* (pthread_mutex_unlock): Likewise.
* Use longjmp/setjmp to implement cancelation when building the library
using a C compiler which doesn't support exceptions, e.g. gcc -x c (note
that gcc -x c++ uses exceptions).
* Also fixed some of the same typos and eliminated PT_STDCALL as
Milan Gardian's patches above.
2001-02-07 Ross Johnson <rpj@special.ise.canberra.edu.au>
Contributed by - Alexander Terekhov <TEREKHOV@de.ibm.com>
* rwlock.c: Revamped.
* implement.h (pthread_rwlock_t_): Redefined.
This implementation does not have reader/writer starvation problem.
Rwlock attempts to behave more like a normal mutex with
races and scheduling policy determining who is more important;
It also supports recursive locking,
has less synchronization overhead (no broadcasts at all,
readers are not blocked on any condition variable) and seem to
be faster than the current implementation [W98 appears to be
approximately 15 percent faster at least - on top of speed increase
from Thomas Pfaff's changes to mutex.c - rpj].
Diffstat (limited to 'rwlock.c')
-rw-r--r-- | rwlock.c | 436 |
1 files changed, 237 insertions, 199 deletions
@@ -24,6 +24,7 @@ */ #include <errno.h> +#include <limits.h> #include "pthread.h" #include "implement.h" @@ -80,120 +81,140 @@ ptw32_rwlock_check_need_init(pthread_rwlock_t *rwlock) LeaveCriticalSection(&ptw32_rwlock_test_init_lock); - return(result); + return result; } int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) { - int result = 0; - pthread_rwlock_t rw; + int result; + pthread_rwlock_t rwl = 0; if (rwlock == NULL) { return EINVAL; } - rw = (pthread_rwlock_t) calloc(1, sizeof(*rw)); + if (attr != NULL && *attr != NULL) + { + result = EINVAL; /* Not supported */ + goto DONE; + } + + rwl = (pthread_rwlock_t) calloc(1, sizeof(*rwl)); - if (rw == NULL) + if (rwl == NULL) { result = ENOMEM; - goto FAIL0; + goto DONE; } - if (attr != NULL - && *attr != NULL) + rwl->nSharedAccessCount = 0; + rwl->nExclusiveAccessCount = 0; + rwl->nCompletedSharedAccessCount = 0; + + result = pthread_mutex_init(&rwl->mtxExclusiveAccess, NULL); + if (result != 0) { - result = EINVAL; /* Not supported */ goto FAIL0; } - if ((result = pthread_mutex_init(&(rw->rw_lock), NULL)) != 0) + result = pthread_mutex_init(&rwl->mtxSharedAccessCompleted, NULL); + if (result != 0) { goto FAIL1; } - if ((result = pthread_cond_init(&(rw->rw_condreaders), NULL)) != 0) + result = pthread_cond_init(&rwl->cndSharedAccessCompleted, NULL); + if (result != 0) { goto FAIL2; } - if ((result = pthread_cond_init(&(rw->rw_condwriters), NULL)) != 0) - { - goto FAIL3; - } - - rw->rw_nwaitreaders = 0; - rw->rw_nwaitwriters = 0; - rw->rw_refcount = 0; - rw->rw_magic = RW_MAGIC; + rwl->nMagic = PTW32_RWLOCK_MAGIC; result = 0; - goto FAIL0; - -FAIL3: - (void) pthread_cond_destroy(&(rw->rw_condreaders)); + goto DONE; FAIL2: - (void) pthread_mutex_destroy(&(rw->rw_lock)); + (void) pthread_mutex_destroy(&(rwl->mtxSharedAccessCompleted)); FAIL1: + (void) pthread_mutex_destroy(&(rwl->mtxExclusiveAccess)); + FAIL0: - *rwlock = rw; + (void) free(rwl); + rwl = NULL; + +DONE: + *rwlock = rwl; - return(result); + return result; } int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) { - pthread_rwlock_t rw; - int result = 0; + pthread_rwlock_t rwl; + int result = 0, result1 = 0, result2 = 0; if (rwlock == NULL || *rwlock == NULL) { - return(EINVAL); + return EINVAL; } if (*rwlock != (pthread_rwlock_t) PTW32_OBJECT_AUTO_INIT) { - rw = *rwlock; + rwl = *rwlock; - if (pthread_mutex_lock(&(rw->rw_lock)) != 0) + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { - return(EINVAL); + return EINVAL; } - if (rw->rw_magic != RW_MAGIC) + if ((result = pthread_mutex_lock(&(rwl->mtxExclusiveAccess))) != 0) { - (void) pthread_mutex_unlock(&(rw->rw_lock)); - return(EINVAL); + return result; } - if (rw->rw_refcount != 0 - || rw->rw_nwaitreaders != 0 - || rw->rw_nwaitwriters != 0) + if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) { - (void) pthread_mutex_unlock(&(rw->rw_lock)); - result = EBUSY; + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; } - else - { - /* - * Need to NULL this before we start freeing up - * and destroying it's components. - */ - *rwlock = NULL; - rw->rw_magic = 0; - (void) pthread_mutex_unlock(&(rw->rw_lock)); - - (void) pthread_cond_destroy(&(rw->rw_condreaders)); - (void) pthread_cond_destroy(&(rw->rw_condwriters)); - (void) pthread_mutex_destroy(&(rw->rw_lock)); - free(rw); - } + /* + * Check whether any threads own/wait for the lock (wait for ex.access); + * report "BUSY" if so. + */ + if (rwl->nExclusiveAccessCount > 0 + || rwl->nSharedAccessCount > rwl->nCompletedSharedAccessCount) + { + result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted)); + result1 = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + result2 = EBUSY; + } + else + { + rwl->nMagic = 0; + + if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + pthread_mutex_unlock(&rwl->mtxExclusiveAccess); + return result; + } + + if ((result = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + *rwlock = NULL; /* Invalidate rwlock before anything else */ + result = pthread_cond_destroy(&(rwl->cndSharedAccessCompleted)); + result1 = pthread_mutex_destroy(&(rwl->mtxSharedAccessCompleted)); + result2 = pthread_mutex_destroy(&(rwl->mtxExclusiveAccess)); + (void) free(rwl); + } } else { @@ -227,28 +248,18 @@ pthread_rwlock_destroy(pthread_rwlock_t *rwlock) LeaveCriticalSection(&ptw32_rwlock_test_init_lock); } - return(result); -} - -static void -_rwlock_cancelrdwait(void * arg) -{ - pthread_rwlock_t rw; - - rw = (pthread_rwlock_t) arg; - rw->rw_nwaitreaders--; - pthread_mutex_unlock(&(rw->rw_lock)); + return ((result != 0) ? result : ((result1 != 0) ? result1 : result2)); } int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) { - int result = 0; - pthread_rwlock_t rw; + int result; + pthread_rwlock_t rwl; if (rwlock == NULL || *rwlock == NULL) { - return(EINVAL); + return EINVAL; } /* @@ -263,70 +274,64 @@ pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) if (result != 0 && result != EBUSY) { - return(result); + return result; } } - rw = *rwlock; + rwl = *rwlock; - if ((result = pthread_mutex_lock(&(rw->rw_lock))) != 0) + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { - return(result); + return EINVAL; } - if (rw->rw_magic != RW_MAGIC) + if ((result = pthread_mutex_lock(&(rwl->mtxExclusiveAccess))) != 0) { - result = EINVAL; - goto FAIL1; + return result; } - /* - * Give preference to waiting writers - */ - while (rw->rw_refcount < 0 || rw->rw_nwaitwriters > 0) + if (++rwl->nSharedAccessCount == INT_MAX) { - rw->rw_nwaitreaders++; - pthread_cleanup_push(_rwlock_cancelrdwait, rw); - result = pthread_cond_wait(&(rw->rw_condreaders), &(rw->rw_lock)); - pthread_cleanup_pop(0); - rw->rw_nwaitreaders--; - - if (result != 0) + if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) { - break; + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; } - } - if (result == 0) - { - rw->rw_refcount++; /* another reader has a read lock */ - } + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; -FAIL1: - (void) pthread_mutex_unlock(&(rw->rw_lock)); + if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; + } + } - return(result); + return (pthread_mutex_unlock(&(rwl->mtxExclusiveAccess))); } static void -_rwlock_cancelwrwait(void * arg) +ptw32_rwlock_cancelwrwait(void * arg) { - pthread_rwlock_t rw; + pthread_rwlock_t rwl = (pthread_rwlock_t) arg; - rw = (pthread_rwlock_t) arg; - rw->rw_nwaitwriters--; - (void) pthread_mutex_unlock(&(rw->rw_lock)); + rwl->nSharedAccessCount = -rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + + (void) pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted)); + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); } int pthread_rwlock_wrlock(pthread_rwlock_t * rwlock) { int result; - pthread_rwlock_t rw; + pthread_rwlock_t rwl; if (rwlock == NULL || *rwlock == NULL) { - return(EINVAL); + return EINVAL; } /* @@ -341,51 +346,71 @@ pthread_rwlock_wrlock(pthread_rwlock_t * rwlock) if (result != 0 && result != EBUSY) { - return(result); + return result; } } - rw = *rwlock; + rwl = *rwlock; - if (rw->rw_magic != RW_MAGIC) + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { - return(EINVAL); + return EINVAL; + } + + if ((result = pthread_mutex_lock(&(rwl->mtxExclusiveAccess))) != 0) + { + return result; } - if ((result = pthread_mutex_lock(&(rw->rw_lock))) != 0) + if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) { - return(result); + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; } - while (rw->rw_refcount != 0) + if (rwl->nExclusiveAccessCount == 0) { - rw->rw_nwaitwriters++; - pthread_cleanup_push(_rwlock_cancelwrwait, rw); - result = pthread_cond_wait(&(rw->rw_condwriters), &(rw->rw_lock)); - pthread_cleanup_pop(0); - rw->rw_nwaitwriters--; + if (rwl->nCompletedSharedAccessCount > 0) + { + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + } - if (result != 0) + if (rwl->nSharedAccessCount > 0) { - break; + rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount; + + pthread_cleanup_push(ptw32_rwlock_cancelwrwait, (void*)rwl); + + do + { + result = pthread_cond_wait(&(rwl->cndSharedAccessCompleted), + &(rwl->mtxSharedAccessCompleted)); + } + while (result == 0 && rwl->nCompletedSharedAccessCount < 0); + + pthread_cleanup_pop ((result != 0) ? 1 : 0); + + if (result == 0) + { + rwl->nSharedAccessCount = 0; + } } } if (result == 0) { - rw->rw_refcount = -1; + rwl->nExclusiveAccessCount++; } - (void) pthread_mutex_unlock(&(rw->rw_lock)); - - return(result); + return result; } int pthread_rwlock_unlock(pthread_rwlock_t * rwlock) { - int result = 0; - pthread_rwlock_t rw; + int result, result1; + pthread_rwlock_t rwl; if (rwlock == NULL || *rwlock == NULL) { @@ -397,67 +422,51 @@ pthread_rwlock_unlock(pthread_rwlock_t * rwlock) /* * Assume any race condition here is harmless. */ - return(0); + return 0; } - rw = *rwlock; - - if ((result = pthread_mutex_lock(&(rw->rw_lock))) != 0) - { - return(result); - } + rwl = *rwlock; - if (rw->rw_magic != RW_MAGIC) + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { - result = EINVAL; - goto FAIL1; + return EINVAL; } - if (rw->rw_refcount > 0) - { - rw->rw_refcount--; /* releasing a reader */ - } - else if (rw->rw_refcount == -1) + if (rwl->nExclusiveAccessCount == 0) { - rw->rw_refcount = 0; /* releasing a writer */ - } - else - { - return(EINVAL); - } - - result = 0; + if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + return result; + } - /* - * Give preference to waiting writers over waiting readers - */ - if (rw->rw_nwaitwriters > 0) - { - if (rw->rw_refcount == 0) + if (++rwl->nCompletedSharedAccessCount == 0) { - result = pthread_cond_signal(&(rw->rw_condwriters)); + result = pthread_cond_signal(&(rwl->cndSharedAccessCompleted)); } + + result1 = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted)); } - else if (rw->rw_nwaitreaders > 0) + else { - result = pthread_cond_broadcast(&(rw->rw_condreaders)); - } + rwl->nExclusiveAccessCount--; -FAIL1: - (void) pthread_mutex_unlock(&(rw->rw_lock)); + result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted)); + result1 = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); - return(result); -} + } + return ((result != 0) ? result : result1); +} + int pthread_rwlock_tryrdlock(pthread_rwlock_t * rwlock) { - int result = 0; - pthread_rwlock_t rw; + int result; + pthread_rwlock_t rwl; if (rwlock == NULL || *rwlock == NULL) { - return(EINVAL); + return EINVAL; } /* @@ -472,47 +481,52 @@ pthread_rwlock_tryrdlock(pthread_rwlock_t * rwlock) if (result != 0 && result != EBUSY) { - return(result); + return result; } } - rw = *rwlock; + rwl = *rwlock; - if ((result = pthread_mutex_lock(&(rw->rw_lock))) != 0) + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { - return(result); + return EINVAL; } - if (rw->rw_magic != RW_MAGIC) + if ((result = pthread_mutex_trylock(&(rwl->mtxExclusiveAccess))) != 0) { - result = EINVAL; - goto FAIL1; + return result; } - if (rw->rw_refcount == -1 || rw->rw_nwaitwriters > 0) - { - result = EBUSY; /* held by a writer or waiting writers */ - } - else + if (++rwl->nSharedAccessCount == INT_MAX) { - rw->rw_refcount++; /* increment count of reader locks */ - } + if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; + } -FAIL1: - (void) pthread_mutex_unlock(&(rw->rw_lock)); + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; - return(result); + if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; + } + } + + return (pthread_mutex_unlock(&rwl->mtxExclusiveAccess)); } int pthread_rwlock_trywrlock(pthread_rwlock_t * rwlock) { - int result = 0; - pthread_rwlock_t rw; + int result, result1; + pthread_rwlock_t rwl; if (rwlock == NULL || *rwlock == NULL) { - return(EINVAL); + return EINVAL; } /* @@ -527,34 +541,58 @@ pthread_rwlock_trywrlock(pthread_rwlock_t * rwlock) if (result != 0 && result != EBUSY) { - return(result); + return result; } } - rw = *rwlock; + rwl = *rwlock; - if ((result = pthread_mutex_lock(&(rw->rw_lock))) != 0) + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { - return(result); + return EINVAL; } - if (rw->rw_magic != RW_MAGIC) + if ((result = pthread_mutex_trylock(&(rwl->mtxExclusiveAccess))) != 0) { - result = EINVAL; - goto FAIL1; + return result; } - if (rw->rw_refcount != 0) + if ((result = pthread_mutex_trylock(&(rwl->mtxSharedAccessCompleted))) != 0) { - result = EBUSY; /* held by either writer or reader(s) */ + result1 = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return ((result1 != 0) ? result1 : result); } - else + + if (rwl->nExclusiveAccessCount == 0) { - rw->rw_refcount = -1; /* available, indicate a writer has it */ - } + if (rwl->nCompletedSharedAccessCount > 0) + { + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + } -FAIL1: - (void) pthread_mutex_unlock(&(rw->rw_lock)); + if (rwl->nSharedAccessCount > 0) + { + if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; + } + + if ((result = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess))) == 0) + { + result = EBUSY; + } + } + else + { + rwl->nExclusiveAccessCount = 1; + } + } + else + { + result = EBUSY; + } - return(result); + return result; } |