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