diff options
-rw-r--r-- | ANNOUNCE | 27 | ||||
-rw-r--r-- | CONTRIBUTORS | 2 | ||||
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | Makefile.in | 4 | ||||
-rw-r--r-- | buildlib.bat | 1 | ||||
-rw-r--r-- | global.c | 6 | ||||
-rw-r--r-- | implement.h | 17 | ||||
-rw-r--r-- | private.c | 4 | ||||
-rw-r--r-- | pthread.def | 12 | ||||
-rw-r--r-- | pthread.h | 34 | ||||
-rw-r--r-- | rwlock.c | 450 | ||||
-rw-r--r-- | tests/ChangeLog | 7 | ||||
-rw-r--r-- | tests/runall.bat | 4 | ||||
-rw-r--r-- | tests/rwlock1.c | 31 | ||||
-rw-r--r-- | tests/rwlock2.c | 34 | ||||
-rw-r--r-- | tests/rwlock3.c | 44 | ||||
-rw-r--r-- | tests/rwlock4.c | 44 |
18 files changed, 728 insertions, 16 deletions
@@ -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 ------------------------------ @@ -151,11 +152,23 @@ 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 @@ -1,5 +1,18 @@ Sat Sep 10 12:56:13 1999 Ross Johnson <rpj@swan.canberra.edu.au> + 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. @@ -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 @@ -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 @@ -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 @@ -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) + /* * ==================== @@ -846,6 +861,25 @@ 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 * * This function blocks until the given WIN32 handle 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 <errno.h>
+
+#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 <rpj@ixobrychus.canberra.edu.au> + + * rwlock1.c: New test. + * rwlock2.c: New test. + * rwlock3.c: New test. + * rwlock4.c: New test. + Aug 22 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au> * 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; +} |