summaryrefslogtreecommitdiff
path: root/mysys/thr_rwlock.c
diff options
context:
space:
mode:
Diffstat (limited to 'mysys/thr_rwlock.c')
-rw-r--r--mysys/thr_rwlock.c137
1 files changed, 115 insertions, 22 deletions
diff --git a/mysys/thr_rwlock.c b/mysys/thr_rwlock.c
index ecd12849822..218cfb251c8 100644
--- a/mysys/thr_rwlock.c
+++ b/mysys/thr_rwlock.c
@@ -59,7 +59,7 @@
* Mountain View, California 94043
*/
-int my_rw_init(my_rw_lock_t *rwp, my_bool *prefer_readers_attr)
+int my_rw_init(my_rw_lock_t *rwp)
{
pthread_condattr_t cond_attr;
@@ -74,8 +74,6 @@ int my_rw_init(my_rw_lock_t *rwp, my_bool *prefer_readers_attr)
#ifdef SAFE_MUTEX
rwp->write_thread = 0;
#endif
- /* If attribute argument is NULL use default value - prefer writers. */
- rwp->prefer_readers= prefer_readers_attr ? *prefer_readers_attr : FALSE;
return(0);
}
@@ -96,8 +94,7 @@ int my_rw_rdlock(my_rw_lock_t *rwp)
pthread_mutex_lock(&rwp->lock);
/* active or queued writers */
- while (( rwp->state < 0 ) ||
- (rwp->waiters && ! rwp->prefer_readers))
+ while (( rwp->state < 0 ) || rwp->waiters)
pthread_cond_wait( &rwp->readers, &rwp->lock);
rwp->state++;
@@ -109,8 +106,7 @@ int my_rw_tryrdlock(my_rw_lock_t *rwp)
{
int res;
pthread_mutex_lock(&rwp->lock);
- if ((rwp->state < 0 ) ||
- (rwp->waiters && ! rwp->prefer_readers))
+ if ((rwp->state < 0 ) || rwp->waiters)
res= EBUSY; /* Can't get lock */
else
{
@@ -192,30 +188,127 @@ int my_rw_unlock(my_rw_lock_t *rwp)
return(0);
}
+#endif /* defined(NEED_MY_RW_LOCK) */
+
-int rw_pr_init(struct st_my_rw_lock_t *rwlock)
+int rw_pr_init(rw_pr_lock_t *rwlock)
{
- my_bool prefer_readers_attr= TRUE;
- return my_rw_init(rwlock, &prefer_readers_attr);
+ pthread_mutex_init(&rwlock->lock, NULL);
+ pthread_cond_init(&rwlock->no_active_readers, NULL);
+ rwlock->active_readers= 0;
+ rwlock->writers_waiting_readers= 0;
+ rwlock->active_writer= FALSE;
+#ifdef SAFE_MUTEX
+ rwlock->writer_thread= 0;
+#endif
+ return 0;
}
-#else
-/*
- We are on system which has native read/write locks which support
- preferring of readers.
-*/
+int rw_pr_destroy(rw_pr_lock_t *rwlock)
+{
+ pthread_cond_destroy(&rwlock->no_active_readers);
+ pthread_mutex_destroy(&rwlock->lock);
+ return 0;
+}
-int rw_pr_init(rw_pr_lock_t *rwlock)
+
+int rw_pr_rdlock(rw_pr_lock_t *rwlock)
+{
+ pthread_mutex_lock(&rwlock->lock);
+ /*
+ The fact that we were able to acquire 'lock' mutex means
+ that there are no active writers and we can acquire rd-lock.
+ Increment active readers counter to prevent requests for
+ wr-lock from succeeding and unlock mutex.
+ */
+ rwlock->active_readers++;
+ pthread_mutex_unlock(&rwlock->lock);
+ return 0;
+}
+
+
+int rw_pr_wrlock(rw_pr_lock_t *rwlock)
{
- pthread_rwlockattr_t rwlock_attr;
+ pthread_mutex_lock(&rwlock->lock);
+
+ if (rwlock->active_readers != 0)
+ {
+ /* There are active readers. We have to wait until they are gone. */
+ rwlock->writers_waiting_readers++;
- pthread_rwlockattr_init(&rwlock_attr);
- pthread_rwlockattr_setkind_np(&rwlock_attr, PTHREAD_RWLOCK_PREFER_READER_NP);
- pthread_rwlock_init(rwlock, NULL);
- pthread_rwlockattr_destroy(&rwlock_attr);
+ while (rwlock->active_readers != 0)
+ pthread_cond_wait(&rwlock->no_active_readers, &rwlock->lock);
+
+ rwlock->writers_waiting_readers--;
+ }
+
+ /*
+ We own 'lock' mutex so there is no active writers.
+ Also there are no active readers.
+ This means that we can grant wr-lock.
+ Not releasing 'lock' mutex until unlock will block
+ both requests for rd and wr-locks.
+ Set 'active_writer' flag to simplify unlock.
+
+ Thanks to the fact wr-lock/unlock in the absence of
+ contention from readers is essentially mutex lock/unlock
+ with a few simple checks make this rwlock implementation
+ wr-lock optimized.
+ */
+ rwlock->active_writer= TRUE;
+#ifdef SAFE_MUTEX
+ rwlock->writer_thread= pthread_self();
+#endif
return 0;
}
-#endif /* defined(NEED_MY_RW_LOCK) */
+
+int rw_pr_unlock(rw_pr_lock_t *rwlock)
+{
+ if (rwlock->active_writer)
+ {
+ /* We are unlocking wr-lock. */
+#ifdef SAFE_MUTEX
+ rwlock->writer_thread= 0;
+#endif
+ rwlock->active_writer= FALSE;
+ if (rwlock->writers_waiting_readers)
+ {
+ /*
+ Avoid expensive cond signal in case when there is no contention
+ or it is wr-only.
+
+ Note that from view point of performance it would be better to
+ signal on the condition variable after unlocking mutex (as it
+ reduces number of contex switches).
+
+ Unfortunately this would mean that such rwlock can't be safely
+ used by MDL subsystem, which relies on the fact that it is OK
+ to destroy rwlock once it is in unlocked state.
+ */
+ pthread_cond_signal(&rwlock->no_active_readers);
+ }
+ pthread_mutex_unlock(&rwlock->lock);
+ }
+ else
+ {
+ /* We are unlocking rd-lock. */
+ pthread_mutex_lock(&rwlock->lock);
+ rwlock->active_readers--;
+ if (rwlock->active_readers == 0 &&
+ rwlock->writers_waiting_readers)
+ {
+ /*
+ If we are last reader and there are waiting
+ writers wake them up.
+ */
+ pthread_cond_signal(&rwlock->no_active_readers);
+ }
+ pthread_mutex_unlock(&rwlock->lock);
+ }
+ return 0;
+}
+
+
#endif /* defined(THREAD) */