1 #ifndef THR_RWLOCK_INCLUDED
2 #define THR_RWLOCK_INCLUDED
3
4 /* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License, version 2.0,
8 as published by the Free Software Foundation.
9
10 This program is also distributed with certain software (including
11 but not limited to OpenSSL) that is licensed under separate terms,
12 as designated in a particular file or component or in included license
13 documentation. The authors of MySQL hereby grant you an additional
14 permission to link the program and your derivative works with the
15 separately licensed software that they have included with MySQL.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License, version 2.0, for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
25
26 /**
27 MySQL rwlock implementation.
28
29 There are two "layers":
30 1) native_rw_*()
31 Functions that map directly down to OS primitives.
32 Windows - SRWLock
33 Other OSes - pthread
34 2) mysql_rw*()
35 Functions that include Performance Schema instrumentation.
36 See include/mysql/psi/mysql_thread.h
37
38 This file also includes rw_pr_*(), which implements a special
39 version of rwlocks that prefer readers. The P_S version of these
40 are mysql_prlock_*() - see include/mysql/psi/mysql_thread.h
41 */
42
43 #include "my_global.h"
44 #include "my_thread.h"
45 #include "thr_cond.h"
46
47 C_MODE_START
48
49 #ifdef _WIN32
50 typedef struct st_my_rw_lock_t
51 {
52 SRWLOCK srwlock; /* native reader writer lock */
53 BOOL have_exclusive_srwlock; /* used for unlock */
54 } native_rw_lock_t;
55 #else
56 typedef pthread_rwlock_t native_rw_lock_t;
57 #endif
58
native_rw_init(native_rw_lock_t * rwp)59 static inline int native_rw_init(native_rw_lock_t *rwp)
60 {
61 #ifdef _WIN32
62 InitializeSRWLock(&rwp->srwlock);
63 rwp->have_exclusive_srwlock = FALSE;
64 return 0;
65 #else
66 /* pthread_rwlockattr_t is not used in MySQL */
67 return pthread_rwlock_init(rwp, NULL);
68 #endif
69 }
70
native_rw_destroy(native_rw_lock_t * rwp)71 static inline int native_rw_destroy(native_rw_lock_t *rwp)
72 {
73 #ifdef _WIN32
74 return 0; /* no destroy function */
75 #else
76 return pthread_rwlock_destroy(rwp);
77 #endif
78 }
79
native_rw_rdlock(native_rw_lock_t * rwp)80 static inline int native_rw_rdlock(native_rw_lock_t *rwp)
81 {
82 #ifdef _WIN32
83 AcquireSRWLockShared(&rwp->srwlock);
84 return 0;
85 #else
86 return pthread_rwlock_rdlock(rwp);
87 #endif
88 }
89
native_rw_tryrdlock(native_rw_lock_t * rwp)90 static inline int native_rw_tryrdlock(native_rw_lock_t *rwp)
91 {
92 #ifdef _WIN32
93 if (!TryAcquireSRWLockShared(&rwp->srwlock))
94 return EBUSY;
95 return 0;
96 #else
97 return pthread_rwlock_tryrdlock(rwp);
98 #endif
99 }
100
native_rw_wrlock(native_rw_lock_t * rwp)101 static inline int native_rw_wrlock(native_rw_lock_t *rwp)
102 {
103 #ifdef _WIN32
104 AcquireSRWLockExclusive(&rwp->srwlock);
105 rwp->have_exclusive_srwlock= TRUE;
106 return 0;
107 #else
108 return pthread_rwlock_wrlock(rwp);
109 #endif
110 }
111
native_rw_trywrlock(native_rw_lock_t * rwp)112 static inline int native_rw_trywrlock(native_rw_lock_t *rwp)
113 {
114 #ifdef _WIN32
115 if (!TryAcquireSRWLockExclusive(&rwp->srwlock))
116 return EBUSY;
117 rwp->have_exclusive_srwlock= TRUE;
118 return 0;
119 #else
120 return pthread_rwlock_trywrlock(rwp);
121 #endif
122 }
123
native_rw_unlock(native_rw_lock_t * rwp)124 static inline int native_rw_unlock(native_rw_lock_t *rwp)
125 {
126 #ifdef _WIN32
127 if (rwp->have_exclusive_srwlock)
128 {
129 rwp->have_exclusive_srwlock= FALSE;
130 ReleaseSRWLockExclusive(&rwp->srwlock);
131 }
132 else
133 ReleaseSRWLockShared(&rwp->srwlock);
134 return 0;
135 #else
136 return pthread_rwlock_unlock(rwp);
137 #endif
138 }
139
140
141 /**
142 Portable implementation of special type of read-write locks.
143
144 These locks have two properties which are unusual for rwlocks:
145 1) They "prefer readers" in the sense that they do not allow
146 situations in which rwlock is rd-locked and there is a
147 pending rd-lock which is blocked (e.g. due to pending
148 request for wr-lock).
149 This is a stronger guarantee than one which is provided for
150 PTHREAD_RWLOCK_PREFER_READER_NP rwlocks in Linux.
151 MDL subsystem deadlock detector relies on this property for
152 its correctness.
153 2) They are optimized for uncontended wr-lock/unlock case.
154 This is scenario in which they are most oftenly used
155 within MDL subsystem. Optimizing for it gives significant
156 performance improvements in some of tests involving many
157 connections.
158
159 Another important requirement imposed on this type of rwlock
160 by the MDL subsystem is that it should be OK to destroy rwlock
161 object which is in unlocked state even though some threads might
162 have not yet fully left unlock operation for it (of course there
163 is an external guarantee that no thread will try to lock rwlock
164 which is destroyed).
165 Putting it another way the unlock operation should not access
166 rwlock data after changing its state to unlocked.
167
168 TODO/FIXME: We should consider alleviating this requirement as
169 it blocks us from doing certain performance optimizations.
170 */
171
172 typedef struct st_rw_pr_lock_t {
173 /**
174 Lock which protects the structure.
175 Also held for the duration of wr-lock.
176 */
177 native_mutex_t lock;
178 /**
179 Condition variable which is used to wake-up
180 writers waiting for readers to go away.
181 */
182 native_cond_t no_active_readers;
183 /** Number of active readers. */
184 uint active_readers;
185 /** Number of writers waiting for readers to go away. */
186 uint writers_waiting_readers;
187 /** Indicates whether there is an active writer. */
188 my_bool active_writer;
189 #ifdef SAFE_MUTEX
190 /** Thread holding wr-lock (for debug purposes only). */
191 my_thread_t writer_thread;
192 #endif
193 } rw_pr_lock_t;
194
195 extern int rw_pr_init(rw_pr_lock_t *);
196 extern int rw_pr_rdlock(rw_pr_lock_t *);
197 extern int rw_pr_wrlock(rw_pr_lock_t *);
198 extern int rw_pr_unlock(rw_pr_lock_t *);
199 extern int rw_pr_destroy(rw_pr_lock_t *);
200
201 static inline void
rw_pr_lock_assert_write_owner(const rw_pr_lock_t * rwlock MY_ATTRIBUTE ((unused)))202 rw_pr_lock_assert_write_owner(const rw_pr_lock_t *rwlock MY_ATTRIBUTE((unused)))
203 {
204 #ifdef SAFE_MUTEX
205 DBUG_ASSERT(rwlock->active_writer &&
206 my_thread_equal(my_thread_self(), rwlock->writer_thread));
207 #endif
208 }
209
210 static inline void
rw_pr_lock_assert_not_write_owner(const rw_pr_lock_t * rwlock MY_ATTRIBUTE ((unused)))211 rw_pr_lock_assert_not_write_owner(const rw_pr_lock_t *rwlock MY_ATTRIBUTE((unused)))
212 {
213 #ifdef SAFE_MUTEX
214 DBUG_ASSERT(!rwlock->active_writer ||
215 !my_thread_equal(my_thread_self(), rwlock->writer_thread));
216 #endif
217 }
218
219 C_MODE_END
220
221 #endif /* THR_RWLOCK_INCLUDED */
222