/********************************************************************** Low-level function for acquiring an exclusive lock. */ UNIV_INLINE ulint rw_lock_x_lock_low( /*===============*/ /* out: RW_LOCK_NOT_LOCKED if did not succeed, RW_LOCK_EX if success, RW_LOCK_WAIT_EX, if got wait reservation */ rw_lock_t* lock, /* in: pointer to rw-lock */ ulint pass, /* in: pass value; != 0, if the lock will be passed to another thread to unlock */ const char* file_name,/* in: file name where lock requested */ ulint line) /* in: line where requested */ { ut_ad(mutex_own(rw_lock_get_mutex(lock))); if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) { if (rw_lock_get_reader_count(lock) == 0) { rw_lock_set_writer(lock, RW_LOCK_EX); lock->writer_thread = os_thread_get_curr_id(); lock->writer_count++; lock->pass = pass; #ifdef UNIV_SYNC_DEBUG rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, file_name, line); #endif lock->last_x_file_name = file_name; lock->last_x_line = (unsigned int) line; /* Locking succeeded, we may return */ return(RW_LOCK_EX); } else { /* There are readers, we have to wait */ rw_lock_set_writer(lock, RW_LOCK_WAIT_EX); lock->writer_thread = os_thread_get_curr_id(); lock->pass = pass; lock->writer_is_wait_ex = TRUE; #ifdef UNIV_SYNC_DEBUG rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX, file_name, line); #endif return(RW_LOCK_WAIT_EX); } } else if ((rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX) && os_thread_eq(lock->writer_thread, os_thread_get_curr_id())) { if (rw_lock_get_reader_count(lock) == 0) { rw_lock_set_writer(lock, RW_LOCK_EX); lock->writer_count++; lock->pass = pass; lock->writer_is_wait_ex = FALSE; #ifdef UNIV_SYNC_DEBUG rw_lock_remove_debug_info(lock, pass, RW_LOCK_WAIT_EX); rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, file_name, line); #endif lock->last_x_file_name = file_name; lock->last_x_line = (unsigned int) line; /* Locking succeeded, we may return */ return(RW_LOCK_EX); } return(RW_LOCK_WAIT_EX); } else if ((rw_lock_get_writer(lock) == RW_LOCK_EX) && os_thread_eq(lock->writer_thread, os_thread_get_curr_id()) && (lock->pass == 0) && (pass == 0)) { lock->writer_count++; #ifdef UNIV_SYNC_DEBUG rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, file_name, line); #endif lock->last_x_file_name = file_name; lock->last_x_line = (unsigned int) line; /* Locking succeeded, we may return */ return(RW_LOCK_EX); } /* Locking did not succeed */ return(RW_LOCK_NOT_LOCKED); }
/******************************************************************//** Function for the next writer to call. Waits for readers to exit. The caller must have already decremented lock_word by X_LOCK_DECR. */ UNIV_INLINE void rw_lock_x_lock_wait( /*================*/ rw_lock_t* lock, /*!< in: pointer to rw-lock */ #ifdef UNIV_SYNC_DEBUG ulint pass, /*!< in: pass value; != 0, if the lock will be passed to another thread to unlock */ #endif const char* file_name,/*!< in: file name where lock requested */ ulint line) /*!< in: line where requested */ { ulint index; ulint i = 0; ut_ad(lock->lock_word <= 0); while (lock->lock_word < 0) { if (srv_spin_wait_delay) { ut_delay(ut_rnd_interval(0, srv_spin_wait_delay)); } if(i < SYNC_SPIN_ROUNDS) { i++; continue; } /* If there is still a reader, then go to sleep.*/ rw_x_spin_round_count += i; i = 0; sync_array_reserve_cell(sync_primary_wait_array, lock, RW_LOCK_WAIT_EX, file_name, line, &index); /* Check lock_word to ensure wake-up isn't missed.*/ if(lock->lock_word < 0) { /* these stats may not be accurate */ lock->count_os_wait++; rw_x_os_wait_count++; /* Add debug info as it is needed to detect possible deadlock. We must add info for WAIT_EX thread for deadlock detection to work properly. */ #ifdef UNIV_SYNC_DEBUG rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX, file_name, line); #endif sync_array_wait_event(sync_primary_wait_array, index); #ifdef UNIV_SYNC_DEBUG rw_lock_remove_debug_info(lock, pass, RW_LOCK_WAIT_EX); #endif /* It is possible to wake when lock_word < 0. We must pass the while-loop check to proceed.*/ } else { sync_array_free_cell(sync_primary_wait_array, index); } } rw_x_spin_round_count += i; }