1/*****************************************************************************
2
3Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2008, Google Inc.
5Copyright (c) 2017, MariaDB Corporation. All Rights Reserved.
6
7Portions of this file contain modifications contributed and copyrighted by
8Google, Inc. Those modifications are gratefully acknowledged and are described
9briefly in the InnoDB documentation. The contributions by Google are
10incorporated with their permission, and subject to the conditions contained in
11the file COPYING.Google.
12
13This program is free software; you can redistribute it and/or modify it under
14the terms of the GNU General Public License as published by the Free Software
15Foundation; version 2 of the License.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc.,
2351 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24
25*****************************************************************************/
26
27/**************************************************//**
28@file include/sync0rw.h
29The read-write lock (for threads, not for database transactions)
30
31Created 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. */
43struct 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
84numerical values smaller than 30 (smaller than BTR_MODIFY_TREE and
85MTR_MEMO_MODIFY) and the order of the numerical values like below! and they
86should be 2pow value to be used also as ORed combination of flag. */
87enum 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
95start value for the lock_word, meaning that it limits the maximum number
96of 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
104struct rw_lock_t;
105
106#ifdef UNIV_DEBUG
107struct rw_lock_debug_t;
108#endif /* UNIV_DEBUG */
109
110typedef UT_LIST_BASE_NODE_T(rw_lock_t) rw_lock_list_t;
111
112extern rw_lock_list_t rw_lock_list;
113extern ib_mutex_t rw_lock_list_mutex;
114
115/** Counters for RW locks. */
116extern rw_lock_stats_t rw_lock_stats;
117
118#ifndef UNIV_PFS_RWLOCK
119/******************************************************************//**
120Creates, or rather, initializes an rw-lock object in a specified memory
121location (which must be appropriately aligned). The rw-lock is initialized
122to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
123is necessary only if the memory block containing it is freed.
124if MySQL performance schema is enabled and "UNIV_PFS_RWLOCK" is
125defined, 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/**************************************************************//**
135NOTE! The following macros should be used in rw locking and
136unlocking, 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/******************************************************************
223NOTE! The following macros should be used in rw locking and
224unlocking, 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/******************************************************************//**
293Creates, or rather, initializes an rw-lock object in a specified memory
294location (which must be appropriately aligned). The rw-lock is initialized
295to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
296is necessary only if the memory block containing it is freed. */
297void
298rw_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/******************************************************************//**
307Calling this function is obligatory only if the memory buffer containing
308the rw-lock is freed. Removes an rw-lock object from the global list. The
309rw-lock is checked to be in the non-locked state. */
310void
311rw_lock_free_func(
312/*==============*/
313 rw_lock_t* lock); /*!< in/out: rw-lock */
314#ifdef UNIV_DEBUG
315/******************************************************************//**
316Checks that the rw-lock has been initialized and that there are no
317simultaneous shared and exclusive locks.
318@return true */
319bool
320rw_lock_validate(
321/*=============*/
322 const rw_lock_t* lock); /*!< in: rw-lock */
323#endif /* UNIV_DEBUG */
324/******************************************************************//**
325Low-level function which tries to lock an rw-lock in s-mode. Performs no
326spinning.
327@return TRUE if success */
328UNIV_INLINE
329ibool
330rw_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/******************************************************************//**
339NOTE! Use the corresponding macro, not directly this function, except if
340you supply the file name and line number. Lock an rw-lock in shared mode
341for the current thread. If the rw-lock is locked in exclusive mode, or
342there is an exclusive lock request waiting, the function spins a preset
343time (controlled by srv_n_spin_wait_rounds), waiting for the lock, before
344suspending the thread. */
345UNIV_INLINE
346void
347rw_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/******************************************************************//**
355NOTE! Use the corresponding macro, not directly this function! Lock an
356rw-lock in exclusive mode for the current thread if the lock can be
357obtained immediately.
358@return TRUE if success */
359UNIV_INLINE
360ibool
361rw_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/******************************************************************//**
367Releases a shared mode lock. */
368UNIV_INLINE
369void
370rw_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/******************************************************************//**
379NOTE! Use the corresponding macro, not directly this function! Lock an
380rw-lock in exclusive mode for the current thread. If the rw-lock is locked
381in shared or exclusive mode, or there is an exclusive lock request waiting,
382the function spins a preset time (controlled by srv_n_spin_wait_rounds), waiting
383for the lock, before suspending the thread. If the same thread has an x-lock
384on the rw-lock, locking succeed, with the following exception: if pass != 0,
385only a single x-lock may be taken on the lock. NOTE: If the same thread has
386an s-lock, locking does not succeed! */
387void
388rw_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/******************************************************************//**
396Low-level function for acquiring an sx lock.
397@return FALSE if did not succeed, TRUE if success. */
398ibool
399rw_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/******************************************************************//**
407NOTE! Use the corresponding macro, not directly this function! Lock an
408rw-lock in SX mode for the current thread. If the rw-lock is locked
409in exclusive mode, or there is an exclusive lock request waiting,
410the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
411for the lock, before suspending the thread. If the same thread has an x-lock
412on the rw-lock, locking succeed, with the following exception: if pass != 0,
413only a single sx-lock may be taken on the lock. NOTE: If the same thread has
414an s-lock, locking does not succeed! */
415void
416rw_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/******************************************************************//**
424Releases an exclusive mode lock. */
425UNIV_INLINE
426void
427rw_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/******************************************************************//**
436Releases an sx mode lock. */
437UNIV_INLINE
438void
439rw_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/******************************************************************//**
448This function is used in the insert buffer to move the ownership of an
449x-latch on a buffer frame to the current thread. The x-latch was set by
450the buffer read operation and it protected the buffer frame while the
451read was done. The ownership is moved because we want that the current
452thread is able to acquire a second x-latch which is stored in an mtr.
453This, in turn, is needed to pass the debug checks of index page
454operations. */
455void
456rw_lock_x_lock_move_ownership(
457/*==========================*/
458 rw_lock_t* lock); /*!< in: lock which was x-locked in the
459 buffer read */
460/******************************************************************//**
461Returns the value of writer_count for the lock. Does not reserve the lock
462mutex, so the caller must be sure it is not changed during the call.
463@return value of writer_count */
464UNIV_INLINE
465ulint
466rw_lock_get_x_lock_count(
467/*=====================*/
468 const rw_lock_t* lock); /*!< in: rw-lock */
469/******************************************************************//**
470Returns the number of sx-lock for the lock. Does not reserve the lock
471mutex, so the caller must be sure it is not changed during the call.
472@return value of writer_count */
473UNIV_INLINE
474ulint
475rw_lock_get_sx_lock_count(
476/*======================*/
477 const rw_lock_t* lock); /*!< in: rw-lock */
478/******************************************************************//**
479Returns the write-status of the lock - this function made more sense
480with the old rw_lock implementation.
481@return RW_LOCK_NOT_LOCKED, RW_LOCK_X, RW_LOCK_X_WAIT, RW_LOCK_SX */
482UNIV_INLINE
483ulint
484rw_lock_get_writer(
485/*===============*/
486 const rw_lock_t* lock); /*!< in: rw-lock */
487/******************************************************************//**
488Returns the number of readers (s-locks).
489@return number of readers */
490UNIV_INLINE
491ulint
492rw_lock_get_reader_count(
493/*=====================*/
494 const rw_lock_t* lock); /*!< in: rw-lock */
495/******************************************************************//**
496Decrements lock_word the specified amount if it is greater than 0.
497This is used by both s_lock and x_lock operations.
498@return true if decr occurs */
499UNIV_INLINE
500bool
501rw_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/******************************************************************//**
508Checks if the thread has locked the rw-lock in the specified mode, with
509the pass value == 0. */
510bool
511rw_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/******************************************************************//**
519Checks if the thread has locked the rw-lock in the specified mode, with
520the pass value == 0. */
521bool
522rw_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/******************************************************************//**
530Checks if somebody has locked the rw-lock in the specified mode.
531@return true if locked */
532bool
533rw_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/***************************************************************//**
540Prints debug info of currently locked rw-locks. */
541void
542rw_lock_list_print_info(
543/*====================*/
544 FILE* file); /*!< in: file where to print */
545
546/*#####################################################################*/
547
548/*********************************************************************//**
549Prints info of a debug struct. */
550void
551rw_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.
558Do not use its fields directly! */
559
560/** The structure used in the spin lock implementation of a read-write
561lock. Several threads may have a shared lock simultaneously in this
562lock, but only one writer may have an exclusive lock, in which case no
563shared locks are allowed. To prevent starving of a writer blocked by
564readers, a writer may queue for x-lock by decrementing lock_word: no
565new readers will be let in while the thread waits for readers to
566exit. */
567
568struct 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
663structure must be protected by rw_lock_debug_mutex_enter(). */
664struct 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
680wrap functions are created if "UNIV_PFS_RWLOCK" is defined.
681The instrumentations are not planted directly into original
682functions, so that we keep the underlying function as they
683are. And in case, user wants to "take out" some rwlock from
684instrumentation even if performance schema (UNIV_PFS_RWLOCK)
685is defined, they can do so by reinstating APIs directly link to
686original underlying functions.
687The instrumented function names have prefix of "pfs_rw_lock_" vs.
688original name prefix of "rw_lock_". Following are list of functions
689that have been instrumented:
690
691rw_lock_create()
692rw_lock_x_lock()
693rw_lock_x_lock_gen()
694rw_lock_x_lock_nowait()
695rw_lock_x_unlock_gen()
696rw_lock_s_lock()
697rw_lock_s_lock_gen()
698rw_lock_s_lock_nowait()
699rw_lock_s_unlock_gen()
700rw_lock_sx_lock()
701rw_lock_sx_unlock_gen()
702rw_lock_free()
703*/
704
705#ifdef UNIV_PFS_RWLOCK
706/******************************************************************//**
707Performance schema instrumented wrap function for rw_lock_create_func()
708NOTE! Please use the corresponding macro rw_lock_create(), not
709directly this function! */
710UNIV_INLINE
711void
712pfs_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/******************************************************************//**
724Performance schema instrumented wrap function for rw_lock_x_lock_func()
725NOTE! Please use the corresponding macro rw_lock_x_lock(), not
726directly this function! */
727UNIV_INLINE
728void
729pfs_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/******************************************************************//**
737Performance schema instrumented wrap function for
738rw_lock_x_lock_func_nowait()
739NOTE! Please use the corresponding macro, not directly this function!
740@return TRUE if success */
741UNIV_INLINE
742ibool
743pfs_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/******************************************************************//**
749Performance schema instrumented wrap function for rw_lock_s_lock_func()
750NOTE! Please use the corresponding macro rw_lock_s_lock(), not directly
751this function! */
752UNIV_INLINE
753void
754pfs_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/******************************************************************//**
762Performance schema instrumented wrap function for rw_lock_s_lock_func()
763NOTE! Please use the corresponding macro rw_lock_s_lock(), not directly
764this function!
765@return TRUE if success */
766UNIV_INLINE
767ibool
768pfs_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/******************************************************************//**
777Performance schema instrumented wrap function for rw_lock_x_lock_func()
778NOTE! Please use the corresponding macro rw_lock_x_lock(), not directly
779this function! */
780UNIV_INLINE
781void
782pfs_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/******************************************************************//**
790Performance schema instrumented wrap function for rw_lock_s_unlock_func()
791NOTE! Please use the corresponding macro rw_lock_s_unlock(), not directly
792this function! */
793UNIV_INLINE
794void
795pfs_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/******************************************************************//**
804Performance schema instrumented wrap function for rw_lock_x_unlock_func()
805NOTE! Please use the corresponding macro rw_lock_x_unlock(), not directly
806this function! */
807UNIV_INLINE
808void
809pfs_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/******************************************************************//**
818Performance schema instrumented wrap function for rw_lock_sx_lock_func()
819NOTE! Please use the corresponding macro rw_lock_sx_lock(), not directly
820this function! */
821UNIV_INLINE
822void
823pfs_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/******************************************************************//**
831Performance schema instrumented wrap function for rw_lock_sx_lock_nowait()
832NOTE! Please use the corresponding macro, not directly
833this function! */
834UNIV_INLINE
835ibool
836pfs_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/******************************************************************//**
844Performance schema instrumented wrap function for rw_lock_sx_unlock_func()
845NOTE! Please use the corresponding macro rw_lock_sx_unlock(), not directly
846this function! */
847UNIV_INLINE
848void
849pfs_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/******************************************************************//**
858Performance schema instrumented wrap function for rw_lock_free_func()
859NOTE! Please use the corresponding macro rw_lock_free(), not directly
860this function! */
861UNIV_INLINE
862void
863pfs_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