diff options
Diffstat (limited to 'mysys/thr_rwlock.c')
-rw-r--r-- | mysys/thr_rwlock.c | 137 |
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) */ |