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