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