📄 sync0rw.ic
字号:
/******************************************************The read-write lock (for threads)(c) 1995 Innobase OyCreated 9/11/1995 Heikki Tuuri*******************************************************//**********************************************************************Lock an rw-lock in shared mode for the current thread. If the rw-lock islocked in exclusive mode, or there is an exclusive lock request waiting,the function spins a preset time (controlled by SYNC_SPIN_ROUNDS),waiting for the lock before suspending the thread. */voidrw_lock_s_lock_spin(/*================*/ 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 */#ifdef UNIV_SYNC_DEBUG/**********************************************************************Inserts the debug information for an rw-lock. */voidrw_lock_add_debug_info(/*===================*/ rw_lock_t* lock, /* in: rw-lock */ ulint pass, /* in: pass value */ ulint lock_type, /* in: lock type */ const char* file_name, /* in: file where requested */ ulint line); /* in: line where requested *//**********************************************************************Removes a debug information struct for an rw-lock. */voidrw_lock_remove_debug_info(/*======================*/ rw_lock_t* lock, /* in: rw-lock */ ulint pass, /* in: pass value */ ulint lock_type); /* in: lock type */#endif /* UNIV_SYNC_DEBUG *//************************************************************************Accessor functions for rw lock. */UNIV_INLINEulintrw_lock_get_waiters(/*================*/ rw_lock_t* lock){ return(lock->waiters);}UNIV_INLINEvoidrw_lock_set_waiters(/*================*/ rw_lock_t* lock, ulint flag){ lock->waiters = flag;}UNIV_INLINEulintrw_lock_get_writer(/*===============*/ rw_lock_t* lock){ return(lock->writer);}UNIV_INLINEvoidrw_lock_set_writer(/*===============*/ rw_lock_t* lock, ulint flag){ lock->writer = flag;}UNIV_INLINEulintrw_lock_get_reader_count(/*=====================*/ rw_lock_t* lock){ return(lock->reader_count);}UNIV_INLINEvoidrw_lock_set_reader_count(/*=====================*/ rw_lock_t* lock, ulint count){ lock->reader_count = count;}UNIV_INLINEmutex_t*rw_lock_get_mutex(/*==============*/ rw_lock_t* lock){ return(&(lock->mutex));}/**********************************************************************Returns the value of writer_count for the lock. Does not reserve the lockmutex, so the caller must be sure it is not changed during the call. */UNIV_INLINEulintrw_lock_get_x_lock_count(/*=====================*/ /* out: value of writer_count */ rw_lock_t* lock) /* in: rw-lock */{ return(lock->writer_count);}/**********************************************************************Low-level function which tries to lock an rw-lock in s-mode. Performs nospinning. */UNIV_INLINEiboolrw_lock_s_lock_low(/*===============*/ /* out: TRUE if success */ rw_lock_t* lock, /* in: pointer to rw-lock */ ulint pass __attribute__((unused)), /* 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 */{#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(rw_lock_get_mutex(lock)));#endif /* UNIV_SYNC_DEBUG */ /* Check if the writer field is free */ if (UNIV_LIKELY(lock->writer == RW_LOCK_NOT_LOCKED)) { /* Set the shared lock by incrementing the reader count */ lock->reader_count++;#ifdef UNIV_SYNC_DEBUG rw_lock_add_debug_info(lock, pass, RW_LOCK_SHARED, file_name, line);#endif lock->last_s_file_name = file_name; lock->last_s_line = line; return(TRUE); /* locking succeeded */ } return(FALSE); /* locking did not succeed */}/**********************************************************************Low-level function which locks an rw-lock in s-mode when we know that itis possible and none else is currently accessing the rw-lock structure.Then we can do the locking without reserving the mutex. */UNIV_INLINEvoidrw_lock_s_lock_direct(/*==================*/ rw_lock_t* lock, /* in: pointer to rw-lock */ const char* file_name, /* in: file name where requested */ ulint line) /* in: line where lock requested */{ ut_ad(lock->writer == RW_LOCK_NOT_LOCKED); ut_ad(rw_lock_get_reader_count(lock) == 0); /* Set the shared lock by incrementing the reader count */ lock->reader_count++; lock->last_s_file_name = file_name; lock->last_s_line = line;#ifdef UNIV_SYNC_DEBUG rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name, line);#endif}/**********************************************************************Low-level function which locks an rw-lock in x-mode when we know that itis not locked and none else is currently accessing the rw-lock structure.Then we can do the locking without reserving the mutex. */UNIV_INLINEvoidrw_lock_x_lock_direct(/*==================*/ rw_lock_t* lock, /* in: pointer to rw-lock */ const char* file_name, /* in: file name where requested */ ulint line) /* in: line where lock requested */{ ut_ad(rw_lock_validate(lock)); ut_ad(rw_lock_get_reader_count(lock) == 0); ut_ad(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED); rw_lock_set_writer(lock, RW_LOCK_EX); lock->writer_thread = os_thread_get_curr_id(); lock->writer_count++; lock->pass = 0; lock->last_x_file_name = file_name; lock->last_x_line = line;#ifdef UNIV_SYNC_DEBUG rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);#endif}/**********************************************************************NOTE! Use the corresponding macro, not directly this function! Lock anrw-lock in shared mode for the current thread. If the rw-lock is lockedin exclusive mode, or there is an exclusive lock request waiting, thefunction spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting forthe lock, before suspending the thread. */UNIV_INLINEvoidrw_lock_s_lock_func(/*================*/ 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 */{ /* NOTE: As we do not know the thread ids for threads which have s-locked a latch, and s-lockers will be served only after waiting x-lock requests have been fulfilled, then if this thread already owns an s-lock here, it may end up in a deadlock with another thread which requests an x-lock here. Therefore, we will forbid recursive s-locking of a latch: the following assert will warn the programmer of the possibility of a tjis kind of deadlock. If we want to implement safe recursive s-locking, we should keep in a list the thread ids of the threads which have s-locked a latch. This would use some CPU time. */ #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */#endif /* UNIV_SYNC_DEBUG */ mutex_enter(rw_lock_get_mutex(lock)); if (UNIV_LIKELY(rw_lock_s_lock_low(lock, pass, file_name, line))) { mutex_exit(rw_lock_get_mutex(lock)); return; /* Success */ } else { /* Did not succeed, try spin wait */ mutex_exit(rw_lock_get_mutex(lock)); rw_lock_s_lock_spin(lock, pass, file_name, line); return; }}/**********************************************************************NOTE! Use the corresponding macro, not directly this function! Lock anrw-lock in shared mode for the current thread if the lock can be acquiredimmediately. */UNIV_INLINEiboolrw_lock_s_lock_func_nowait(/*=======================*/ /* out: TRUE if success */ rw_lock_t* lock, /* in: pointer to rw-lock */ const char* file_name,/* in: file name where lock requested */ ulint line) /* in: line where requested */{ ibool success = FALSE; mutex_enter(rw_lock_get_mutex(lock)); if (lock->writer == RW_LOCK_NOT_LOCKED) { /* Set the shared lock by incrementing the reader count */ lock->reader_count++;#ifdef UNIV_SYNC_DEBUG rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name, line);#endif lock->last_s_file_name = file_name; lock->last_s_line = line; success = TRUE; } mutex_exit(rw_lock_get_mutex(lock)); return(success);}/**********************************************************************NOTE! Use the corresponding macro, not directly this function! Lock anrw-lock in exclusive mode for the current thread if the lock can beobtained immediately. */UNIV_INLINEiboolrw_lock_x_lock_func_nowait(/*=======================*/ /* out: TRUE if success */ rw_lock_t* lock, /* in: pointer to rw-lock */ const char* file_name,/* in: file name where lock requested */ ulint line) /* in: line where requested */{ ibool success = FALSE; os_thread_id_t curr_thread = os_thread_get_curr_id(); mutex_enter(rw_lock_get_mutex(lock)); if (UNIV_UNLIKELY(rw_lock_get_reader_count(lock) != 0)) { } else if (UNIV_LIKELY(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED)) { rw_lock_set_writer(lock, RW_LOCK_EX); lock->writer_thread = curr_thread; lock->pass = 0; relock: lock->writer_count++; #ifdef UNIV_SYNC_DEBUG rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);#endif lock->last_x_file_name = file_name; lock->last_x_line = line; success = TRUE; } else if (rw_lock_get_writer(lock) == RW_LOCK_EX && lock->pass == 0 && os_thread_eq(lock->writer_thread, curr_thread)) { goto relock; } mutex_exit(rw_lock_get_mutex(lock)); ut_ad(rw_lock_validate(lock)); return(success);}/**********************************************************************Releases a shared mode lock. */UNIV_INLINEvoidrw_lock_s_unlock_func(/*==================*/ rw_lock_t* lock /* in: rw-lock */#ifdef UNIV_SYNC_DEBUG ,ulint pass /* in: pass value; != 0, if the lock may have been passed to another thread to unlock */#endif ){ mutex_t* mutex = &(lock->mutex); ibool sg = FALSE; /* Acquire the mutex protecting the rw-lock fields */ mutex_enter(mutex); /* Reset the shared lock by decrementing the reader count */ ut_ad(lock->reader_count > 0); lock->reader_count--;#ifdef UNIV_SYNC_DEBUG rw_lock_remove_debug_info(lock, pass, RW_LOCK_SHARED);#endif /* If there may be waiters and this was the last s-lock, signal the object */ if (UNIV_UNLIKELY(lock->waiters) && lock->reader_count == 0) { sg = TRUE; rw_lock_set_waiters(lock, 0); } mutex_exit(mutex); if (UNIV_UNLIKELY(sg)) { sync_array_signal_object(sync_primary_wait_array, lock); } ut_ad(rw_lock_validate(lock));#ifdef UNIV_SYNC_PERF_STAT rw_s_exit_count++;#endif}/**********************************************************************Releases a shared mode lock when we know there are no waiters and noneelse will access the lock during the time this function is executed. */UNIV_INLINEvoidrw_lock_s_unlock_direct(/*====================*/ rw_lock_t* lock) /* in: rw-lock */{ /* Reset the shared lock by decrementing the reader count */ ut_ad(lock->reader_count > 0); lock->reader_count--;#ifdef UNIV_SYNC_DEBUG rw_lock_remove_debug_info(lock, 0, RW_LOCK_SHARED);#endif ut_ad(!lock->waiters); ut_ad(rw_lock_validate(lock));#ifdef UNIV_SYNC_PERF_STAT rw_s_exit_count++;#endif}/**********************************************************************Releases an exclusive mode lock. */UNIV_INLINEvoidrw_lock_x_unlock_func(/*==================*/ rw_lock_t* lock /* in: rw-lock */#ifdef UNIV_SYNC_DEBUG ,ulint pass /* in: pass value; != 0, if the lock may have been passed to another thread to unlock */#endif ){ ibool sg = FALSE; /* Acquire the mutex protecting the rw-lock fields */ mutex_enter(&(lock->mutex)); /* Reset the exclusive lock if this thread no longer has an x-mode lock */ ut_ad(lock->writer_count > 0); lock->writer_count--; if (lock->writer_count == 0) { rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED); }#ifdef UNIV_SYNC_DEBUG rw_lock_remove_debug_info(lock, pass, RW_LOCK_EX);#endif /* If there may be waiters, signal the lock */ if (UNIV_UNLIKELY(lock->waiters) && lock->writer_count == 0) { sg = TRUE; rw_lock_set_waiters(lock, 0); } mutex_exit(&(lock->mutex)); if (UNIV_UNLIKELY(sg)) { sync_array_signal_object(sync_primary_wait_array, lock); } ut_ad(rw_lock_validate(lock));#ifdef UNIV_SYNC_PERF_STAT rw_x_exit_count++;#endif}/**********************************************************************Releases an exclusive mode lock when we know there are no waiters, andnone else will access the lock durint the time this function is executed. */UNIV_INLINEvoidrw_lock_x_unlock_direct(/*====================*/ rw_lock_t* lock) /* in: rw-lock */{ /* Reset the exclusive lock if this thread no longer has an x-mode lock */ ut_ad(lock->writer_count > 0); lock->writer_count--; if (lock->writer_count == 0) { rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED); }#ifdef UNIV_SYNC_DEBUG rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX);#endif ut_ad(!lock->waiters); ut_ad(rw_lock_validate(lock));#ifdef UNIV_SYNC_PERF_STAT rw_x_exit_count++;#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -