Skip to content

Commit 260161f

Browse files
committed
MDEV-24167 fixup: Avoid hangs in SRW_LOCK_DUMMY
In commit 1fdc161 we introduced a mutex-and-condition-variable based fallback implementation for platforms that lack a futex system call. That implementation is prone to hangs. Let us use separate condition variables for shared and exclusive requests.
1 parent a13fac9 commit 260161f

File tree

2 files changed

+45
-25
lines changed

2 files changed

+45
-25
lines changed

storage/innobase/include/srw_lock.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class srw_lock_low final : private rw_lock
3535
#endif
3636
#ifdef SRW_LOCK_DUMMY
3737
pthread_mutex_t mutex;
38-
pthread_cond_t cond;
38+
pthread_cond_t cond_shared;
39+
pthread_cond_t cond_exclusive;
3940
#endif
4041
/** @return pointer to the lock word */
4142
rw_lock *word() { return static_cast<rw_lock*>(this); }
@@ -46,11 +47,14 @@ class srw_lock_low final : private rw_lock
4647
void write_lock();
4748
/** Wait for signal
4849
@param l lock word from a failed acquisition */
49-
inline void wait(uint32_t l);
50+
inline void writer_wait(uint32_t l);
51+
/** Wait for signal
52+
@param l lock word from a failed acquisition */
53+
inline void readers_wait(uint32_t l);
5054
/** Send signal to one waiter */
51-
inline void wake_one();
55+
inline void writer_wake();
5256
/** Send signal to all waiters */
53-
inline void wake_all();
57+
inline void readers_wake();
5458
public:
5559
#ifdef SRW_LOCK_DUMMY
5660
void init();

storage/innobase/sync/srw_lock.cc

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,48 +24,60 @@ void srw_lock_low::init()
2424
{
2525
DBUG_ASSERT(!is_locked_or_waiting());
2626
pthread_mutex_init(&mutex, nullptr);
27-
pthread_cond_init(&cond, nullptr);
27+
pthread_cond_init(&cond_shared, nullptr);
28+
pthread_cond_init(&cond_exclusive, nullptr);
2829
}
2930

3031
void srw_lock_low::destroy()
3132
{
3233
DBUG_ASSERT(!is_locked_or_waiting());
3334
pthread_mutex_destroy(&mutex);
34-
pthread_cond_destroy(&cond);
35+
pthread_cond_destroy(&cond_shared);
36+
pthread_cond_destroy(&cond_exclusive);
3537
}
3638

37-
inline void srw_lock_low::wait(uint32_t l)
39+
inline void srw_lock_low::writer_wait(uint32_t l)
3840
{
3941
pthread_mutex_lock(&mutex);
4042
if (value() == l)
41-
pthread_cond_wait(&cond, &mutex);
43+
pthread_cond_wait(&cond_exclusive, &mutex);
4244
pthread_mutex_unlock(&mutex);
4345
}
4446

45-
inline void srw_lock_low::wake_one()
47+
inline void srw_lock_low::readers_wait(uint32_t l)
4648
{
4749
pthread_mutex_lock(&mutex);
48-
pthread_cond_signal(&cond);
50+
if (value() == l)
51+
pthread_cond_wait(&cond_shared, &mutex);
4952
pthread_mutex_unlock(&mutex);
5053
}
5154

52-
inline void srw_lock_low::wake_all()
55+
inline void srw_lock_low::writer_wake()
5356
{
5457
pthread_mutex_lock(&mutex);
55-
pthread_cond_broadcast(&cond);
58+
uint32_t l= value();
59+
if (l & WRITER)
60+
DBUG_ASSERT(!(l & ~WRITER_PENDING));
61+
else
62+
{
63+
pthread_cond_broadcast(&cond_exclusive);
64+
if (!(l & WRITER_PENDING))
65+
pthread_cond_broadcast(&cond_shared);
66+
}
5667
pthread_mutex_unlock(&mutex);
5768
}
69+
# define readers_wake writer_wake
5870
#else
5971
static_assert(4 == sizeof(rw_lock), "ABI");
6072
# ifdef _WIN32
6173
# include <synchapi.h>
6274

63-
inline void srw_lock_low::wait(uint32_t l)
75+
inline void srw_lock_low::writer_wait(uint32_t l)
6476
{
6577
WaitOnAddress(word(), &l, 4, INFINITE);
6678
}
67-
inline void srw_lock_low::wake_one() { WakeByAddressSingle(word()); }
68-
inline void srw_lock_low::wake_all() { WakeByAddressAll(word()); }
79+
inline void srw_lock_low::writer_wake() { WakeByAddressSingle(word()); }
80+
inline void srw_lock_low::readers_wake() { WakeByAddressAll(word()); }
6981
# else
7082
# ifdef __linux__
7183
# include <linux/futex.h>
@@ -81,10 +93,14 @@ inline void srw_lock_low::wake_all() { WakeByAddressAll(word()); }
8193
# error "no futex support"
8294
# endif
8395

84-
inline void srw_lock_low::wait(uint32_t l) { SRW_FUTEX(word(), WAIT, l); }
85-
inline void srw_lock_low::wake_one() { SRW_FUTEX(word(), WAKE, 1); }
86-
inline void srw_lock_low::wake_all() { SRW_FUTEX(word(), WAKE, INT_MAX); }
96+
inline void srw_lock_low::writer_wait(uint32_t l)
97+
{
98+
SRW_FUTEX(word(), WAIT, l);
99+
}
100+
inline void srw_lock_low::writer_wake() { SRW_FUTEX(word(), WAKE, 1); }
101+
inline void srw_lock_low::readers_wake() { SRW_FUTEX(word(), WAKE, INT_MAX); }
87102
# endif
103+
# define readers_wait writer_wait
88104
#endif
89105

90106
/** Wait for a read lock.
@@ -99,15 +115,15 @@ void srw_lock_low::read_lock(uint32_t l)
99115
#ifdef SRW_LOCK_DUMMY
100116
pthread_mutex_lock(&mutex);
101117
{
102-
pthread_cond_signal(&cond);
103-
pthread_cond_wait(&cond, &mutex);
118+
pthread_cond_signal(&cond_exclusive);
119+
pthread_cond_wait(&cond_shared, &mutex);
104120
l= value();
105121
}
106122
while (l == WRITER_WAITING);
107123
pthread_mutex_unlock(&mutex);
108124
continue;
109125
#else
110-
wake_one();
126+
writer_wake();
111127
#endif
112128
}
113129
else
@@ -120,7 +136,7 @@ void srw_lock_low::read_lock(uint32_t l)
120136
goto wake_writer;
121137
}
122138

123-
wait(l);
139+
readers_wait(l);
124140
}
125141
while (!read_trylock(l));
126142
}
@@ -153,10 +169,10 @@ void srw_lock_low::write_lock()
153169
else
154170
DBUG_ASSERT(~WRITER_WAITING & l);
155171

156-
wait(l);
172+
writer_wait(l);
157173
}
158174
}
159175

160-
void srw_lock_low::rd_unlock() { if (read_unlock()) wake_one(); }
176+
void srw_lock_low::rd_unlock() { if (read_unlock()) writer_wake(); }
161177

162-
void srw_lock_low::wr_unlock() { write_unlock(); wake_all(); }
178+
void srw_lock_low::wr_unlock() { write_unlock(); readers_wake(); }

0 commit comments

Comments
 (0)