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