summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrpj <rpj>2001-02-07 03:48:23 +0000
committerrpj <rpj>2001-02-07 03:48:23 +0000
commit2f4a1905d1a8c424900a8615ec730f7637482525 (patch)
tree9c35a724f9d033b81afb26c83612a2d88208a073
parent9a59a1b4611cbd4b1fcf7549a97dc2cbe340b794 (diff)
Revamp read-write locks and update cond vars.
See ChangeLog.
-rw-r--r--ChangeLog12
-rw-r--r--condvar.c371
-rw-r--r--implement.h159
-rw-r--r--rwlock.c434
-rw-r--r--tests/rwlock6.c110
5 files changed, 543 insertions, 543 deletions
diff --git a/ChangeLog b/ChangeLog
index 0606071..074526f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2001-02-07 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * rwlock.c: Revamped.
+ This implementation does not have reader/writer starvation problem.
+ I've tried to make rwlock to behaive 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.
+ - Alexander Terekhov <TEREKHOV@de.ibm.com>
+
2001-02-06 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
* condvar.c (pthread_cond_init): Completely revamped.
diff --git a/condvar.c b/condvar.c
index 2974000..99871f9 100644
--- a/condvar.c
+++ b/condvar.c
@@ -27,7 +27,7 @@
#include "implement.h"
static int
-ptw32_cond_check_need_init(pthread_cond_t *cond)
+ptw32_cond_check_need_init (pthread_cond_t *cond)
{
int result = 0;
@@ -77,7 +77,7 @@ ptw32_cond_check_need_init(pthread_cond_t *cond)
LeaveCriticalSection(&ptw32_cond_test_init_lock);
- return(result);
+ return result;
}
@@ -124,7 +124,7 @@ pthread_condattr_init (pthread_condattr_t * attr)
*attr = attr_result;
- return (result);
+ return result;
} /* pthread_condattr_init */
@@ -162,17 +162,16 @@ pthread_condattr_destroy (pthread_condattr_t * attr)
if (attr == NULL || *attr == NULL)
{
result = EINVAL;
-
}
else
{
- free (*attr);
+ (void) free (*attr);
*attr = NULL;
result = 0;
}
- return (result);
+ return result;
} /* pthread_condattr_destroy */
@@ -220,13 +219,10 @@ pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared)
{
int result;
- if ((attr != NULL && *attr != NULL) &&
- (pshared != NULL))
+ if ((attr != NULL && *attr != NULL) && (pshared != NULL))
{
-
*pshared = (*attr)->pshared;
result = 0;
-
}
else
{
@@ -234,7 +230,7 @@ pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared)
result = EINVAL;
}
- return (result);
+ return result;
} /* pthread_condattr_getpshared */
@@ -284,12 +280,10 @@ pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared)
{
int result;
- if ((attr != NULL && *attr != NULL) &&
- ((pshared == PTHREAD_PROCESS_SHARED) ||
- (pshared == PTHREAD_PROCESS_PRIVATE)))
+ if ((attr != NULL && *attr != NULL)
+ && ((pshared == PTHREAD_PROCESS_SHARED)
+ || (pshared == PTHREAD_PROCESS_PRIVATE)))
{
-
-
if (pshared == PTHREAD_PROCESS_SHARED)
{
@@ -306,19 +300,19 @@ pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared)
{
result = 0;
}
- (*attr)->pshared = pshared;
+ (*attr)->pshared = pshared;
}
else
{
result = EINVAL;
-
}
- return (result);
+ return result;
} /* pthread_condattr_setpshared */
+
int
pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
/*
@@ -348,7 +342,7 @@ pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
* ------------------------------------------------------
*/
{
- int result = EAGAIN;
+ int result;
pthread_cond_t cv = NULL;
if (cond == NULL)
@@ -364,16 +358,15 @@ pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
* processes.
*/
result = ENOSYS;
-
- goto FAIL0;
+ goto DONE;
}
- cv = (pthread_cond_t) calloc (1, sizeof (*cv));
+ cv = (pthread_cond_t) calloc(1, sizeof (*cv));
if (cv == NULL)
{
result = ENOMEM;
- goto FAIL0;
+ goto DONE;
}
cv->nWaitersBlocked = 0;
@@ -382,20 +375,21 @@ pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
if (sem_init(&(cv->semBlockLock), 0, 1) != 0)
{
+ result = errno;
goto FAIL0;
}
if (sem_init(&(cv->semBlockQueue), 0, 0) != 0)
{
+ result = errno;
goto FAIL1;
}
- if (pthread_mutex_init(&(cv->mtxUnblockLock), 0) != 0)
+ if ((result = pthread_mutex_init(&(cv->mtxUnblockLock), 0)) != 0)
{
goto FAIL2;
}
-
result = 0;
goto DONE;
@@ -412,13 +406,17 @@ FAIL1:
(void) sem_destroy(&(cv->semBlockLock));
FAIL0:
+ (void) free(cv);
+ cv = NULL;
+
DONE:
*cond = cv;
- return (result);
+ return result;
} /* pthread_cond_init */
+
int
pthread_cond_destroy (pthread_cond_t * cond)
/*
@@ -447,13 +445,13 @@ pthread_cond_destroy (pthread_cond_t * cond)
* ------------------------------------------------------
*/
{
- int result = 0;
pthread_cond_t cv;
+ int result = 0, result1 = 0, result2 = 0;
/*
* Assuming any race condition here is harmless.
*/
- if (cond == NULL
+ if (cond == NULL
|| *cond == NULL)
{
return EINVAL;
@@ -485,20 +483,34 @@ pthread_cond_destroy (pthread_cond_t * cond)
*/
if (cv->nWaitersBlocked - cv->nWaitersUnblocked > 0)
{
- (void) sem_post(&(cv->semBlockLock));
- (void) pthread_mutex_unlock(&(cv->mtxUnblockLock));
- return EBUSY;
+ if (sem_post(&(cv->semBlockLock)) != 0)
+ {
+ result = errno;
+ }
+ result1 = pthread_mutex_unlock(&(cv->mtxUnblockLock));
+ result2 = EBUSY;
+ }
+ else
+ {
+ /*
+ * Now it is safe to destroy
+ */
+ *cond = NULL;
+ if (sem_destroy(&(cv->semBlockLock)) != 0)
+ {
+ result = errno;
+ }
+ if (sem_destroy(&(cv->semBlockQueue)) != 0)
+ {
+ result1 = errno;
+ }
+ if ((result2 = pthread_mutex_unlock(&(cv->mtxUnblockLock))) == 0)
+ {
+ result2 = pthread_mutex_destroy(&(cv->mtxUnblockLock));
+ }
+
+ (void) free(cv);
}
-
- /*
- * Now it is safe to destroy
- */
- *cond = NULL; /* Invalidate it before anything else */
- (void) sem_destroy(&(cv->semBlockLock));
- (void) sem_destroy(&(cv->semBlockQueue));
- (void) pthread_mutex_unlock(&(cv->mtxUnblockLock));
- (void) pthread_mutex_destroy(&(cv->mtxUnblockLock));
- free(cv);
}
else
{
@@ -532,7 +544,8 @@ pthread_cond_destroy (pthread_cond_t * cond)
LeaveCriticalSection(&ptw32_cond_test_init_lock);
}
- return (result);
+ return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
+
}
/*
@@ -548,17 +561,16 @@ typedef struct {
static void
ptw32_cond_wait_cleanup(void * args)
{
- ptw32_cond_wait_cleanup_args_t * cleanup_args =
- (ptw32_cond_wait_cleanup_args_t *) args;
+ ptw32_cond_wait_cleanup_args_t * cleanup_args = (ptw32_cond_wait_cleanup_args_t *) args;
pthread_cond_t cv = cleanup_args->cv;
int * resultPtr = cleanup_args->resultPtr;
int eLastSignal; /* enum: 1=yes 0=no -1=cancelled/timedout w/o signal(s) */
int result;
/*
- * Whether we got here as a result of signal/broadcast or because of
- * timeout on wait or thread cancellation we indicate that we are no
- * longer waiting. The waiter is responsible for adjusting waiters
+ * Whether we got here as a result of signal/broadcast or because of
+ * timeout on wait or thread cancellation we indicate that we are no
+ * longer waiting. The waiter is responsible for adjusting waiters
* (to)unblock(ed) counts (protected by unblock lock).
* Unblock lock/Sync.LEVEL-2 supports _timedwait and cancellation.
*/
@@ -575,7 +587,7 @@ ptw32_cond_wait_cleanup(void * args)
/*
* No more LEVEL-2 access to waiters (to)unblock(ed) counts needed
*/
- if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
+ if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
{
*resultPtr = result;
return;
@@ -611,14 +623,15 @@ ptw32_cond_wait_cleanup(void * args)
}
/*
- * XSH: Upon successful return, the mutex has been locked and is owned
+ * XSH: Upon successful return, the mutex has been locked and is owned
* by the calling thread
*/
if ((result = pthread_mutex_lock(cleanup_args->mutexPtr)) != 0)
{
*resultPtr = result;
}
-}
+
+} /* ptw32_cond_wait_cleanup */
static int
ptw32_cond_timedwait (pthread_cond_t * cond,
@@ -692,13 +705,13 @@ ptw32_cond_timedwait (pthread_cond_t * cond,
* timeout, or
* thread cancellation
*
- * Note:
+ * Note:
*
* ptw32_sem_timedwait is a cancellation point,
- * hence providing the mechanism for making
- * pthread_cond_wait a cancellation point.
+ * hence providing the mechanism for making
+ * pthread_cond_wait a cancellation point.
* We use the cleanup mechanism to ensure we
- * re-lock the mutex and adjust (to)unblock(ed) waiters
+ * re-lock the mutex and adjust (to)unblock(ed) waiters
* counts if we are cancelled, timed out or signalled.
*/
if (ptw32_sem_timedwait(&(cv->semBlockQueue), abstime) != 0)
@@ -712,18 +725,115 @@ ptw32_cond_timedwait (pthread_cond_t * cond,
*/
pthread_cleanup_pop(1);
-
/*
* "result" can be modified by the cleanup handler.
*/
- return (result);
+ return result;
} /* ptw32_cond_timedwait */
+static int
+ptw32_cond_unblock (pthread_cond_t * cond,
+ int unblockAll)
+{
+ int result;
+ pthread_cond_t cv;
+
+ if (cond == NULL || *cond == NULL)
+ {
+ return EINVAL;
+ }
+
+ cv = *cond;
+
+ /*
+ * No-op if the CV is static and hasn't been initialised yet.
+ * Assuming that any race condition is harmless.
+ */
+ if (cv == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
+ {
+ return 0;
+ }
+
+ /*
+ * Synchronize access to waiters blocked count (LEVEL-1)
+ */
+ if (sem_wait(&(cv->semBlockLock)) != 0)
+ {
+ return errno;
+ }
+
+ /*
+ * Synchronize access to waiters (to)unblock(ed) counts (LEVEL-2)
+ * This sync.level supports _timedwait and cancellation
+ */
+ if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
+ {
+ return result;
+ }
+
+ /*
+ * Adjust waiters blocked and unblocked counts (collect garbage)
+ */
+ if (cv->nWaitersUnblocked != 0)
+ {
+ cv->nWaitersBlocked -= cv->nWaitersUnblocked;
+ cv->nWaitersUnblocked = 0;
+ }
+
+ /*
+ * If (after adjustment) there are still some waiters blocked counted...
+ */
+ if ( cv->nWaitersBlocked > 0)
+ {
+ /*
+ * We will unblock first waiter and leave semBlockLock/LEVEL-1 locked
+ * LEVEL-1 access is left disabled until last signal/unblock completes
+ */
+ cv->nWaitersToUnblock = (unblockAll) ? cv->nWaitersBlocked : 1;
+
+ /*
+ * No more LEVEL-2 access to waiters (to)unblock(ed) counts needed
+ * This sync.level supports _timedwait and cancellation
+ */
+ if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
+ {
+ return result;
+ }
+
+
+ /*
+ * Now, with LEVEL-2 lock released let first waiter go through semaphore
+ */
+ if (sem_post(&(cv->semBlockQueue)) != 0)
+ {
+ return errno;
+ }
+ }
+ /*
+ * No waiter blocked - no more LEVEL-1 access to blocked count needed...
+ */
+ else if (sem_post(&(cv->semBlockLock)) != 0)
+ {
+ return errno;
+ }
+ /*
+ * ...and no more LEVEL-2 access to waiters (to)unblock(ed) counts needed too
+ * This sync.level supports _timedwait and cancellation
+ */
+ else
+ {
+ result = pthread_mutex_unlock(&(cv->mtxUnblockLock));
+ }
+
+ return result;
+
+} /* ptw32_cond_unblock */
+
int
pthread_cond_wait (pthread_cond_t * cond,
- pthread_mutex_t * mutex)
+ pthread_mutex_t * mutex)
/*
* ------------------------------------------------------
* DOCPUBLIC
@@ -748,8 +858,9 @@ pthread_cond_wait (pthread_cond_t * cond,
* awakened by a signal or broadcast.
*
* NOTES:
+ *
* 1) The function must be called with 'mutex' LOCKED
- * by the calling thread, or undefined behaviour
+ * by the calling thread, or undefined behaviour
* will result.
*
* 2) This routine atomically releases 'mutex' and causes
@@ -774,7 +885,7 @@ pthread_cond_wait (pthread_cond_t * cond,
/*
* The NULL abstime arg means INFINITE waiting.
*/
- return(ptw32_cond_timedwait(cond, mutex, NULL));
+ return (ptw32_cond_timedwait(cond, mutex, NULL));
} /* pthread_cond_wait */
@@ -808,7 +919,7 @@ pthread_cond_timedwait (pthread_cond_t * cond,
*
* NOTES:
* 1) The function must be called with 'mutex' LOCKED
- * by the calling thread, or undefined behaviour
+ * by the calling thread, or undefined behaviour
* will result.
*
* 2) This routine atomically releases 'mutex' and causes
@@ -828,118 +939,14 @@ pthread_cond_timedwait (pthread_cond_t * cond,
* ------------------------------------------------------
*/
{
- int result = 0;
-
if (abstime == NULL)
{
- result = EINVAL;
- }
- else
- {
- result = ptw32_cond_timedwait(cond, mutex, abstime);
- }
-
- return(result);
-} /* pthread_cond_timedwait */
-
-
-static int
-ptw32_cond_unblock (pthread_cond_t * cond,
- int unblockAll)
-{
- int result;
- pthread_cond_t cv;
-
- if (cond == NULL || *cond == NULL)
- {
return EINVAL;
}
- cv = *cond;
-
- /*
- * No-op if the CV is static and hasn't been initialised yet.
- * Assuming that any race condition is harmless.
- */
- if (cv == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
- {
- return 0;
- }
-
- /*
- * Synchronize access to waiters blocked count (LEVEL-1)
- */
- if (sem_wait(&(cv->semBlockLock)) != 0)
- {
- return errno;
- }
-
- /*
- * Synchronize access to waiters (to)unblock(ed) counts (LEVEL-2)
- * This sync.level supports _timedwait and cancellation
- */
- if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
- {
- return result;
- }
+ return (ptw32_cond_timedwait(cond, mutex, abstime));
- /*
- * Adjust waiters blocked and unblocked counts (collect garbage)
- */
- if (cv->nWaitersUnblocked != 0)
- {
- cv->nWaitersBlocked -= cv->nWaitersUnblocked;
- cv->nWaitersUnblocked = 0;
- }
-
- /*
- * If (after adjustment) there are still some waiters blocked counted...
- */
- if ( cv->nWaitersBlocked > 0)
- {
- /*
- * We will unblock first waiter and leave semBlockLock/LEVEL-1 locked
- * LEVEL-1 access is left disabled until last signal/unblock completes
- */
- cv->nWaitersToUnblock = (unblockAll) ? cv->nWaitersBlocked : 1;
-
- /*
- * No more LEVEL-2 access to waiters (to)unblock(ed) counts needed
- * This sync.level supports _timedwait and cancellation
- */
- if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
- {
- return result;
- }
-
-
- /*
- * Now, with LEVEL-2 lock released let first waiter go through semaphore
- */
- if (sem_post(&(cv->semBlockQueue)) != 0)
- {
- return errno;
- }
- }
- /*
- * No waiter blocked - no more LEVEL-1 access to blocked count needed...
- */
- else if (sem_post(&(cv->semBlockLock)) != 0)
- {
- return errno;
- }
- /*
- * ...and no more LEVEL-2 access to waiters (to)unblock(ed) counts needed too
- * This sync.level supports _timedwait and cancellation
- */
- else
- {
- result = pthread_mutex_unlock(&(cv->mtxUnblockLock));
- }
-
- return(result);
-
-} /* ptw32_cond_unblock */
+} /* pthread_cond_timedwait */
int
@@ -966,17 +973,10 @@ pthread_cond_signal (pthread_cond_t * cond)
* an unspecified waiter is awakened.
*
* NOTES:
+ *
* 1) Use when any waiter can respond and only one need
* respond (all waiters being equal).
*
- * 2) This function MUST be called under the protection
- * of the SAME mutex that is used with the condition
- * variable being signaled; OTHERWISE, the condition
- * variable may be signaled between the test of the
- * associated condition and the blocking
- * pthread_cond_signal.
- * This can cause an infinite wait.
- *
* RESULTS
* 0 successfully signaled condition,
* EINVAL 'cond' is invalid,
@@ -984,10 +984,10 @@ pthread_cond_signal (pthread_cond_t * cond)
* ------------------------------------------------------
*/
{
- /*
+ /*
* The '0'(FALSE) unblockAll arg means unblock ONE waiter.
*/
- return(ptw32_cond_unblock(cond, 0));
+ return (ptw32_cond_unblock(cond, 0));
} /* pthread_cond_signal */
@@ -1009,14 +1009,8 @@ pthread_cond_broadcast (pthread_cond_t * cond)
* all waiting threads.
*
* NOTES:
- * 1) This function MUST be called under the protection
- * of the SAME mutex that is used with the condition
- * variable being signaled; OTHERWISE, the condition
- * variable may be signaled between the test of the
- * associated condition and the blocking pthread_cond_wait.
- * This can cause an infinite wait.
- *
- * 2) Use when more than one waiter may respond to
+ *
+ * 1) Use when more than one waiter may respond to
* predicate change or if any waiting thread may
* not be able to respond
*
@@ -1029,10 +1023,9 @@ pthread_cond_broadcast (pthread_cond_t * cond)
* ------------------------------------------------------
*/
{
- /*
+ /*
* The '1'(TRUE) unblockAll arg means unblock ALL waiters.
*/
- return(ptw32_cond_unblock(cond, 1));
-
-}
+ return (ptw32_cond_unblock(cond, 1));
+} /* pthread_cond_broadcast */
diff --git a/implement.h b/implement.h
index ec889e3..353f4f9 100644
--- a/implement.h
+++ b/implement.h
@@ -46,13 +46,13 @@ typedef enum {
* The thread is still "alive" if the numeric value of the
* state is greater or equal "PThreadStateRunning".
*/
- PThreadStateInitial = 0, /* Thread not running */
- PThreadStateRunning, /* Thread alive & kicking */
- PThreadStateSuspended, /* Thread alive but suspended */
- PThreadStateCanceling, /* Thread alive but and is */
+ PThreadStateInitial = 0, /* Thread not running */
+ PThreadStateRunning, /* Thread alive & kicking */
+ PThreadStateSuspended, /* Thread alive but suspended */
+ PThreadStateCanceling, /* Thread alive but and is */
/* in the process of terminating */
/* due to a cancellation request */
- PThreadStateException, /* Thread alive but exiting */
+ PThreadStateException, /* Thread alive but exiting */
/* due to an exception */
PThreadStateLast
}
@@ -64,40 +64,14 @@ typedef enum {
* This enumeration represents the reason why a thread has
* terminated/is terminating.
*/
- PThreadDemisePeaceful = 0, /* Death due natural causes */
- PThreadDemiseCancelled, /* Death due to user cancel */
- PThreadDemiseException, /* Death due to unhandled */
+ PThreadDemisePeaceful = 0, /* Death due natural causes */
+ PThreadDemiseCancelled, /* Death due to user cancel */
+ PThreadDemiseException, /* Death due to unhandled */
/* exception */
- PThreadDemiseNotDead /* I'm not dead! */
+ PThreadDemiseNotDead /* I'm not dead! */
}
PThreadDemise;
-
-/*
- * ====================
- * ====================
- * Internal implementation of a critical section
- * ====================
- * ====================
- */
-
-typedef struct ptw32_cs_t_ {
- CRITICAL_SECTION cs;
- LONG lock_idx;
- int entered_count;
- int valid;
- pthread_t owner;
-} ptw32_cs_t;
-
-
-/*
- * ====================
- * ====================
- * POSIX thread and attributes
- * ====================
- * ====================
- */
-
struct pthread_t_ {
DWORD thread;
HANDLE threadH;
@@ -148,7 +122,8 @@ struct pthread_attr_t_ {
#define PTW32_OBJECT_INVALID NULL
struct pthread_mutex_t_ {
- ptw32_cs_t cs;
+ HANDLE mutex;
+ CRITICAL_SECTION cs;
int lockCount;
pthread_t ownerThread;
};
@@ -156,7 +131,7 @@ struct pthread_mutex_t_ {
struct pthread_mutexattr_t_ {
int pshared;
- int type;
+ int forcecs;
};
@@ -177,54 +152,36 @@ struct ThreadParms {
void *arg;
};
-#if 0
-struct pthread_cond_t_ {
- long waiters; /* # waiting threads */
- pthread_mutex_t waitersLock; /* Mutex that guards access to
- waiter count */
- sem_t sema; /* Queue up threads waiting for the
- condition to become signaled */
- HANDLE waitersDone; /* An auto reset event used by the
- broadcast/signal thread to wait
- for the waiting thread(s) to wake
- up and get a chance at the
- semaphore */
- int wasBroadcast; /* keeps track if we are signaling
- or broadcasting */
-};
-
-#else
struct pthread_cond_t_ {
- long nWaitersBlocked; /* Number of threads blocked */
- long nWaitersUnblocked; /* Number of threads unblocked */
- long nWaitersToUnblock; /* Number of threads to unblock */
- sem_t semBlockQueue; /* Queue up threads waiting for the */
- /* condition to become signalled */
- sem_t semBlockLock; /* Semaphore that guards access to */
- /* waiters blocked count/block queue */
- /* +-> Mandatory Sync.LEVEL-1 */
- pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to */
- /* waiters (to)unblock(ed) counts */
- /* +-> Optional* Sync.LEVEL-2 */
-}; /* Opt*) for _timedwait and cancellation */
-#endif
+ long nWaitersBlocked; /* Number of threads blocked */
+ long nWaitersUnblocked; /* Number of threads unblocked */
+ long nWaitersToUnblock; /* Number of threads to unblock */
+ sem_t semBlockQueue; /* Queue up threads waiting for the */
+ /* condition to become signalled */
+ sem_t semBlockLock; /* Semaphore that guards access to */
+ /* | waiters blocked count/block queue */
+ /* +-> Mandatory Sync.LEVEL-1 */
+ pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to */
+ /* | waiters (to)unblock(ed) counts */
+ /* +-> Optional* Sync.LEVEL-2 */
+}; /* Opt*) for _timedwait and cancellation*/
+
struct pthread_condattr_t_ {
int pshared;
};
-#define RW_MAGIC 0x19283746
+#define PTW32_RWLOCK_MAGIC 0xfacade2
struct pthread_rwlock_t_ {
- pthread_mutex_t rw_lock; /* 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 */
+ pthread_mutex_t mtxExclusiveAccess;
+ pthread_mutex_t mtxSharedAccessCompleted;
+ pthread_cond_t cndSharedAccessCompleted;
+ int nSharedAccessCount;
+ int nExclusiveAccessCount;
+ int nCompletedSharedAccessCount;
+ int nMagic;
};
struct pthread_rwlockattr_t_ {
@@ -307,17 +264,17 @@ struct ThreadKeyAssoc {
* Severity Values:
*/
#define SE_SUCCESS 0x00
-#define SE_INFORMATION 0x01
+#define SE_INFORMATION 0x01
#define SE_WARNING 0x02
#define SE_ERROR 0x03
#define MAKE_SOFTWARE_EXCEPTION( _severity, _facility, _exception ) \
-( (DWORD) ( ( (_severity) << 30 ) | /* Severity code */ \
- ( 1 << 29 ) | /* MS=0, User=1 */ \
- ( 0 << 28 ) | /* Reserved */ \
- ( (_facility) << 16 ) | /* Facility Code */ \
- ( (_exception) << 0 ) /* Exception Code */ \
- ) )
+( (DWORD) ( ( (_severity) << 30 ) | /* Severity code */ \
+ ( 1 << 29 ) | /* MS=0, User=1 */ \
+ ( 0 << 28 ) | /* Reserved */ \
+ ( (_facility) << 16 ) | /* Facility Code */ \
+ ( (_exception) << 0 ) /* Exception Code */ \
+ ) )
/*
* We choose one specific Facility/Error code combination to
@@ -325,13 +282,13 @@ struct ThreadKeyAssoc {
* We store our actual component and error code within
* the optional information array.
*/
-#define EXCEPTION_PTW32_SERVICES \
+#define EXCEPTION_PTW32_SERVICES \
MAKE_SOFTWARE_EXCEPTION( SE_ERROR, \
- PTW32_SERVICES_FACILITY, \
- PTW32_SERVICES_ERROR )
+ PTW32_SERVICES_FACILITY, \
+ PTW32_SERVICES_ERROR )
-#define PTW32_SERVICES_FACILITY 0xBAD
-#define PTW32_SERVICES_ERROR 0xDEED
+#define PTW32_SERVICES_FACILITY 0xBAD
+#define PTW32_SERVICES_ERROR 0xDEED
#endif /* _MSC_VER */
@@ -394,13 +351,13 @@ ptw32_threadStart (ThreadParms * threadParms);
void ptw32_callUserDestroyRoutines (pthread_t thread);
int ptw32_tkAssocCreate (ThreadKeyAssoc ** assocP,
- pthread_t thread,
- pthread_key_t key);
+ pthread_t thread,
+ pthread_key_t key);
void ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc);
int ptw32_sem_timedwait (sem_t * sem,
- const struct timespec * abstime);
+ const struct timespec * abstime);
#ifdef NEED_SEM
void ptw32_decrease_semaphore(sem_t * sem);
@@ -428,17 +385,17 @@ BOOL ptw32_increase_semaphore(sem_t * sem,
*/
#define _beginthreadex(security, \
- stack_size, \
- start_proc, \
- arg, \
- flags, \
- pid) \
+ stack_size, \
+ start_proc, \
+ arg, \
+ flags, \
+ pid) \
CreateThread(security, \
- stack_size, \
- (LPTHREAD_START_ROUTINE) start_proc, \
- arg, \
- flags, \
- pid)
+ stack_size, \
+ (LPTHREAD_START_ROUTINE) start_proc, \
+ arg, \
+ flags, \
+ pid)
#define _endthreadex ExitThread
diff --git a/rwlock.c b/rwlock.c
index cd886a4..4e15636 100644
--- a/rwlock.c
+++ b/rwlock.c
@@ -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
-ptw32_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(ptw32_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
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 != 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(ptw32_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;
}
diff --git a/tests/rwlock6.c b/tests/rwlock6.c
index 7daccd7..8a75b83 100644
--- a/tests/rwlock6.c
+++ b/tests/rwlock6.c
@@ -1,65 +1,65 @@
-/*
- * rwlock6.c
- *
- * Check that writer locks have priority.
- *
- * Depends on API functions:
- * pthread_rwlock_rdlock()
- * pthread_rwlock_wrlock()
- * pthread_rwlock_unlock()
- */
+/*
+ * rwlock6.c
+ *
+ * Check that writer locks have priority.
+ *
+ * Depends on API functions:
+ * pthread_rwlock_rdlock()
+ * pthread_rwlock_wrlock()
+ * pthread_rwlock_unlock()
+ */
-#include "test.h"
-
-static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER;
+#include "test.h"
+
+static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER;
-static int bankAccount;
+static int bankAccount;
-void * wrfunc(void * arg)
-{
- assert(pthread_rwlock_wrlock(&rwlock1) == 0);
- Sleep(1000);
- bankAccount += 10;
- assert(pthread_rwlock_unlock(&rwlock1) == 0);
+void * wrfunc(void * arg)
+{
+ assert(pthread_rwlock_wrlock(&rwlock1) == 0);
+ Sleep(1000);
+ bankAccount += 10;
+ assert(pthread_rwlock_unlock(&rwlock1) == 0);
- return((void *) bankAccount);
-}
-
-void * rdfunc(void * arg)
-{
- int ba = 0;
+ return((void *) bankAccount);
+}
+
+void * rdfunc(void * arg)
+{
+ int ba = 0;
- assert(pthread_rwlock_rdlock(&rwlock1) == 0);
- ba = bankAccount;
- assert(pthread_rwlock_unlock(&rwlock1) == 0);
+ assert(pthread_rwlock_rdlock(&rwlock1) == 0);
+ ba = bankAccount;
+ assert(pthread_rwlock_unlock(&rwlock1) == 0);
- ba += 10;
- return((void *) ba);
-}
-
-int
-main()
-{
- pthread_t wrt1;
- pthread_t wrt2;
- pthread_t rdt;
- int wr1Result = 0;
- int wr2Result = 0;
- int rdResult = 0;
+ ba += 10;
+ return((void *) ba);
+}
+
+int
+main()
+{
+ pthread_t wrt1;
+ pthread_t wrt2;
+ pthread_t rdt;
+ int wr1Result = 0;
+ int wr2Result = 0;
+ int rdResult = 0;
- assert(pthread_create(&wrt1, NULL, wrfunc, NULL) == 0);
- Sleep(200);
- assert(pthread_create(&rdt, NULL, rdfunc, NULL) == 0);
- Sleep(200);
- assert(pthread_create(&wrt2, NULL, wrfunc, NULL) == 0);
+ assert(pthread_create(&wrt1, NULL, wrfunc, NULL) == 0);
+ Sleep(200);
+ assert(pthread_create(&rdt, NULL, rdfunc, NULL) == 0);
+ Sleep(200);
+ assert(pthread_create(&wrt2, NULL, wrfunc, NULL) == 0);
- assert(pthread_join(wrt1, (void **) &wr1Result) == 0);
- assert(pthread_join(wrt2, (void **) &wr2Result) == 0);
- assert(pthread_join(rdt, (void **) &rdResult) == 0);
+ assert(pthread_join(wrt1, (void **) &wr1Result) == 0);
+ assert(pthread_join(wrt2, (void **) &wr2Result) == 0);
+ assert(pthread_join(rdt, (void **) &rdResult) == 0);
- assert(wr1Result == 10);
- assert(wr2Result == 20);
- assert(rdResult == 30);
+ assert(wr1Result == 10);
+ assert(wr2Result == 20);
+ assert(rdResult == 20);
- return 0;
-}
+ return 0;
+}