From 9031537658e89136c6a5bb959f9b9a4338a5d056 Mon Sep 17 00:00:00 2001 From: rpj Date: Wed, 15 Sep 1999 00:56:21 +0000 Subject: Sat Sep 10 12:56:13 1999 Ross Johnson The following code for POSIX read/write locks was contributed by Aurelio Medina. * implement.h (pthread_rwlock_t_): Add. * pthread.h (pthread_rwlock_t): Add. (PTHREAD_RWLOCK_INITIALIZER): Add. Add rwlock function prototypes. * rwlock.c: New module. * pthread.def: Add new rwlock functions. * private.c (_pthread_processInitialize): initialise _pthread_rwlock_test_init_lock critical section. * global.c (_pthread_rwlock_test_init_lock): Add. * mutex.c (pthread_mutex_destroy): Don't free mutex memory if mutex is PTHREAD_MUTEX_INITIALIZER and has not been initialised yet. tests/ChangeLog Sep 15 1999 Ross Johnson * rwlock1.c: New test. * rwlock2.c: New test. * rwlock3.c: New test. * rwlock4.c: New test. --- ANNOUNCE | 27 +++- CONTRIBUTORS | 2 + ChangeLog | 13 ++ Makefile | 10 +- Makefile.in | 4 +- buildlib.bat | 1 + global.c | 6 + implement.h | 17 +++ private.c | 4 +- pthread.def | 12 +- pthread.h | 34 +++++ rwlock.c | 450 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/ChangeLog | 7 + tests/runall.bat | 4 + tests/rwlock1.c | 31 ++++ tests/rwlock2.c | 34 +++++ tests/rwlock3.c | 44 ++++++ tests/rwlock4.c | 44 ++++++ 18 files changed, 728 insertions(+), 16 deletions(-) create mode 100644 rwlock.c create mode 100644 tests/rwlock1.c create mode 100644 tests/rwlock2.c create mode 100644 tests/rwlock3.c create mode 100644 tests/rwlock4.c diff --git a/ANNOUNCE b/ANNOUNCE index f35d39d..ec8eeac 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -24,14 +24,15 @@ Change Summary (since the last snapshot) (See the ChangeLog file for details.) -Fixed exception stack cleanup if calling pthread_exit() -- (Lorin Hochstein and John Bossom). +Fixed a few bugs: + - threads return status properly (Milan Gardian) + - fix memory leak in mutexes (Milan Gardian) -Fixed bugs in condition variables - (Peter Slacik): - - additional contention checks - - properly adjust number of waiting threads after timed - condvar timeout. +Added new POSIX read/write locks (Aurelio Medina) +These routines have not been fully tested yet. +Changes to allow building with mingw32/MSCVRT (Mumit Khan) +This still needs a little work. Level of standards conformance ------------------------------ @@ -150,12 +151,24 @@ The following functions are implemented: --------------------------- pthread_sigmask + --------------------------- + Read/Write Locks: + --------------------------- + pthread_rwlock_init + pthread_rwlock_destroy + pthread_rwlock_tryrdlock + pthread_rwlock_trywrlock + pthread_rwlock_rdlock + pthread_rwlock_rwlock + pthread_rwlock_unlock + --------------------------- Static Initializers (macros) --------------------------- PTHREAD_ONCE_INIT PTHREAD_MUTEX_INITIALIZER - PTHREAD_COND_INITIALIZER + PTHREAD_COND_INITIALIZER + PTHREAD_RWLOCK_INITIALIZER --------------------------- Thread-Safe C Runtime Library (macros) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index b4780bd..f16ef20 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -12,3 +12,5 @@ Mark E. Armstrong avail@pacbell.net Lorin Hochstein lmh@xiphos.ca Peter Slacik Peter.Slacik@tatramed.sk Mumit Khan khan@xraylith.wisc.edu +Aurelio Medina aureliom@crt.com +Milan Gardian mg@tatramed.sk diff --git a/ChangeLog b/ChangeLog index 7309f0d..d439916 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,18 @@ Sat Sep 10 12:56:13 1999 Ross Johnson + The following code for POSIX read/write locks was contributed + by Aurelio Medina. + + * implement.h (pthread_rwlock_t_): Add. + * pthread.h (pthread_rwlock_t): Add. + (PTHREAD_RWLOCK_INITIALIZER): Add. + Add rwlock function prototypes. + * rwlock.c: New module. + * pthread.def: Add new rwlock functions. + * private.c (_pthread_processInitialize): initialise + _pthread_rwlock_test_init_lock critical section. + * global.c (_pthread_rwlock_test_init_lock): Add. + * mutex.c (pthread_mutex_destroy): Don't free mutex memory if mutex is PTHREAD_MUTEX_INITIALIZER and has not been initialised yet. diff --git a/Makefile b/Makefile index 55228a9..f0d8982 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ CC = g++ AR = ar -LD = gcc -mdll -e _DllMain@12 +LD = gcc -mdll OPT = -g -O2 @@ -34,11 +34,11 @@ CFLAGS = $(OPT) -I. -DHAVE_CONFIG_H -Wall ## Cygwin G++ #CFLAGS = $(OPT) -fhandle-exceptions -I. -DHAVE_CONFIG_H -Wall -OBJS = attr.o cancel.o cleanup.o condvar.o create.o dll.o \ - exit.o fork.o global.o misc.o mutex.o private.o sched.o \ - semaphore.o signal.o sync.o tsd.o +OBJS = attr.o cancel.o cleanup.o condvar.o create.o dll.o errno.o \ + exit.o fork.o global.o misc.o mutex.o private.o rwlock.o \ + sched.o semaphore.o signal.o sync.o tsd.o -INCL = implement.h pthread.h windows.h +INCL = implement.h semaphore.h pthread.h windows.h DLL = pthread.dll diff --git a/Makefile.in b/Makefile.in index 518061e..f0d8982 100644 --- a/Makefile.in +++ b/Makefile.in @@ -35,8 +35,8 @@ CFLAGS = $(OPT) -I. -DHAVE_CONFIG_H -Wall #CFLAGS = $(OPT) -fhandle-exceptions -I. -DHAVE_CONFIG_H -Wall OBJS = attr.o cancel.o cleanup.o condvar.o create.o dll.o errno.o \ - exit.o fork.o global.o misc.o mutex.o private.o sched.o \ - semaphore.o signal.o sync.o tsd.o + exit.o fork.o global.o misc.o mutex.o private.o rwlock.o \ + sched.o semaphore.o signal.o sync.o tsd.o INCL = implement.h semaphore.h pthread.h windows.h diff --git a/buildlib.bat b/buildlib.bat index 5e2e1c8..c2c5c4f 100644 --- a/buildlib.bat +++ b/buildlib.bat @@ -17,6 +17,7 @@ cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c signal cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c sync.c cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c tsd.c cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c semaphore.c +cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c rwlock.c cl /LD /Zi *.obj /Fepthread.dll /link /nodefaultlib:libcmt /implib:pthread.lib msvcrt.lib /def:pthread.def diff --git a/global.c b/global.c index 9db308a..c0173bb 100644 --- a/global.c +++ b/global.c @@ -44,5 +44,11 @@ CRITICAL_SECTION _pthread_mutex_test_init_lock; */ CRITICAL_SECTION _pthread_cond_test_init_lock; +/* + * Global lock for testing internal state of PTHREAD_RWLOCK_INITIALIZER + * created read/write locks. + */ +CRITICAL_SECTION _pthread_rwlock_test_init_lock; + diff --git a/implement.h b/implement.h index 11d5b1b..b48b2f2 100644 --- a/implement.h +++ b/implement.h @@ -161,6 +161,22 @@ struct pthread_condattr_t_ { int pshared; }; +#define RW_MAGIC 0x19283746 + +struct pthread_rwlock_t_ { + pthread_mutex_t rw_mutex; /* basic lock on this struct */ + pthread_cond_t rw_condreaders; /* for reader threads waiting */ + pthread_cond_t rw_condwriters; /* for writer threads waiting */ + int rw_magic; /* for error checking */ + int rw_nwaitreaders; /* the number waiting */ + int rw_nwaitwriters; /* the number waiting */ + int rw_refcount; /* -1 if writer has the lock, + else # readers holding the lock */ +}; + +struct pthread_rwlockattr_t_ { + int pshared; +}; struct ThreadKeyAssoc { /* @@ -297,6 +313,7 @@ extern pthread_key_t _pthread_selfThreadKey; extern pthread_key_t _pthread_cleanupKey; extern CRITICAL_SECTION _pthread_mutex_test_init_lock; extern CRITICAL_SECTION _pthread_cond_test_init_lock; +extern CRITICAL_SECTION _pthread_rwlock_test_init_lock; #ifdef __cplusplus diff --git a/private.c b/private.c index ede6b14..cd01fe5 100644 --- a/private.c +++ b/private.c @@ -77,6 +77,7 @@ _pthread_processInitialize (void) */ InitializeCriticalSection(&_pthread_mutex_test_init_lock); InitializeCriticalSection(&_pthread_cond_test_init_lock); + InitializeCriticalSection(&_pthread_rwlock_test_init_lock); return (_pthread_processInitialized); @@ -131,8 +132,9 @@ _pthread_processTerminate (void) /* * Destroy the global test and init check locks. */ - DeleteCriticalSection(&_pthread_mutex_test_init_lock); + DeleteCriticalSection(&_pthread_rwlock_test_init_lock); DeleteCriticalSection(&_pthread_cond_test_init_lock); + DeleteCriticalSection(&_pthread_mutex_test_init_lock); _pthread_processInitialized = FALSE; } diff --git a/pthread.def b/pthread.def index b7d1ce9..6920d5a 100644 --- a/pthread.def +++ b/pthread.def @@ -1,5 +1,5 @@ ; pthread.def -; Last updated: $Date: 1999/05/29 06:44:34 $ +; Last updated: $Date: 1999/09/15 00:56:22 $ ; Currently unimplemented functions are commented out. @@ -88,6 +88,16 @@ sem_close sem_unlink sem_getvalue ; +; Read/Write Locks +; +pthread_rwlock_init +pthread_rwlock_destroy +pthread_rwlock_tryrdlock +pthread_rwlock_trywrlock +pthread_rwlock_rdlock +pthread_rwlock_wrlock +pthread_rwlock_unlock +; ; Non-portable but useful ; pthread_mutexattr_setforcecs_np diff --git a/pthread.h b/pthread.h index af982b3..ebf9854 100644 --- a/pthread.h +++ b/pthread.h @@ -122,6 +122,17 @@ * --------------------------- * pthread_sigmask * + * --------------------------- + * Read/Write Locks: + * --------------------------- + * pthread_rwlock_init + * pthread_rwlock_destroy + * pthread_rwlock_tryrdlock + * pthread_rwlock_trywrlock + * pthread_rwlock_rdlock + * pthread_rwlock_rwlock + * pthread_rwlock_unlock + * * Limitations * =========== * The following functions are not implemented: @@ -418,6 +429,8 @@ typedef struct pthread_mutex_t_ *pthread_mutex_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; +typedef struct pthread_rwlock_t_ *pthread_rwlock_t; +typedef struct pthread_rwlockattr_t_ *pthread_rwlockattr_t; /* @@ -496,6 +509,8 @@ struct pthread_once_t_ #define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1) +#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1) + /* * ==================== @@ -845,6 +860,25 @@ int pthread_attr_getschedparam (const pthread_attr_t *attr, int pthread_attr_setschedparam (pthread_attr_t *attr, const struct sched_param *param); +/* + * Read-Write Lock Functions + */ + +int pthread_rwlock_init(pthread_rwlock_t *lock, + const pthread_rwlockattr_t *attr); + +int pthread_rwlock_destroy(pthread_rwlock_t *lock); + +int pthread_rwlock_tryrdlock(pthread_rwlock_t *); + +int pthread_rwlock_trywrlock(pthread_rwlock_t *); + +int pthread_rwlock_rdlock(pthread_rwlock_t *lock); + +int pthread_rwlock_wrlock(pthread_rwlock_t *lock); + +int pthread_rwlock_unlock(pthread_rwlock_t *lock); + /* * Protected Methods * diff --git a/rwlock.c b/rwlock.c new file mode 100644 index 0000000..499de59 --- /dev/null +++ b/rwlock.c @@ -0,0 +1,450 @@ +/* + * rwlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright (C) 1998 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +static int +_rwlock_check_need_init(pthread_rwlock_t *rwlock) +{ + int result = 0; + + /* + * The following guarded test is specifically for statically + * initialised rwlocks (via PTHREAD_RWLOCK_INITIALIZER). + * + * Note that by not providing this synchronisation we risk + * introducing race conditions into applications which are + * correctly written. + * + * Approach + * -------- + * We know that static rwlocks will not be PROCESS_SHARED + * so we can serialise access to internal state using + * Win32 Critical Sections rather than Win32 Mutexes. + * + * 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. + * + */ + EnterCriticalSection(&_pthread_rwlock_test_init_lock); + + /* + * We got here possibly under race + * conditions. Check 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 (*rwlock == (pthread_rwlock_t) _PTHREAD_OBJECT_AUTO_INIT) + { + result = pthread_rwlock_init(rwlock, NULL); + } + + LeaveCriticalSection(&_pthread_rwlock_test_init_lock); + + return(result); +} + +int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) +{ + int result = 0; + pthread_rwlock_t rw; + + if (rwlock == NULL) + { + return EINVAL; + } + + rw = *rwlock; + + rw = (pthread_rwlock_t) calloc(1, sizeof(*rw)); + + if (rw == NULL) + { + result = ENOMEM; + goto fail0; + } + + if (attr != NULL + && *attr != NULL) + { + result = EINVAL; /* Not supported */ + goto fail0; + } + + if ((result = pthread_mutex_init(&rw->rw_mutex, NULL)) != 0) + { + goto fail1; + } + + if ((result = pthread_cond_init(&rw->rw_condreaders, NULL)) != 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; + + result = 0; + goto fail0; + +fail3: + pthread_cond_destroy(&rw->rw_condreaders); + +fail2: + pthread_mutex_destroy(&rw->rw_mutex); + +fail1: +fail0: + *rwlock = rw; + + return(result); /* an errno value */ +} + +int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t rw; + + if (rwlock == NULL || *rwlock == NULL || (*rwlock)->rw_magic != RW_MAGIC) + { + return(EINVAL); + } + + if (*rwlock == (pthread_rwlock_t) _PTHREAD_OBJECT_AUTO_INIT) + { + /* + * Destroy a static declared R/W lock that has never been + * initialised. + */ + *rwlock = NULL; + return(0); + } + + rw = *rwlock; + + if (rw->rw_refcount != 0 + || rw->rw_nwaitreaders != 0 + || rw->rw_nwaitwriters != 0) + { + return(EBUSY); + } + + pthread_mutex_destroy(&rw->rw_mutex); + pthread_cond_destroy(&rw->rw_condreaders); + pthread_cond_destroy(&rw->rw_condwriters); + rw->rw_magic = 0; + free(rw); + *rwlock = NULL; + + return(0); +} + +static void _rwlock_cancelrdwait(void *arg) +{ + pthread_rwlock_t rw; + + rw = arg; + rw->rw_nwaitreaders--; + pthread_mutex_unlock(&rw->rw_mutex); +} + +int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) +{ + int result = 0; + pthread_rwlock_t rw; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of _rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == (pthread_rwlock_t) _PTHREAD_OBJECT_AUTO_INIT) + { + result = _rwlock_check_need_init(rwlock); + } + + rw = *rwlock; + + if (rw->rw_magic != RW_MAGIC) + { + return(EINVAL); + } + + if ((result = pthread_mutex_lock(&rw->rw_mutex)) != 0) + { + return(result); + } + + /* give preference to waiting writers */ + while (rw->rw_refcount < 0 || rw->rw_nwaitwriters > 0) + { + rw->rw_nwaitreaders++; + pthread_cleanup_push(_rwlock_cancelrdwait, rw); + result = pthread_cond_wait(&rw->rw_condreaders, &rw->rw_mutex); + pthread_cleanup_pop(0); + rw->rw_nwaitreaders--; + + if (result != 0) + { + break; + } + } + + if (result == 0) + { + rw->rw_refcount++; /* another reader has a read lock */ + } + + pthread_mutex_unlock(&rw->rw_mutex); + + return(result); +} + +static void _rwlock_cancelwrwait(void *arg) +{ + pthread_rwlock_t rw; + + rw = arg; + rw->rw_nwaitwriters--; + pthread_mutex_unlock(&rw->rw_mutex); +} + +int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) +{ + int result; + pthread_rwlock_t rw; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of _rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == (pthread_rwlock_t) _PTHREAD_OBJECT_AUTO_INIT) + { + result = _rwlock_check_need_init(rwlock); + } + + rw = *rwlock; + + if (rw->rw_magic != RW_MAGIC) + return(EINVAL); + + if ( (result = pthread_mutex_lock(&rw->rw_mutex)) != 0) + return(result); + + while (rw->rw_refcount != 0) { + rw->rw_nwaitwriters++; + pthread_cleanup_push(_rwlock_cancelwrwait, rw); + result = pthread_cond_wait(&rw->rw_condwriters, &rw->rw_mutex); + pthread_cleanup_pop(0); + rw->rw_nwaitwriters--; + if (result != 0) + break; + } + if (result == 0) + rw->rw_refcount = -1; + + pthread_mutex_unlock(&rw->rw_mutex); + return(result); +} + +int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) +{ + int result = 0; + pthread_rwlock_t rw; + + if (rwlock == NULL || *rwlock == NULL) + { + return(EINVAL); + } + + if (*rwlock == (pthread_rwlock_t) _PTHREAD_OBJECT_AUTO_INIT) + { + return(0); + } + + rw = *rwlock; + + if (rw->rw_magic != RW_MAGIC) + { + return(EINVAL); + } + + if ( (result = pthread_mutex_lock(&rw->rw_mutex)) != 0) + { + return(result); + } + + if (rw->rw_refcount > 0) + { + rw->rw_refcount--; /* releasing a reader */ + } + else if (rw->rw_refcount == -1) + { + rw->rw_refcount = 0; /* releasing a writer */ + } + else + { + return(EINVAL); + } + + result = 0; + + /* + * Give preference to waiting writers over waiting readers + */ + if (rw->rw_nwaitwriters > 0) + { + if (rw->rw_refcount == 0) + { + result = pthread_cond_signal(&rw->rw_condwriters); + } + } + else if (rw->rw_nwaitreaders > 0) + { + result = pthread_cond_broadcast(&rw->rw_condreaders); + } + + pthread_mutex_unlock(&rw->rw_mutex); + return(result); +} + +int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) +{ + int result = 0; + pthread_rwlock_t rw; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of _rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == (pthread_rwlock_t) _PTHREAD_OBJECT_AUTO_INIT) + { + result = _rwlock_check_need_init(rwlock); + } + + rw = *rwlock; + + if (rw->rw_magic != RW_MAGIC) + { + return(EINVAL); + } + + if ( (result = pthread_mutex_lock(&rw->rw_mutex)) != 0) + { + return(result); + } + + if (rw->rw_refcount == -1 || rw->rw_nwaitwriters > 0) + { + result = EBUSY; /* held by a writer or waiting writers */ + } + else + { + rw->rw_refcount++; /* increment count of reader locks */ + } + + pthread_mutex_unlock(&rw->rw_mutex); + return(result); +} + +int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) +{ + int result = 0; + pthread_rwlock_t rw; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of _rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == (pthread_rwlock_t) _PTHREAD_OBJECT_AUTO_INIT) + { + result = _rwlock_check_need_init(rwlock); + } + + rw = *rwlock; + + if (rw->rw_magic != RW_MAGIC) + { + return(EINVAL); + } + + if ( (result = pthread_mutex_lock(&rw->rw_mutex)) != 0) + { + return(result); + } + + if (rw->rw_refcount != 0) + { + result = EBUSY; /* held by either writer or reader(s) */ + } + else + { + rw->rw_refcount = -1; /* available, indicate a writer has it */ + } + + pthread_mutex_unlock(&rw->rw_mutex); + return(result); +} diff --git a/tests/ChangeLog b/tests/ChangeLog index 1ee3634..4ee832c 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,10 @@ +Sep 15 1999 Ross Johnson + + * rwlock1.c: New test. + * rwlock2.c: New test. + * rwlock3.c: New test. + * rwlock4.c: New test. + Aug 22 1999 Ross Johnson * runall.bat (join2): Add test. diff --git a/tests/runall.bat b/tests/runall.bat index 8086fc3..78a94b6 100644 --- a/tests/runall.bat +++ b/tests/runall.bat @@ -25,3 +25,7 @@ call runtest cl condvar4 call runtest cl condvar5 call runtest cl condvar6 call runtest cl errno1 +call runtest cl rwlock1 +call runtest cl rwlock2 +call runtest cl rwlock3 +call runtest cl rwlock4 diff --git a/tests/rwlock1.c b/tests/rwlock1.c new file mode 100644 index 0000000..540ef7a --- /dev/null +++ b/tests/rwlock1.c @@ -0,0 +1,31 @@ +/* + * rwlock1.c + * + * Create a simple rwlock object, lock it, and then unlock it again. + * + * Depends on API functions: + * pthread_rwlock_init() + * pthread_rwlock_lock() + * pthread_rwlock_unlock() + * pthread_rwlock_destroy() + */ + +#include "test.h" + +pthread_rwlock_t rwlock = NULL; + +int +main() +{ + assert(rwlock == NULL); + + assert(pthread_rwlock_init(&rwlock, NULL) == 0); + + assert(rwlock != NULL); + + assert(pthread_rwlock_destroy(&rwlock) == 0); + + assert(rwlock == NULL); + + return 0; +} diff --git a/tests/rwlock2.c b/tests/rwlock2.c new file mode 100644 index 0000000..cfb3228 --- /dev/null +++ b/tests/rwlock2.c @@ -0,0 +1,34 @@ +/* + * rwlock2.c + * + * Declare a static rwlock object, lock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_rwlock_rdlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + +pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; + +int +main() +{ + assert(rwlock == PTHREAD_RWLOCK_INITIALIZER); + + assert(pthread_rwlock_rdlock(&rwlock) == 0); + + assert(rwlock != PTHREAD_RWLOCK_INITIALIZER); + + assert(rwlock != NULL); + + assert(pthread_rwlock_unlock(&rwlock) == 0); + + assert(pthread_rwlock_destroy(&rwlock) == 0); + + assert(rwlock == NULL); + + return 0; +} diff --git a/tests/rwlock3.c b/tests/rwlock3.c new file mode 100644 index 0000000..92e8286 --- /dev/null +++ b/tests/rwlock3.c @@ -0,0 +1,44 @@ +/* + * rwlock3.c + * + * Declare a static rwlock object, lock it, trylock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_rwlock_wrlock() + * pthread_rwlock_trywrlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + +pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + +static int washere = 0; + +void * func(void * arg) +{ + assert(pthread_rwlock_trywrlock(&rwlock1) == EBUSY); + + washere = 1; + + return 0; +} + +int +main() +{ + pthread_t t; + + assert(pthread_rwlock_wrlock(&rwlock1) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + + Sleep(2000); + + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + assert(washere == 1); + + return 0; +} diff --git a/tests/rwlock4.c b/tests/rwlock4.c new file mode 100644 index 0000000..07e4cff --- /dev/null +++ b/tests/rwlock4.c @@ -0,0 +1,44 @@ +/* + * rwlock3.c + * + * Declare a static rwlock object, rdlock it, trywrlock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_rwlock_rdlock() + * pthread_rwlock_trywrlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + +pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + +static int washere = 0; + +void * func(void * arg) +{ + assert(pthread_rwlock_trywrlock(&rwlock1) == EBUSY); + + washere = 1; + + return 0; +} + +int +main() +{ + pthread_t t; + + assert(pthread_rwlock_rdlock(&rwlock1) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + + Sleep(2000); + + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + assert(washere == 1); + + return 0; +} -- cgit v1.2.3