summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/my_pthread.h106
-rw-r--r--include/mysql/psi/mysql_thread.h88
2 files changed, 69 insertions, 125 deletions
diff --git a/include/my_pthread.h b/include/my_pthread.h
index 5cf181596ad..27ab5ba23fe 100644
--- a/include/my_pthread.h
+++ b/include/my_pthread.h
@@ -594,7 +594,7 @@ int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp);
/* Use our own version of read/write locks */
#define NEED_MY_RW_LOCK 1
#define rw_lock_t my_rw_lock_t
-#define my_rwlock_init(A,B) my_rw_init((A), 0)
+#define my_rwlock_init(A,B) my_rw_init((A))
#define rw_rdlock(A) my_rw_rdlock((A))
#define rw_wrlock(A) my_rw_wrlock((A))
#define rw_tryrdlock(A) my_rw_tryrdlock((A))
@@ -606,49 +606,82 @@ int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp);
#endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */
-/*
- Portable read-write locks which prefer readers.
-
- Required by some algorithms in order to provide correctness.
+/**
+ Portable implementation of special type of read-write locks.
+
+ These locks have two properties which are unusual for rwlocks:
+ 1) They "prefer readers" in the sense that they do not allow
+ situations in which rwlock is rd-locked and there is a
+ pending rd-lock which is blocked (e.g. due to pending
+ request for wr-lock).
+ This is a stronger guarantee than one which is provided for
+ PTHREAD_RWLOCK_PREFER_READER_NP rwlocks in Linux.
+ MDL subsystem deadlock detector relies on this property for
+ its correctness.
+ 2) They are optimized for uncontended wr-lock/unlock case.
+ This is scenario in which they are most oftenly used
+ within MDL subsystem. Optimizing for it gives significant
+ performance improvements in some of tests involving many
+ connections.
+
+ Another important requirement imposed on this type of rwlock
+ by the MDL subsystem is that it should be OK to destroy rwlock
+ object which is in unlocked state even though some threads might
+ have not yet fully left unlock operation for it (of course there
+ is an external guarantee that no thread will try to lock rwlock
+ which is destroyed).
+ Putting it another way the unlock operation should not access
+ rwlock data after changing its state to unlocked.
+
+ TODO/FIXME: We should consider alleviating this requirement as
+ it blocks us from doing certain performance optimizations.
*/
-#if defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP)
-/*
- On systems which have a way to specify that readers should
- be preferred through attribute mechanism (e.g. Linux) we use
- system implementation of read/write locks.
-*/
-#define rw_pr_lock_t pthread_rwlock_t
+typedef struct st_rw_pr_lock_t {
+ /**
+ Lock which protects the structure.
+ Also held for the duration of wr-lock.
+ */
+ pthread_mutex_t lock;
+ /**
+ Condition variable which is used to wake-up
+ writers waiting for readers to go away.
+ */
+ pthread_cond_t no_active_readers;
+ /** Number of active readers. */
+ uint active_readers;
+ /** Number of writers waiting for readers to go away. */
+ uint writers_waiting_readers;
+ /** Indicates whether there is an active writer. */
+ my_bool active_writer;
+#ifdef SAFE_MUTEX
+ /** Thread holding wr-lock (for debug purposes only). */
+ pthread_t writer_thread;
+#endif
+} rw_pr_lock_t;
+
extern int rw_pr_init(rw_pr_lock_t *);
-#define rw_pr_rdlock(A) pthread_rwlock_rdlock(A)
-#define rw_pr_wrlock(A) pthread_rwlock_wrlock(A)
-#define rw_pr_tryrdlock(A) pthread_rwlock_tryrdlock(A)
-#define rw_pr_trywrlock(A) pthread_rwlock_trywrlock(A)
-#define rw_pr_unlock(A) pthread_rwlock_unlock(A)
-#define rw_pr_destroy(A) pthread_rwlock_destroy(A)
+extern int rw_pr_rdlock(rw_pr_lock_t *);
+extern int rw_pr_wrlock(rw_pr_lock_t *);
+extern int rw_pr_unlock(rw_pr_lock_t *);
+extern int rw_pr_destroy(rw_pr_lock_t *);
+#ifdef SAFE_MUTEX
+#define rw_pr_lock_assert_write_owner(A) \
+ DBUG_ASSERT((A)->active_writer && pthread_equal(pthread_self(), \
+ (A)->writer_thread))
+#define rw_pr_lock_assert_not_write_owner(A) \
+ DBUG_ASSERT(! (A)->active_writer || ! pthread_equal(pthread_self(), \
+ (A)->writer_thread))
+#else
#define rw_pr_lock_assert_write_owner(A)
#define rw_pr_lock_assert_not_write_owner(A)
-#else
-/* Otherwise we have to use our own implementation of read/write locks. */
-#define NEED_MY_RW_LOCK 1
-struct st_my_rw_lock_t;
-#define rw_pr_lock_t my_rw_lock_t
-extern int rw_pr_init(struct st_my_rw_lock_t *);
-#define rw_pr_rdlock(A) my_rw_rdlock((A))
-#define rw_pr_wrlock(A) my_rw_wrlock((A))
-#define rw_pr_tryrdlock(A) my_rw_tryrdlock((A))
-#define rw_pr_trywrlock(A) my_rw_trywrlock((A))
-#define rw_pr_unlock(A) my_rw_unlock((A))
-#define rw_pr_destroy(A) my_rw_destroy((A))
-#define rw_pr_lock_assert_write_owner(A) my_rw_lock_assert_write_owner((A))
-#define rw_pr_lock_assert_not_write_owner(A) my_rw_lock_assert_not_write_owner((A))
-#endif /* defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) */
+#endif /* SAFE_MUTEX */
#ifdef NEED_MY_RW_LOCK
/*
- On systems which don't support native read/write locks, or don't support
- read/write locks which prefer readers we have to use own implementation.
+ On systems which don't support native read/write locks we have
+ to use own implementation.
*/
typedef struct st_my_rw_lock_t {
pthread_mutex_t lock; /* lock for structure */
@@ -656,13 +689,12 @@ typedef struct st_my_rw_lock_t {
pthread_cond_t writers; /* waiting writers */
int state; /* -1:writer,0:free,>0:readers */
int waiters; /* number of waiting writers */
- my_bool prefer_readers;
#ifdef SAFE_MUTEX
pthread_t write_thread;
#endif
} my_rw_lock_t;
-extern int my_rw_init(my_rw_lock_t *, my_bool *);
+extern int my_rw_init(my_rw_lock_t *);
extern int my_rw_destroy(my_rw_lock_t *);
extern int my_rw_rdlock(my_rw_lock_t *);
extern int my_rw_wrlock(my_rw_lock_t *);
diff --git a/include/mysql/psi/mysql_thread.h b/include/mysql/psi/mysql_thread.h
index 60b4f5d6ef4..5b8ea3dc5dc 100644
--- a/include/mysql/psi/mysql_thread.h
+++ b/include/mysql/psi/mysql_thread.h
@@ -141,9 +141,7 @@ typedef struct st_mysql_rwlock mysql_rwlock_t;
@c mysql_prlock_t is a drop-in replacement for @c rw_pr_lock_t.
@sa mysql_prlock_init
@sa mysql_prlock_rdlock
- @sa mysql_prlock_tryrdlock
@sa mysql_prlock_wrlock
- @sa mysql_prlock_trywrlock
@sa mysql_prlock_unlock
@sa mysql_prlock_destroy
*/
@@ -421,20 +419,6 @@ typedef struct st_mysql_cond mysql_cond_t;
#endif
/**
- @def mysql_prlock_tryrdlock(RW)
- Instrumented rw_pr_tryrdlock.
- @c mysql_prlock_tryrdlock is a drop-in replacement
- for @c rw_pr_tryrdlock.
-*/
-#ifdef HAVE_PSI_INTERFACE
- #define mysql_prlock_tryrdlock(RW) \
- inline_mysql_prlock_tryrdlock(RW, __FILE__, __LINE__)
-#else
- #define mysql_prlock_tryrdlock(RW) \
- inline_mysql_prlock_tryrdlock(RW)
-#endif
-
-/**
@def mysql_rwlock_trywrlock(RW)
Instrumented rwlock_trywrlock.
@c mysql_rwlock_trywrlock is a drop-in replacement
@@ -449,20 +433,6 @@ typedef struct st_mysql_cond mysql_cond_t;
#endif
/**
- @def mysql_prlock_trywrlock(RW)
- Instrumented rw_pr_trywrlock.
- @c mysql_prlock_trywrlock is a drop-in replacement
- for @c rw_pr_trywrlock.
-*/
-#ifdef HAVE_PSI_INTERFACE
- #define mysql_prlock_trywrlock(RW) \
- inline_mysql_prlock_trywrlock(RW, __FILE__, __LINE__)
-#else
- #define mysql_prlock_trywrlock(RW) \
- inline_mysql_prlock_trywrlock(RW)
-#endif
-
-/**
@def mysql_rwlock_unlock(RW)
Instrumented rwlock_unlock.
@c mysql_rwlock_unlock is a drop-in replacement
@@ -905,35 +875,6 @@ static inline int inline_mysql_rwlock_tryrdlock(
return result;
}
-#ifndef DISABLE_MYSQL_PRLOCK_H
-static inline int inline_mysql_prlock_tryrdlock(
- mysql_prlock_t *that
-#ifdef HAVE_PSI_INTERFACE
- , const char *src_file, uint src_line
-#endif
- )
-{
- int result;
-#ifdef HAVE_PSI_INTERFACE
- struct PSI_rwlock_locker *locker= NULL;
- PSI_rwlock_locker_state state;
- if (likely(PSI_server && that->m_psi))
- {
- locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi,
- PSI_RWLOCK_TRYREADLOCK);
- if (likely(locker != NULL))
- PSI_server->start_rwlock_rdwait(locker, src_file, src_line);
- }
-#endif
- result= rw_pr_tryrdlock(&that->m_prlock);
-#ifdef HAVE_PSI_INTERFACE
- if (likely(locker != NULL))
- PSI_server->end_rwlock_rdwait(locker, result);
-#endif
- return result;
-}
-#endif
-
static inline int inline_mysql_rwlock_trywrlock(
mysql_rwlock_t *that
#ifdef HAVE_PSI_INTERFACE
@@ -961,35 +902,6 @@ static inline int inline_mysql_rwlock_trywrlock(
return result;
}
-#ifndef DISABLE_MYSQL_PRLOCK_H
-static inline int inline_mysql_prlock_trywrlock(
- mysql_prlock_t *that
-#ifdef HAVE_PSI_INTERFACE
- , const char *src_file, uint src_line
-#endif
- )
-{
- int result;
-#ifdef HAVE_PSI_INTERFACE
- struct PSI_rwlock_locker *locker= NULL;
- PSI_rwlock_locker_state state;
- if (likely(PSI_server && that->m_psi))
- {
- locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi,
- PSI_RWLOCK_TRYWRITELOCK);
- if (likely(locker != NULL))
- PSI_server->start_rwlock_wrwait(locker, src_file, src_line);
- }
-#endif
- result= rw_pr_trywrlock(&that->m_prlock);
-#ifdef HAVE_PSI_INTERFACE
- if (likely(locker != NULL))
- PSI_server->end_rwlock_wrwait(locker, result);
-#endif
- return result;
-}
-#endif
-
static inline int inline_mysql_rwlock_unlock(
mysql_rwlock_t *that)
{