1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2008, Google Inc. |
5 | Copyright (c) 2017, MariaDB Corporation. All Rights Reserved. |
6 | |
7 | Portions of this file contain modifications contributed and copyrighted by |
8 | Google, Inc. Those modifications are gratefully acknowledged and are described |
9 | briefly in the InnoDB documentation. The contributions by Google are |
10 | incorporated with their permission, and subject to the conditions contained in |
11 | the file COPYING.Google. |
12 | |
13 | This program is free software; you can redistribute it and/or modify it under |
14 | the terms of the GNU General Public License as published by the Free Software |
15 | Foundation; version 2 of the License. |
16 | |
17 | This program is distributed in the hope that it will be useful, but WITHOUT |
18 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
19 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
20 | |
21 | You should have received a copy of the GNU General Public License along with |
22 | this program; if not, write to the Free Software Foundation, Inc., |
23 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
24 | |
25 | *****************************************************************************/ |
26 | |
27 | /**************************************************//** |
28 | @file include/sync0rw.h |
29 | The read-write lock (for threads, not for database transactions) |
30 | |
31 | Created 9/11/1995 Heikki Tuuri |
32 | *******************************************************/ |
33 | |
34 | #ifndef sync0rw_h |
35 | #define sync0rw_h |
36 | |
37 | #include "univ.i" |
38 | #include "ut0counter.h" |
39 | #include "os0event.h" |
40 | #include "ut0mutex.h" |
41 | |
42 | /** Counters for RW locks. */ |
43 | struct rw_lock_stats_t { |
44 | typedef ib_counter_t<int64_t, IB_N_SLOTS> int64_counter_t; |
45 | |
46 | /** number of spin waits on rw-latches, |
47 | resulted during shared (read) locks */ |
48 | int64_counter_t rw_s_spin_wait_count; |
49 | |
50 | /** number of spin loop rounds on rw-latches, |
51 | resulted during shared (read) locks */ |
52 | int64_counter_t rw_s_spin_round_count; |
53 | |
54 | /** number of OS waits on rw-latches, |
55 | resulted during shared (read) locks */ |
56 | int64_counter_t rw_s_os_wait_count; |
57 | |
58 | /** number of spin waits on rw-latches, |
59 | resulted during exclusive (write) locks */ |
60 | int64_counter_t rw_x_spin_wait_count; |
61 | |
62 | /** number of spin loop rounds on rw-latches, |
63 | resulted during exclusive (write) locks */ |
64 | int64_counter_t rw_x_spin_round_count; |
65 | |
66 | /** number of OS waits on rw-latches, |
67 | resulted during exclusive (write) locks */ |
68 | int64_counter_t rw_x_os_wait_count; |
69 | |
70 | /** number of spin waits on rw-latches, |
71 | resulted during sx locks */ |
72 | int64_counter_t rw_sx_spin_wait_count; |
73 | |
74 | /** number of spin loop rounds on rw-latches, |
75 | resulted during sx locks */ |
76 | int64_counter_t rw_sx_spin_round_count; |
77 | |
78 | /** number of OS waits on rw-latches, |
79 | resulted during sx locks */ |
80 | int64_counter_t rw_sx_os_wait_count; |
81 | }; |
82 | |
83 | /* Latch types; these are used also in btr0btr.h and mtr0mtr.h: keep the |
84 | numerical values smaller than 30 (smaller than BTR_MODIFY_TREE and |
85 | MTR_MEMO_MODIFY) and the order of the numerical values like below! and they |
86 | should be 2pow value to be used also as ORed combination of flag. */ |
87 | enum rw_lock_type_t { |
88 | RW_S_LATCH = 1, |
89 | RW_X_LATCH = 2, |
90 | RW_SX_LATCH = 4, |
91 | RW_NO_LATCH = 8 |
92 | }; |
93 | |
94 | /* We decrement lock_word by X_LOCK_DECR for each x_lock. It is also the |
95 | start value for the lock_word, meaning that it limits the maximum number |
96 | of concurrent read locks before the rw_lock breaks. */ |
97 | /* We decrement lock_word by X_LOCK_HALF_DECR for sx_lock. */ |
98 | #define X_LOCK_DECR 0x20000000 |
99 | #define X_LOCK_HALF_DECR 0x10000000 |
100 | |
101 | #ifdef rw_lock_t |
102 | #undef rw_lock_t |
103 | #endif |
104 | struct rw_lock_t; |
105 | |
106 | #ifdef UNIV_DEBUG |
107 | struct rw_lock_debug_t; |
108 | #endif /* UNIV_DEBUG */ |
109 | |
110 | typedef UT_LIST_BASE_NODE_T(rw_lock_t) rw_lock_list_t; |
111 | |
112 | extern rw_lock_list_t rw_lock_list; |
113 | extern ib_mutex_t rw_lock_list_mutex; |
114 | |
115 | /** Counters for RW locks. */ |
116 | extern rw_lock_stats_t rw_lock_stats; |
117 | |
118 | #ifndef UNIV_PFS_RWLOCK |
119 | /******************************************************************//** |
120 | Creates, or rather, initializes an rw-lock object in a specified memory |
121 | location (which must be appropriately aligned). The rw-lock is initialized |
122 | to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free |
123 | is necessary only if the memory block containing it is freed. |
124 | if MySQL performance schema is enabled and "UNIV_PFS_RWLOCK" is |
125 | defined, the rwlock are instrumented with performance schema probes. */ |
126 | # ifdef UNIV_DEBUG |
127 | # define rw_lock_create(K, L, level) \ |
128 | rw_lock_create_func((L), (level), __FILE__, __LINE__) |
129 | # else /* UNIV_DEBUG */ |
130 | # define rw_lock_create(K, L, level) \ |
131 | rw_lock_create_func((L), __FILE__, __LINE__) |
132 | # endif /* UNIV_DEBUG */ |
133 | |
134 | /**************************************************************//** |
135 | NOTE! The following macros should be used in rw locking and |
136 | unlocking, not the corresponding function. */ |
137 | |
138 | # define rw_lock_s_lock(M) \ |
139 | rw_lock_s_lock_func((M), 0, __FILE__, __LINE__) |
140 | |
141 | # define rw_lock_s_lock_inline(M, P, F, L) \ |
142 | rw_lock_s_lock_func((M), (P), (F), (L)) |
143 | |
144 | # define rw_lock_s_lock_gen(M, P) \ |
145 | rw_lock_s_lock_func((M), (P), __FILE__, __LINE__) |
146 | |
147 | # define rw_lock_s_lock_nowait(M, F, L) \ |
148 | rw_lock_s_lock_low((M), 0, (F), (L)) |
149 | |
150 | # ifdef UNIV_DEBUG |
151 | # define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(P, L) |
152 | # else |
153 | # define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(L) |
154 | # endif /* UNIV_DEBUG */ |
155 | |
156 | #define rw_lock_sx_lock(L) \ |
157 | rw_lock_sx_lock_func((L), 0, __FILE__, __LINE__) |
158 | |
159 | #define rw_lock_sx_lock_inline(M, P, F, L) \ |
160 | rw_lock_sx_lock_func((M), (P), (F), (L)) |
161 | |
162 | #define rw_lock_sx_lock_gen(M, P) \ |
163 | rw_lock_sx_lock_func((M), (P), __FILE__, __LINE__) |
164 | |
165 | #define rw_lock_sx_lock_nowait(M, P) \ |
166 | rw_lock_sx_lock_low((M), (P), __FILE__, __LINE__) |
167 | |
168 | #define rw_lock_sx_lock(L) \ |
169 | rw_lock_sx_lock_func((L), 0, __FILE__, __LINE__) |
170 | |
171 | #define rw_lock_sx_lock_inline(M, P, F, L) \ |
172 | rw_lock_sx_lock_func((M), (P), (F), (L)) |
173 | |
174 | #define rw_lock_sx_lock_gen(M, P) \ |
175 | rw_lock_sx_lock_func((M), (P), __FILE__, __LINE__) |
176 | |
177 | #define rw_lock_sx_lock_nowait(M, P) \ |
178 | rw_lock_sx_lock_low((M), (P), __FILE__, __LINE__) |
179 | |
180 | # ifdef UNIV_DEBUG |
181 | # define rw_lock_sx_unlock(L) rw_lock_sx_unlock_func(0, L) |
182 | # define rw_lock_sx_unlock_gen(L, P) rw_lock_sx_unlock_func(P, L) |
183 | # else /* UNIV_DEBUG */ |
184 | # define rw_lock_sx_unlock(L) rw_lock_sx_unlock_func(L) |
185 | # define rw_lock_sx_unlock_gen(L, P) rw_lock_sx_unlock_func(L) |
186 | # endif /* UNIV_DEBUG */ |
187 | |
188 | # define rw_lock_x_lock(M) \ |
189 | rw_lock_x_lock_func((M), 0, __FILE__, __LINE__) |
190 | |
191 | # define rw_lock_x_lock_inline(M, P, F, L) \ |
192 | rw_lock_x_lock_func((M), (P), (F), (L)) |
193 | |
194 | # define rw_lock_x_lock_gen(M, P) \ |
195 | rw_lock_x_lock_func((M), (P), __FILE__, __LINE__) |
196 | |
197 | # define rw_lock_x_lock_nowait(M) \ |
198 | rw_lock_x_lock_func_nowait((M), __FILE__, __LINE__) |
199 | |
200 | # define rw_lock_x_lock_func_nowait_inline(M, F, L) \ |
201 | rw_lock_x_lock_func_nowait((M), (F), (L)) |
202 | |
203 | # ifdef UNIV_DEBUG |
204 | # define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(P, L) |
205 | # else |
206 | # define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(L) |
207 | # endif |
208 | |
209 | # define rw_lock_free(M) rw_lock_free_func(M) |
210 | |
211 | #else /* !UNIV_PFS_RWLOCK */ |
212 | |
213 | /* Following macros point to Performance Schema instrumented functions. */ |
214 | # ifdef UNIV_DEBUG |
215 | # define rw_lock_create(K, L, level) \ |
216 | pfs_rw_lock_create_func((K), (L), (level), __FILE__, __LINE__) |
217 | # else /* UNIV_DEBUG */ |
218 | # define rw_lock_create(K, L, level) \ |
219 | pfs_rw_lock_create_func((K), (L), __FILE__, __LINE__) |
220 | # endif /* UNIV_DEBUG */ |
221 | |
222 | /****************************************************************** |
223 | NOTE! The following macros should be used in rw locking and |
224 | unlocking, not the corresponding function. */ |
225 | |
226 | # define rw_lock_s_lock(M) \ |
227 | pfs_rw_lock_s_lock_func((M), 0, __FILE__, __LINE__) |
228 | |
229 | # define rw_lock_s_lock_inline(M, P, F, L) \ |
230 | pfs_rw_lock_s_lock_func((M), (P), (F), (L)) |
231 | |
232 | # define rw_lock_s_lock_gen(M, P) \ |
233 | pfs_rw_lock_s_lock_func((M), (P), __FILE__, __LINE__) |
234 | |
235 | # define rw_lock_s_lock_nowait(M, F, L) \ |
236 | pfs_rw_lock_s_lock_low((M), 0, (F), (L)) |
237 | |
238 | # ifdef UNIV_DEBUG |
239 | # define rw_lock_s_unlock_gen(L, P) pfs_rw_lock_s_unlock_func(P, L) |
240 | # else |
241 | # define rw_lock_s_unlock_gen(L, P) pfs_rw_lock_s_unlock_func(L) |
242 | # endif |
243 | |
244 | # define rw_lock_sx_lock(M) \ |
245 | pfs_rw_lock_sx_lock_func((M), 0, __FILE__, __LINE__) |
246 | |
247 | # define rw_lock_sx_lock_inline(M, P, F, L) \ |
248 | pfs_rw_lock_sx_lock_func((M), (P), (F), (L)) |
249 | |
250 | # define rw_lock_sx_lock_gen(M, P) \ |
251 | pfs_rw_lock_sx_lock_func((M), (P), __FILE__, __LINE__) |
252 | |
253 | #define rw_lock_sx_lock_nowait(M, P) \ |
254 | pfs_rw_lock_sx_lock_low((M), (P), __FILE__, __LINE__) |
255 | |
256 | # ifdef UNIV_DEBUG |
257 | # define rw_lock_sx_unlock(L) pfs_rw_lock_sx_unlock_func(0, L) |
258 | # define rw_lock_sx_unlock_gen(L, P) pfs_rw_lock_sx_unlock_func(P, L) |
259 | # else |
260 | # define rw_lock_sx_unlock(L) pfs_rw_lock_sx_unlock_func(L) |
261 | # define rw_lock_sx_unlock_gen(L, P) pfs_rw_lock_sx_unlock_func(L) |
262 | # endif |
263 | |
264 | # define rw_lock_x_lock(M) \ |
265 | pfs_rw_lock_x_lock_func((M), 0, __FILE__, __LINE__) |
266 | |
267 | # define rw_lock_x_lock_inline(M, P, F, L) \ |
268 | pfs_rw_lock_x_lock_func((M), (P), (F), (L)) |
269 | |
270 | # define rw_lock_x_lock_gen(M, P) \ |
271 | pfs_rw_lock_x_lock_func((M), (P), __FILE__, __LINE__) |
272 | |
273 | # define rw_lock_x_lock_nowait(M) \ |
274 | pfs_rw_lock_x_lock_func_nowait((M), __FILE__, __LINE__) |
275 | |
276 | # define rw_lock_x_lock_func_nowait_inline(M, F, L) \ |
277 | pfs_rw_lock_x_lock_func_nowait((M), (F), (L)) |
278 | |
279 | # ifdef UNIV_DEBUG |
280 | # define rw_lock_x_unlock_gen(L, P) pfs_rw_lock_x_unlock_func(P, L) |
281 | # else |
282 | # define rw_lock_x_unlock_gen(L, P) pfs_rw_lock_x_unlock_func(L) |
283 | # endif |
284 | |
285 | # define rw_lock_free(M) pfs_rw_lock_free_func(M) |
286 | |
287 | #endif /* !UNIV_PFS_RWLOCK */ |
288 | |
289 | #define rw_lock_s_unlock(L) rw_lock_s_unlock_gen(L, 0) |
290 | #define rw_lock_x_unlock(L) rw_lock_x_unlock_gen(L, 0) |
291 | |
292 | /******************************************************************//** |
293 | Creates, or rather, initializes an rw-lock object in a specified memory |
294 | location (which must be appropriately aligned). The rw-lock is initialized |
295 | to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free |
296 | is necessary only if the memory block containing it is freed. */ |
297 | void |
298 | rw_lock_create_func( |
299 | /*================*/ |
300 | rw_lock_t* lock, /*!< in: pointer to memory */ |
301 | #ifdef UNIV_DEBUG |
302 | latch_level_t level, /*!< in: level */ |
303 | #endif /* UNIV_DEBUG */ |
304 | const char* cfile_name, /*!< in: file name where created */ |
305 | unsigned cline); /*!< in: file line where created */ |
306 | /******************************************************************//** |
307 | Calling this function is obligatory only if the memory buffer containing |
308 | the rw-lock is freed. Removes an rw-lock object from the global list. The |
309 | rw-lock is checked to be in the non-locked state. */ |
310 | void |
311 | rw_lock_free_func( |
312 | /*==============*/ |
313 | rw_lock_t* lock); /*!< in/out: rw-lock */ |
314 | #ifdef UNIV_DEBUG |
315 | /******************************************************************//** |
316 | Checks that the rw-lock has been initialized and that there are no |
317 | simultaneous shared and exclusive locks. |
318 | @return true */ |
319 | bool |
320 | rw_lock_validate( |
321 | /*=============*/ |
322 | const rw_lock_t* lock); /*!< in: rw-lock */ |
323 | #endif /* UNIV_DEBUG */ |
324 | /******************************************************************//** |
325 | Low-level function which tries to lock an rw-lock in s-mode. Performs no |
326 | spinning. |
327 | @return TRUE if success */ |
328 | UNIV_INLINE |
329 | ibool |
330 | rw_lock_s_lock_low( |
331 | /*===============*/ |
332 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
333 | ulint pass MY_ATTRIBUTE((unused)), |
334 | /*!< in: pass value; != 0, if the lock will be |
335 | passed to another thread to unlock */ |
336 | const char* file_name, /*!< in: file name where lock requested */ |
337 | unsigned line); /*!< in: line where requested */ |
338 | /******************************************************************//** |
339 | NOTE! Use the corresponding macro, not directly this function, except if |
340 | you supply the file name and line number. Lock an rw-lock in shared mode |
341 | for the current thread. If the rw-lock is locked in exclusive mode, or |
342 | there is an exclusive lock request waiting, the function spins a preset |
343 | time (controlled by srv_n_spin_wait_rounds), waiting for the lock, before |
344 | suspending the thread. */ |
345 | UNIV_INLINE |
346 | void |
347 | rw_lock_s_lock_func( |
348 | /*================*/ |
349 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
350 | ulint pass, /*!< in: pass value; != 0, if the lock will |
351 | be passed to another thread to unlock */ |
352 | const char* file_name,/*!< in: file name where lock requested */ |
353 | unsigned line); /*!< in: line where requested */ |
354 | /******************************************************************//** |
355 | NOTE! Use the corresponding macro, not directly this function! Lock an |
356 | rw-lock in exclusive mode for the current thread if the lock can be |
357 | obtained immediately. |
358 | @return TRUE if success */ |
359 | UNIV_INLINE |
360 | ibool |
361 | rw_lock_x_lock_func_nowait( |
362 | /*=======================*/ |
363 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
364 | const char* file_name,/*!< in: file name where lock requested */ |
365 | unsigned line); /*!< in: line where requested */ |
366 | /******************************************************************//** |
367 | Releases a shared mode lock. */ |
368 | UNIV_INLINE |
369 | void |
370 | rw_lock_s_unlock_func( |
371 | /*==================*/ |
372 | #ifdef UNIV_DEBUG |
373 | ulint pass, /*!< in: pass value; != 0, if the lock may have |
374 | been passed to another thread to unlock */ |
375 | #endif /* UNIV_DEBUG */ |
376 | rw_lock_t* lock); /*!< in/out: rw-lock */ |
377 | |
378 | /******************************************************************//** |
379 | NOTE! Use the corresponding macro, not directly this function! Lock an |
380 | rw-lock in exclusive mode for the current thread. If the rw-lock is locked |
381 | in shared or exclusive mode, or there is an exclusive lock request waiting, |
382 | the function spins a preset time (controlled by srv_n_spin_wait_rounds), waiting |
383 | for the lock, before suspending the thread. If the same thread has an x-lock |
384 | on the rw-lock, locking succeed, with the following exception: if pass != 0, |
385 | only a single x-lock may be taken on the lock. NOTE: If the same thread has |
386 | an s-lock, locking does not succeed! */ |
387 | void |
388 | rw_lock_x_lock_func( |
389 | /*================*/ |
390 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
391 | ulint pass, /*!< in: pass value; != 0, if the lock will |
392 | be passed to another thread to unlock */ |
393 | const char* file_name,/*!< in: file name where lock requested */ |
394 | unsigned line); /*!< in: line where requested */ |
395 | /******************************************************************//** |
396 | Low-level function for acquiring an sx lock. |
397 | @return FALSE if did not succeed, TRUE if success. */ |
398 | ibool |
399 | rw_lock_sx_lock_low( |
400 | /*================*/ |
401 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
402 | ulint pass, /*!< in: pass value; != 0, if the lock will |
403 | be passed to another thread to unlock */ |
404 | const char* file_name,/*!< in: file name where lock requested */ |
405 | unsigned line); /*!< in: line where requested */ |
406 | /******************************************************************//** |
407 | NOTE! Use the corresponding macro, not directly this function! Lock an |
408 | rw-lock in SX mode for the current thread. If the rw-lock is locked |
409 | in exclusive mode, or there is an exclusive lock request waiting, |
410 | the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting |
411 | for the lock, before suspending the thread. If the same thread has an x-lock |
412 | on the rw-lock, locking succeed, with the following exception: if pass != 0, |
413 | only a single sx-lock may be taken on the lock. NOTE: If the same thread has |
414 | an s-lock, locking does not succeed! */ |
415 | void |
416 | rw_lock_sx_lock_func( |
417 | /*=================*/ |
418 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
419 | ulint pass, /*!< in: pass value; != 0, if the lock will |
420 | be passed to another thread to unlock */ |
421 | const char* file_name,/*!< in: file name where lock requested */ |
422 | unsigned line); /*!< in: line where requested */ |
423 | /******************************************************************//** |
424 | Releases an exclusive mode lock. */ |
425 | UNIV_INLINE |
426 | void |
427 | rw_lock_x_unlock_func( |
428 | /*==================*/ |
429 | #ifdef UNIV_DEBUG |
430 | ulint pass, /*!< in: pass value; != 0, if the lock may have |
431 | been passed to another thread to unlock */ |
432 | #endif /* UNIV_DEBUG */ |
433 | rw_lock_t* lock); /*!< in/out: rw-lock */ |
434 | |
435 | /******************************************************************//** |
436 | Releases an sx mode lock. */ |
437 | UNIV_INLINE |
438 | void |
439 | rw_lock_sx_unlock_func( |
440 | /*===================*/ |
441 | #ifdef UNIV_DEBUG |
442 | ulint pass, /*!< in: pass value; != 0, if the lock may have |
443 | been passed to another thread to unlock */ |
444 | #endif /* UNIV_DEBUG */ |
445 | rw_lock_t* lock); /*!< in/out: rw-lock */ |
446 | |
447 | /******************************************************************//** |
448 | This function is used in the insert buffer to move the ownership of an |
449 | x-latch on a buffer frame to the current thread. The x-latch was set by |
450 | the buffer read operation and it protected the buffer frame while the |
451 | read was done. The ownership is moved because we want that the current |
452 | thread is able to acquire a second x-latch which is stored in an mtr. |
453 | This, in turn, is needed to pass the debug checks of index page |
454 | operations. */ |
455 | void |
456 | rw_lock_x_lock_move_ownership( |
457 | /*==========================*/ |
458 | rw_lock_t* lock); /*!< in: lock which was x-locked in the |
459 | buffer read */ |
460 | /******************************************************************//** |
461 | Returns the value of writer_count for the lock. Does not reserve the lock |
462 | mutex, so the caller must be sure it is not changed during the call. |
463 | @return value of writer_count */ |
464 | UNIV_INLINE |
465 | ulint |
466 | rw_lock_get_x_lock_count( |
467 | /*=====================*/ |
468 | const rw_lock_t* lock); /*!< in: rw-lock */ |
469 | /******************************************************************//** |
470 | Returns the number of sx-lock for the lock. Does not reserve the lock |
471 | mutex, so the caller must be sure it is not changed during the call. |
472 | @return value of writer_count */ |
473 | UNIV_INLINE |
474 | ulint |
475 | rw_lock_get_sx_lock_count( |
476 | /*======================*/ |
477 | const rw_lock_t* lock); /*!< in: rw-lock */ |
478 | /******************************************************************//** |
479 | Returns the write-status of the lock - this function made more sense |
480 | with the old rw_lock implementation. |
481 | @return RW_LOCK_NOT_LOCKED, RW_LOCK_X, RW_LOCK_X_WAIT, RW_LOCK_SX */ |
482 | UNIV_INLINE |
483 | ulint |
484 | rw_lock_get_writer( |
485 | /*===============*/ |
486 | const rw_lock_t* lock); /*!< in: rw-lock */ |
487 | /******************************************************************//** |
488 | Returns the number of readers (s-locks). |
489 | @return number of readers */ |
490 | UNIV_INLINE |
491 | ulint |
492 | rw_lock_get_reader_count( |
493 | /*=====================*/ |
494 | const rw_lock_t* lock); /*!< in: rw-lock */ |
495 | /******************************************************************//** |
496 | Decrements lock_word the specified amount if it is greater than 0. |
497 | This is used by both s_lock and x_lock operations. |
498 | @return true if decr occurs */ |
499 | UNIV_INLINE |
500 | bool |
501 | rw_lock_lock_word_decr( |
502 | /*===================*/ |
503 | rw_lock_t* lock, /*!< in/out: rw-lock */ |
504 | int32_t amount, /*!< in: amount to decrement */ |
505 | int32_t threshold); /*!< in: threshold of judgement */ |
506 | #ifdef UNIV_DEBUG |
507 | /******************************************************************//** |
508 | Checks if the thread has locked the rw-lock in the specified mode, with |
509 | the pass value == 0. */ |
510 | bool |
511 | rw_lock_own( |
512 | /*========*/ |
513 | rw_lock_t* lock, /*!< in: rw-lock */ |
514 | ulint lock_type) /*!< in: lock type: RW_LOCK_S, |
515 | RW_LOCK_X */ |
516 | MY_ATTRIBUTE((warn_unused_result)); |
517 | |
518 | /******************************************************************//** |
519 | Checks if the thread has locked the rw-lock in the specified mode, with |
520 | the pass value == 0. */ |
521 | bool |
522 | rw_lock_own_flagged( |
523 | /*================*/ |
524 | const rw_lock_t* lock, /*!< in: rw-lock */ |
525 | rw_lock_flags_t flags) /*!< in: specify lock types with |
526 | OR of the rw_lock_flag_t values */ |
527 | MY_ATTRIBUTE((warn_unused_result)); |
528 | #endif /* UNIV_DEBUG */ |
529 | /******************************************************************//** |
530 | Checks if somebody has locked the rw-lock in the specified mode. |
531 | @return true if locked */ |
532 | bool |
533 | rw_lock_is_locked( |
534 | /*==============*/ |
535 | rw_lock_t* lock, /*!< in: rw-lock */ |
536 | ulint lock_type); /*!< in: lock type: RW_LOCK_S, |
537 | RW_LOCK_X or RW_LOCK_SX */ |
538 | #ifdef UNIV_DEBUG |
539 | /***************************************************************//** |
540 | Prints debug info of currently locked rw-locks. */ |
541 | void |
542 | rw_lock_list_print_info( |
543 | /*====================*/ |
544 | FILE* file); /*!< in: file where to print */ |
545 | |
546 | /*#####################################################################*/ |
547 | |
548 | /*********************************************************************//** |
549 | Prints info of a debug struct. */ |
550 | void |
551 | rw_lock_debug_print( |
552 | /*================*/ |
553 | FILE* f, /*!< in: output stream */ |
554 | const rw_lock_debug_t* info); /*!< in: debug struct */ |
555 | #endif /* UNIV_DEBUG */ |
556 | |
557 | /* NOTE! The structure appears here only for the compiler to know its size. |
558 | Do not use its fields directly! */ |
559 | |
560 | /** The structure used in the spin lock implementation of a read-write |
561 | lock. Several threads may have a shared lock simultaneously in this |
562 | lock, but only one writer may have an exclusive lock, in which case no |
563 | shared locks are allowed. To prevent starving of a writer blocked by |
564 | readers, a writer may queue for x-lock by decrementing lock_word: no |
565 | new readers will be let in while the thread waits for readers to |
566 | exit. */ |
567 | |
568 | struct rw_lock_t |
569 | #ifdef UNIV_DEBUG |
570 | : public latch_t |
571 | #endif /* UNIV_DEBUG */ |
572 | { |
573 | /** Holds the state of the lock. */ |
574 | int32_t lock_word; |
575 | |
576 | /** 1: there are waiters */ |
577 | int32_t waiters; |
578 | |
579 | /** number of granted SX locks. */ |
580 | volatile ulint sx_recursive; |
581 | |
582 | /** This is TRUE if the writer field is RW_LOCK_X_WAIT; this field |
583 | is located far from the memory update hotspot fields which are at |
584 | the start of this struct, thus we can peek this field without |
585 | causing much memory bus traffic */ |
586 | bool writer_is_wait_ex; |
587 | |
588 | /** The value is typically set to thread id of a writer thread making |
589 | normal rw_locks recursive. In case of asynchronous IO, when a non-zero |
590 | value of 'pass' is passed then we keep the lock non-recursive. |
591 | |
592 | writer_thread must be reset in x_unlock functions before incrementing |
593 | the lock_word. */ |
594 | volatile os_thread_id_t writer_thread; |
595 | |
596 | /** Used by sync0arr.cc for thread queueing */ |
597 | os_event_t event; |
598 | |
599 | /** Event for next-writer to wait on. A thread must decrement |
600 | lock_word before waiting. */ |
601 | os_event_t wait_ex_event; |
602 | |
603 | /** File name where lock created */ |
604 | const char* cfile_name; |
605 | |
606 | /** File name where last x-locked */ |
607 | const char* last_x_file_name; |
608 | |
609 | /** Line where created */ |
610 | unsigned cline:13; |
611 | |
612 | /** If 1 then the rw-lock is a block lock */ |
613 | unsigned is_block_lock:1; |
614 | |
615 | /** Line number where last time x-locked */ |
616 | unsigned last_x_line:14; |
617 | |
618 | /** Count of os_waits. May not be accurate */ |
619 | uint32_t count_os_wait; |
620 | |
621 | /** All allocated rw locks are put into a list */ |
622 | UT_LIST_NODE_T(rw_lock_t) list; |
623 | |
624 | #ifdef UNIV_PFS_RWLOCK |
625 | /** The instrumentation hook */ |
626 | struct PSI_rwlock* pfs_psi; |
627 | #endif /* UNIV_PFS_RWLOCK */ |
628 | |
629 | #ifdef UNIV_DEBUG |
630 | /** Value of rw_lock_t::magic_n */ |
631 | # define RW_LOCK_MAGIC_N 22643 |
632 | |
633 | /** Constructor */ |
634 | rw_lock_t() |
635 | { |
636 | magic_n = RW_LOCK_MAGIC_N; |
637 | } |
638 | |
639 | /** Destructor */ |
640 | virtual ~rw_lock_t() |
641 | { |
642 | ut_ad(magic_n == RW_LOCK_MAGIC_N); |
643 | magic_n = 0; |
644 | } |
645 | |
646 | virtual std::string to_string() const; |
647 | virtual std::string locked_from() const; |
648 | |
649 | /** For checking memory corruption. */ |
650 | ulint magic_n; |
651 | |
652 | /** In the debug version: pointer to the debug info list of the lock */ |
653 | UT_LIST_BASE_NODE_T(rw_lock_debug_t) debug_list; |
654 | |
655 | /** Level in the global latching order. */ |
656 | latch_level_t level; |
657 | |
658 | #endif /* UNIV_DEBUG */ |
659 | |
660 | }; |
661 | #ifdef UNIV_DEBUG |
662 | /** The structure for storing debug info of an rw-lock. All access to this |
663 | structure must be protected by rw_lock_debug_mutex_enter(). */ |
664 | struct rw_lock_debug_t { |
665 | |
666 | os_thread_id_t thread_id; /*!< The thread id of the thread which |
667 | locked the rw-lock */ |
668 | ulint pass; /*!< Pass value given in the lock operation */ |
669 | ulint lock_type; /*!< Type of the lock: RW_LOCK_X, |
670 | RW_LOCK_S, RW_LOCK_X_WAIT */ |
671 | const char* file_name;/*!< File name where the lock was obtained */ |
672 | unsigned line; /*!< Line where the rw-lock was locked */ |
673 | UT_LIST_NODE_T(rw_lock_debug_t) list; |
674 | /*!< Debug structs are linked in a two-way |
675 | list */ |
676 | }; |
677 | #endif /* UNIV_DEBUG */ |
678 | |
679 | /* For performance schema instrumentation, a new set of rwlock |
680 | wrap functions are created if "UNIV_PFS_RWLOCK" is defined. |
681 | The instrumentations are not planted directly into original |
682 | functions, so that we keep the underlying function as they |
683 | are. And in case, user wants to "take out" some rwlock from |
684 | instrumentation even if performance schema (UNIV_PFS_RWLOCK) |
685 | is defined, they can do so by reinstating APIs directly link to |
686 | original underlying functions. |
687 | The instrumented function names have prefix of "pfs_rw_lock_" vs. |
688 | original name prefix of "rw_lock_". Following are list of functions |
689 | that have been instrumented: |
690 | |
691 | rw_lock_create() |
692 | rw_lock_x_lock() |
693 | rw_lock_x_lock_gen() |
694 | rw_lock_x_lock_nowait() |
695 | rw_lock_x_unlock_gen() |
696 | rw_lock_s_lock() |
697 | rw_lock_s_lock_gen() |
698 | rw_lock_s_lock_nowait() |
699 | rw_lock_s_unlock_gen() |
700 | rw_lock_sx_lock() |
701 | rw_lock_sx_unlock_gen() |
702 | rw_lock_free() |
703 | */ |
704 | |
705 | #ifdef UNIV_PFS_RWLOCK |
706 | /******************************************************************//** |
707 | Performance schema instrumented wrap function for rw_lock_create_func() |
708 | NOTE! Please use the corresponding macro rw_lock_create(), not |
709 | directly this function! */ |
710 | UNIV_INLINE |
711 | void |
712 | pfs_rw_lock_create_func( |
713 | /*====================*/ |
714 | PSI_rwlock_key key, /*!< in: key registered with |
715 | performance schema */ |
716 | rw_lock_t* lock, /*!< in: rw lock */ |
717 | #ifdef UNIV_DEBUG |
718 | latch_level_t level, /*!< in: level */ |
719 | #endif /* UNIV_DEBUG */ |
720 | const char* cfile_name, /*!< in: file name where created */ |
721 | unsigned cline); /*!< in: file line where created */ |
722 | |
723 | /******************************************************************//** |
724 | Performance schema instrumented wrap function for rw_lock_x_lock_func() |
725 | NOTE! Please use the corresponding macro rw_lock_x_lock(), not |
726 | directly this function! */ |
727 | UNIV_INLINE |
728 | void |
729 | pfs_rw_lock_x_lock_func( |
730 | /*====================*/ |
731 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
732 | ulint pass, /*!< in: pass value; != 0, if the lock will |
733 | be passed to another thread to unlock */ |
734 | const char* file_name,/*!< in: file name where lock requested */ |
735 | unsigned line); /*!< in: line where requested */ |
736 | /******************************************************************//** |
737 | Performance schema instrumented wrap function for |
738 | rw_lock_x_lock_func_nowait() |
739 | NOTE! Please use the corresponding macro, not directly this function! |
740 | @return TRUE if success */ |
741 | UNIV_INLINE |
742 | ibool |
743 | pfs_rw_lock_x_lock_func_nowait( |
744 | /*===========================*/ |
745 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
746 | const char* file_name,/*!< in: file name where lock requested */ |
747 | unsigned line); /*!< in: line where requested */ |
748 | /******************************************************************//** |
749 | Performance schema instrumented wrap function for rw_lock_s_lock_func() |
750 | NOTE! Please use the corresponding macro rw_lock_s_lock(), not directly |
751 | this function! */ |
752 | UNIV_INLINE |
753 | void |
754 | pfs_rw_lock_s_lock_func( |
755 | /*====================*/ |
756 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
757 | ulint pass, /*!< in: pass value; != 0, if the lock will |
758 | be passed to another thread to unlock */ |
759 | const char* file_name,/*!< in: file name where lock requested */ |
760 | unsigned line); /*!< in: line where requested */ |
761 | /******************************************************************//** |
762 | Performance schema instrumented wrap function for rw_lock_s_lock_func() |
763 | NOTE! Please use the corresponding macro rw_lock_s_lock(), not directly |
764 | this function! |
765 | @return TRUE if success */ |
766 | UNIV_INLINE |
767 | ibool |
768 | pfs_rw_lock_s_lock_low( |
769 | /*===================*/ |
770 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
771 | ulint pass, /*!< in: pass value; != 0, if the |
772 | lock will be passed to another |
773 | thread to unlock */ |
774 | const char* file_name, /*!< in: file name where lock requested */ |
775 | unsigned line); /*!< in: line where requested */ |
776 | /******************************************************************//** |
777 | Performance schema instrumented wrap function for rw_lock_x_lock_func() |
778 | NOTE! Please use the corresponding macro rw_lock_x_lock(), not directly |
779 | this function! */ |
780 | UNIV_INLINE |
781 | void |
782 | pfs_rw_lock_x_lock_func( |
783 | /*====================*/ |
784 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
785 | ulint pass, /*!< in: pass value; != 0, if the lock will |
786 | be passed to another thread to unlock */ |
787 | const char* file_name,/*!< in: file name where lock requested */ |
788 | unsigned line); /*!< in: line where requested */ |
789 | /******************************************************************//** |
790 | Performance schema instrumented wrap function for rw_lock_s_unlock_func() |
791 | NOTE! Please use the corresponding macro rw_lock_s_unlock(), not directly |
792 | this function! */ |
793 | UNIV_INLINE |
794 | void |
795 | pfs_rw_lock_s_unlock_func( |
796 | /*======================*/ |
797 | #ifdef UNIV_DEBUG |
798 | ulint pass, /*!< in: pass value; != 0, if the |
799 | lock may have been passed to another |
800 | thread to unlock */ |
801 | #endif /* UNIV_DEBUG */ |
802 | rw_lock_t* lock); /*!< in/out: rw-lock */ |
803 | /******************************************************************//** |
804 | Performance schema instrumented wrap function for rw_lock_x_unlock_func() |
805 | NOTE! Please use the corresponding macro rw_lock_x_unlock(), not directly |
806 | this function! */ |
807 | UNIV_INLINE |
808 | void |
809 | pfs_rw_lock_x_unlock_func( |
810 | /*======================*/ |
811 | #ifdef UNIV_DEBUG |
812 | ulint pass, /*!< in: pass value; != 0, if the |
813 | lock may have been passed to another |
814 | thread to unlock */ |
815 | #endif /* UNIV_DEBUG */ |
816 | rw_lock_t* lock); /*!< in/out: rw-lock */ |
817 | /******************************************************************//** |
818 | Performance schema instrumented wrap function for rw_lock_sx_lock_func() |
819 | NOTE! Please use the corresponding macro rw_lock_sx_lock(), not directly |
820 | this function! */ |
821 | UNIV_INLINE |
822 | void |
823 | pfs_rw_lock_sx_lock_func( |
824 | /*====================*/ |
825 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
826 | ulint pass, /*!< in: pass value; != 0, if the lock will |
827 | be passed to another thread to unlock */ |
828 | const char* file_name,/*!< in: file name where lock requested */ |
829 | unsigned line); /*!< in: line where requested */ |
830 | /******************************************************************//** |
831 | Performance schema instrumented wrap function for rw_lock_sx_lock_nowait() |
832 | NOTE! Please use the corresponding macro, not directly |
833 | this function! */ |
834 | UNIV_INLINE |
835 | ibool |
836 | pfs_rw_lock_sx_lock_low( |
837 | /*================*/ |
838 | rw_lock_t* lock, /*!< in: pointer to rw-lock */ |
839 | ulint pass, /*!< in: pass value; != 0, if the lock will |
840 | be passed to another thread to unlock */ |
841 | const char* file_name,/*!< in: file name where lock requested */ |
842 | unsigned line); /*!< in: line where requested */ |
843 | /******************************************************************//** |
844 | Performance schema instrumented wrap function for rw_lock_sx_unlock_func() |
845 | NOTE! Please use the corresponding macro rw_lock_sx_unlock(), not directly |
846 | this function! */ |
847 | UNIV_INLINE |
848 | void |
849 | pfs_rw_lock_sx_unlock_func( |
850 | /*======================*/ |
851 | #ifdef UNIV_DEBUG |
852 | ulint pass, /*!< in: pass value; != 0, if the |
853 | lock may have been passed to another |
854 | thread to unlock */ |
855 | #endif /* UNIV_DEBUG */ |
856 | rw_lock_t* lock); /*!< in/out: rw-lock */ |
857 | /******************************************************************//** |
858 | Performance schema instrumented wrap function for rw_lock_free_func() |
859 | NOTE! Please use the corresponding macro rw_lock_free(), not directly |
860 | this function! */ |
861 | UNIV_INLINE |
862 | void |
863 | pfs_rw_lock_free_func( |
864 | /*==================*/ |
865 | rw_lock_t* lock); /*!< in: rw-lock */ |
866 | #endif /* UNIV_PFS_RWLOCK */ |
867 | |
868 | #include "sync0rw.ic" |
869 | |
870 | #endif /* sync0rw.h */ |
871 | |