Commit 70cdb841 authored by Marko Mäkelä's avatar Marko Mäkelä

amend 88722a7c

This will be pushed separately as MDEV-24142 once it works.

rw_lock_sx_unlock_func(): Wake up an X-latch waiter if needed.

sync_array_wait_event(): Wake up even if a pending SX-latch
request exists.

rw_lock_x_unlock_func(): Clean up.

FIXME: rw_lock_x_lock_wait_func() can still get stuck in
sync_array_wait_event() with lock_word==-X_LOCK_HALF_DECR.
parent 4b334320
...@@ -390,36 +390,34 @@ rw_lock_x_unlock_func( ...@@ -390,36 +390,34 @@ rw_lock_x_unlock_func(
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
rw_lock_t* lock) /*!< in/out: rw-lock */ rw_lock_t* lock) /*!< in/out: rw-lock */
{ {
int32_t lock_word = lock->lock_word; ut_d(rw_lock_remove_debug_info(lock, pass, RW_LOCK_X));
if (lock_word == 0) { switch (int32_t lock_word= lock->lock_word) {
/* Last caller in a possible recursive chain. */ case 0:
lock->writer_thread = 0; /* Last caller in a possible recursive chain. */
} lock->writer_thread= 0;
/* fall through */
ut_d(rw_lock_remove_debug_info(lock, pass, RW_LOCK_X)); case -X_LOCK_HALF_DECR:
/* Last X-lock owned by this thread, it may still hold SX-locks.
if (lock_word == 0 || lock_word == -X_LOCK_HALF_DECR) { ACQ_REL due to...
/* Last X-lock owned by this thread, it may still hold SX-locks. RELEASE: we release rw-lock
ACQ_REL due to... ACQUIRE: we want waiters to be loaded after lock_word is stored */
RELEASE: we release rw-lock lock->lock_word.fetch_add(X_LOCK_DECR, std::memory_order_acq_rel);
ACQUIRE: we want waiters to be loaded after lock_word is stored */ if (lock->waiters)
lock->lock_word.fetch_add(X_LOCK_DECR, lock->wakeup_waiters();
std::memory_order_acq_rel); break;
if (lock->waiters) { case -X_LOCK_DECR:
lock->wakeup_waiters(); case -X_LOCK_DECR - X_LOCK_HALF_DECR:
} /* There are 2 x-locks */
} else if (lock_word == -X_LOCK_DECR lock->lock_word.fetch_add(X_LOCK_DECR);
|| lock_word == -(X_LOCK_DECR + X_LOCK_HALF_DECR)) { break;
/* There are 2 x-locks */ default:
lock->lock_word.fetch_add(X_LOCK_DECR); /* There are more than 2 x-locks. */
} else { ut_ad(lock_word < -X_LOCK_DECR);
/* There are more than 2 x-locks. */ lock->lock_word.fetch_add(1);
ut_ad(lock_word < -X_LOCK_DECR); }
lock->lock_word.fetch_add(1);
} ut_ad(rw_lock_validate(lock));
ut_ad(rw_lock_validate(lock));
} }
/******************************************************************//** /******************************************************************//**
...@@ -436,12 +434,9 @@ rw_lock_sx_unlock_func( ...@@ -436,12 +434,9 @@ rw_lock_sx_unlock_func(
{ {
ut_ad(rw_lock_get_sx_lock_count(lock)); ut_ad(rw_lock_get_sx_lock_count(lock));
ut_ad(lock->sx_recursive > 0); ut_ad(lock->sx_recursive > 0);
--lock->sx_recursive;
ut_d(rw_lock_remove_debug_info(lock, pass, RW_LOCK_SX)); ut_d(rw_lock_remove_debug_info(lock, pass, RW_LOCK_SX));
if (lock->sx_recursive == 0) { if (--lock->sx_recursive == 0) {
int32_t lock_word = lock->lock_word; int32_t lock_word = lock->lock_word;
/* Last caller in a possible recursive chain. */ /* Last caller in a possible recursive chain. */
if (lock_word > 0) { if (lock_word > 0) {
...@@ -465,7 +460,11 @@ rw_lock_sx_unlock_func( ...@@ -465,7 +460,11 @@ rw_lock_sx_unlock_func(
/* still has x-lock */ /* still has x-lock */
ut_ad(lock_word == -X_LOCK_HALF_DECR || ut_ad(lock_word == -X_LOCK_HALF_DECR ||
lock_word <= -(X_LOCK_DECR + X_LOCK_HALF_DECR)); lock_word <= -(X_LOCK_DECR + X_LOCK_HALF_DECR));
lock->lock_word.fetch_add(X_LOCK_HALF_DECR); switch (lock->lock_word.fetch_add(X_LOCK_HALF_DECR)) {
case -X_LOCK_HALF_DECR * 2:
case -X_LOCK_HALF_DECR:
lock->wakeup_wait_ex();
}
} }
} }
......
...@@ -414,9 +414,16 @@ sync_array_wait_event( ...@@ -414,9 +414,16 @@ sync_array_wait_event(
rw_lock_t *lock= cell->latch; rw_lock_t *lock= cell->latch;
const int32_t lock_word = lock->lock_word; const int32_t lock_word = lock->lock_word;
if (cell->request_type == RW_LOCK_X_WAIT) { if (cell->request_type == RW_LOCK_X_WAIT) {
if (lock_word) { switch (lock_word) {
case 0:
case -X_LOCK_DECR:
break;
default:
mysql_mutex_lock(&lock->wait_mutex); mysql_mutex_lock(&lock->wait_mutex);
while (lock->lock_word) { while (const int32_t l = lock->lock_word) {
if (l == -X_LOCK_DECR) {
break;
}
mysql_cond_wait(&lock->wait_ex_cond, mysql_cond_wait(&lock->wait_ex_cond,
&lock->wait_mutex); &lock->wait_mutex);
} }
......
...@@ -129,7 +129,8 @@ wait_ex_cond: A thread may only wait on the wait_ex_cond after it has ...@@ -129,7 +129,8 @@ wait_ex_cond: A thread may only wait on the wait_ex_cond after it has
(2) Verify that lock_word < 0. (2) Verify that lock_word < 0.
These restrictions force the above ordering. These restrictions force the above ordering.
Immediately before sending the wake-up signal, we should: Immediately before sending the wake-up signal, we should:
Verify lock_word == 0 (waiting thread holds x_lock) Verify lock_word == 0 || lock_word == -X_LOCK_HALF_DECR
(waiting thread holds x_lock)
*/ */
rw_lock_stats_t rw_lock_stats; rw_lock_stats_t rw_lock_stats;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment