summaryrefslogtreecommitdiff
path: root/mysys/thr_rwlock.c
diff options
context:
space:
mode:
authorDmitry Lenev <dlenev@mysql.com>2010-02-28 07:35:09 +0300
committerDmitry Lenev <dlenev@mysql.com>2010-02-28 07:35:09 +0300
commit6b5c4a9ef61eff4768c6fdf04857ae8a1b219a6c (patch)
tree72819bde0c313c8ef3b67a20ff9ac4fe00833093 /mysys/thr_rwlock.c
parent093106f552ae890a0c6b4b183899a5d0affa1629 (diff)
downloadmariadb-git-6b5c4a9ef61eff4768c6fdf04857ae8a1b219a6c.tar.gz
Fix for bug #51105 "MDL deadlock in rqg_mdl_stability test
on Windows". On platforms where read-write lock implementation does not prefer readers by default (Windows, Solaris) server might have deadlocked while detecting MDL deadlock. MDL deadlock detector relies on the fact that read-write locks which are used in its implementation prefer readers (see new comment for MDL_lock::m_rwlock for details). So far MDL code assumed that default implementation of read/write locks for the system has this property. Indeed, this turned out ot be wrong, for example, for Windows or Solaris. Thus MDL deadlock detector might have deadlocked on these systems. This fix simply adds portable implementation of read/write lock which prefer readers and changes MDL code to use this new type of synchronization primitive. No test case is added as existing rqg_mdl_stability test can serve as one. config.h.cmake: Check for presence of pthread_rwlockattr_setkind_np to be able to determine if system natively supports read-write locks for which we can specify if readers or writers should be preferred. configure.cmake: Check for presence of pthread_rwlockattr_setkind_np to be able to determine if system natively supports read-write locks for which we can specify if readers or writers should be preferred. configure.in: Check for presence of pthread_rwlockattr_setkind_np to be able to determine if system natively supports read-write locks for which we can specify if readers or writers should be preferred. include/my_pthread.h: Added support for portable read-write locks which prefer readers. To do so extended existing my_rw_lock_t implementation to support selection of whom to prefer depending on a flag. mysys/thr_rwlock.c: Extended existing my_rw_lock_t implementation to support selection of whom to prefer depending on a flag. Added rw_pr_init() function implementing initialization of read-write locks preferring readers. sql/mdl.cc: Use portable read-write locks which prefer readers instead of relying on that system implementation of read-write locks has this property (this was true for Linux/NPTL but was false, for example, for Windows and Solaris). Added comment explaining why preferring readers is important for MDL deadlock detector (thanks to Serg for example!). sql/mdl.h: Use portable read-write locks which prefer readers instead of relying on that system implementation of read-write locks has this property (this was true for Linux/NPTL but was false, for example, for Windows and Solaris).
Diffstat (limited to 'mysys/thr_rwlock.c')
-rw-r--r--mysys/thr_rwlock.c56
1 files changed, 44 insertions, 12 deletions
diff --git a/mysys/thr_rwlock.c b/mysys/thr_rwlock.c
index 0aa4d3fc3c4..2ac4a00695e 100644
--- a/mysys/thr_rwlock.c
+++ b/mysys/thr_rwlock.c
@@ -16,7 +16,8 @@
/* Synchronization - readers / writer thread locks */
#include "mysys_priv.h"
-#if defined(THREAD) && !defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && !defined(HAVE_RWLOCK_INIT)
+#if defined(THREAD)
+#if defined(NEED_MY_RW_LOCK)
#include <errno.h>
/*
@@ -58,7 +59,7 @@
* Mountain View, California 94043
*/
-int my_rwlock_init(rw_lock_t *rwp, void *arg __attribute__((unused)))
+int my_rw_init(my_rw_lock_t *rwp, my_bool *prefer_readers_attr)
{
pthread_condattr_t cond_attr;
@@ -70,12 +71,14 @@ int my_rwlock_init(rw_lock_t *rwp, void *arg __attribute__((unused)))
rwp->state = 0;
rwp->waiters = 0;
+ /* If attribute argument is NULL use default value - prefer writers. */
+ rwp->prefer_readers= prefer_readers_attr ? *prefer_readers_attr : FALSE;
return(0);
}
-int my_rwlock_destroy(rw_lock_t *rwp)
+int my_rw_destroy(my_rw_lock_t *rwp)
{
pthread_mutex_destroy( &rwp->lock );
pthread_cond_destroy( &rwp->readers );
@@ -84,12 +87,13 @@ int my_rwlock_destroy(rw_lock_t *rwp)
}
-int my_rw_rdlock(rw_lock_t *rwp)
+int my_rw_rdlock(my_rw_lock_t *rwp)
{
pthread_mutex_lock(&rwp->lock);
/* active or queued writers */
- while (( rwp->state < 0 ) || rwp->waiters)
+ while (( rwp->state < 0 ) ||
+ (rwp->waiters && ! rwp->prefer_readers))
pthread_cond_wait( &rwp->readers, &rwp->lock);
rwp->state++;
@@ -97,11 +101,12 @@ int my_rw_rdlock(rw_lock_t *rwp)
return(0);
}
-int my_rw_tryrdlock(rw_lock_t *rwp)
+int my_rw_tryrdlock(my_rw_lock_t *rwp)
{
int res;
pthread_mutex_lock(&rwp->lock);
- if ((rwp->state < 0 ) || rwp->waiters)
+ if ((rwp->state < 0 ) ||
+ (rwp->waiters && ! rwp->prefer_readers))
res= EBUSY; /* Can't get lock */
else
{
@@ -113,7 +118,7 @@ int my_rw_tryrdlock(rw_lock_t *rwp)
}
-int my_rw_wrlock(rw_lock_t *rwp)
+int my_rw_wrlock(my_rw_lock_t *rwp)
{
pthread_mutex_lock(&rwp->lock);
rwp->waiters++; /* another writer queued */
@@ -127,7 +132,7 @@ int my_rw_wrlock(rw_lock_t *rwp)
}
-int my_rw_trywrlock(rw_lock_t *rwp)
+int my_rw_trywrlock(my_rw_lock_t *rwp)
{
int res;
pthread_mutex_lock(&rwp->lock);
@@ -143,7 +148,7 @@ int my_rw_trywrlock(rw_lock_t *rwp)
}
-int my_rw_unlock(rw_lock_t *rwp)
+int my_rw_unlock(my_rw_lock_t *rwp)
{
DBUG_PRINT("rw_unlock",
("state: %d waiters: %d", rwp->state, rwp->waiters));
@@ -160,7 +165,8 @@ int my_rw_unlock(rw_lock_t *rwp)
}
else
{
- if ( --rwp->state == 0 ) /* no more readers */
+ if ( --rwp->state == 0 && /* no more readers */
+ rwp->waiters)
pthread_cond_signal( &rwp->writers );
}
@@ -168,4 +174,30 @@ int my_rw_unlock(rw_lock_t *rwp)
return(0);
}
-#endif
+
+int rw_pr_init(struct st_my_rw_lock_t *rwlock)
+{
+ my_bool prefer_readers_attr= TRUE;
+ return my_rw_init(rwlock, &prefer_readers_attr);
+}
+
+#else
+
+/*
+ We are on system which has native read/write locks which support
+ preferring of readers.
+*/
+
+int rw_pr_init(rw_pr_lock_t *rwlock)
+{
+ pthread_rwlockattr_t rwlock_attr;
+
+ 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);
+ return 0;
+}
+
+#endif /* defined(NEED_MY_RW_LOCK) */
+#endif /* defined(THREAD) */