summaryrefslogtreecommitdiff
path: root/innobase/include/sync0rw.ic
diff options
context:
space:
mode:
Diffstat (limited to 'innobase/include/sync0rw.ic')
-rw-r--r--innobase/include/sync0rw.ic510
1 files changed, 510 insertions, 0 deletions
diff --git a/innobase/include/sync0rw.ic b/innobase/include/sync0rw.ic
new file mode 100644
index 00000000000..11add13d2d0
--- /dev/null
+++ b/innobase/include/sync0rw.ic
@@ -0,0 +1,510 @@
+/******************************************************
+The read-write lock (for threads)
+
+(c) 1995 Innobase Oy
+
+Created 9/11/1995 Heikki Tuuri
+*******************************************************/
+
+/**********************************************************************
+Lock an rw-lock in shared mode for the current thread. If the rw-lock is
+locked 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. */
+
+void
+rw_lock_s_lock_spin(
+/*================*/
+ 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 */
+ char* file_name, /* in: file name where lock requested */
+ ulint line /* in: line where requested */
+ #endif
+);
+/**********************************************************************
+Inserts the debug information for an rw-lock. */
+
+void
+rw_lock_add_debug_info(
+/*===================*/
+ rw_lock_t* lock, /* in: rw-lock */
+ ulint pass, /* in: pass value */
+ ulint lock_type, /* in: lock type */
+ char* file_name, /* in: file where requested */
+ ulint line); /* in: line where requested */
+/**********************************************************************
+Removes a debug information struct for an rw-lock. */
+
+void
+rw_lock_remove_debug_info(
+/*======================*/
+ rw_lock_t* lock, /* in: rw-lock */
+ ulint pass, /* in: pass value */
+ ulint lock_type); /* in: lock type */
+
+
+/************************************************************************
+Accessor functions for rw lock. */
+UNIV_INLINE
+ulint
+rw_lock_get_waiters(
+/*================*/
+ rw_lock_t* lock)
+{
+ return(lock->waiters);
+}
+UNIV_INLINE
+void
+rw_lock_set_waiters(
+/*================*/
+ rw_lock_t* lock,
+ ulint flag)
+{
+ lock->waiters = flag;
+}
+UNIV_INLINE
+ulint
+rw_lock_get_writer(
+/*===============*/
+ rw_lock_t* lock)
+{
+ return(lock->writer);
+}
+UNIV_INLINE
+void
+rw_lock_set_writer(
+/*===============*/
+ rw_lock_t* lock,
+ ulint flag)
+{
+ lock->writer = flag;
+}
+UNIV_INLINE
+ulint
+rw_lock_get_reader_count(
+/*=====================*/
+ rw_lock_t* lock)
+{
+ return(lock->reader_count);
+}
+UNIV_INLINE
+void
+rw_lock_set_reader_count(
+/*=====================*/
+ rw_lock_t* lock,
+ ulint count)
+{
+ lock->reader_count = count;
+}
+UNIV_INLINE
+mutex_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 lock
+mutex, so the caller must be sure it is not changed during the call. */
+UNIV_INLINE
+ulint
+rw_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 no
+spinning. */
+UNIV_INLINE
+ibool
+rw_lock_s_lock_low(
+/*===============*/
+ /* out: TRUE if success */
+ 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 */
+ char* file_name, /* in: file name where lock requested */
+ ulint line /* in: line where requested */
+ #endif
+)
+{
+ ut_ad(mutex_own(rw_lock_get_mutex(lock)));
+
+ /* Check if the writer field is free */
+
+ 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, pass, RW_LOCK_SHARED, file_name,
+ line);
+ #endif
+
+ 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 it
+is possible and none else is currently accessing the rw-lock structure.
+Then we can do the locking without reserving the mutex. */
+UNIV_INLINE
+void
+rw_lock_s_lock_direct(
+/*==================*/
+ rw_lock_t* lock /* in: pointer to rw-lock */
+ #ifdef UNIV_SYNC_DEBUG
+ ,char* file_name, /* in: file name where lock requested */
+ ulint line /* in: line where requested */
+ #endif
+)
+{
+ 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++;
+
+ #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 it
+is not locked and none else is currently accessing the rw-lock structure.
+Then we can do the locking without reserving the mutex. */
+UNIV_INLINE
+void
+rw_lock_x_lock_direct(
+/*==================*/
+ rw_lock_t* lock /* in: pointer to rw-lock */
+ #ifdef UNIV_SYNC_DEBUG
+ ,char* file_name, /* in: file name where lock requested */
+ ulint line /* in: line where requested */
+ #endif
+)
+{
+ 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;
+
+ #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 an
+rw-lock in shared mode for the current thread. If the rw-lock is locked
+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. */
+UNIV_INLINE
+void
+rw_lock_s_lock_func(
+/*================*/
+ 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 */
+ char* file_name, /* in: file name where lock requested */
+ ulint line /* in: line where requested */
+ #endif
+)
+{
+ /* 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. */
+
+ ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */
+
+ mutex_enter(rw_lock_get_mutex(lock));
+
+ if (TRUE == rw_lock_s_lock_low(lock
+ #ifdef UNIV_SYNC_DEBUG
+ ,pass, file_name, line
+ #endif
+ )) {
+ 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
+ #ifdef UNIV_SYNC_DEBUG
+ ,pass, file_name, line
+ #endif
+ );
+ return;
+ }
+}
+
+/**********************************************************************
+NOTE! Use the corresponding macro, not directly this function! Lock an
+rw-lock in shared mode for the current thread if the lock can be acquired
+immediately. */
+UNIV_INLINE
+ibool
+rw_lock_s_lock_func_nowait(
+/*=======================*/
+ /* out: TRUE if success */
+ rw_lock_t* lock /* in: pointer to rw-lock */
+ #ifdef UNIV_SYNC_DEBUG
+ ,char* file_name, /* in: file name where lock requested */
+ ulint line /* in: line where requested */
+ #endif
+)
+{
+ 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
+
+ success = TRUE;
+ }
+
+ mutex_exit(rw_lock_get_mutex(lock));
+
+ return(success);
+}
+
+/**********************************************************************
+NOTE! Use the corresponding macro, not directly this function! Lock an
+rw-lock in exclusive mode for the current thread if the lock can be
+obtained immediately. */
+UNIV_INLINE
+ibool
+rw_lock_x_lock_func_nowait(
+/*=======================*/
+ /* out: TRUE if success */
+ rw_lock_t* lock /* in: pointer to rw-lock */
+ #ifdef UNIV_SYNC_DEBUG
+ ,char* file_name, /* in: file name where lock requested */
+ ulint line /* in: line where requested */
+ #endif
+)
+{
+ ibool success = FALSE;
+
+ mutex_enter(rw_lock_get_mutex(lock));
+
+ if ((rw_lock_get_reader_count(lock) == 0)
+ && ((rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED)
+ || ((rw_lock_get_writer(lock) == RW_LOCK_EX)
+ && (lock->pass == 0)
+ && (lock->writer_thread == os_thread_get_curr_id())))) {
+
+ rw_lock_set_writer(lock, RW_LOCK_EX);
+ lock->writer_thread = os_thread_get_curr_id();
+ lock->writer_count++;
+ lock->pass = 0;
+
+ #ifdef UNIV_SYNC_DEBUG
+ rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
+ #endif
+
+ success = TRUE;
+ }
+
+ mutex_exit(rw_lock_get_mutex(lock));
+
+ ut_ad(rw_lock_validate(lock));
+
+ return(success);
+}
+
+/**********************************************************************
+Releases a shared mode lock. */
+UNIV_INLINE
+void
+rw_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 (lock->waiters && (lock->reader_count == 0)) {
+ sg = TRUE;
+
+ rw_lock_set_waiters(lock, 0);
+ }
+
+ mutex_exit(mutex);
+
+ if (sg == TRUE) {
+ 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 none
+else will access the lock during the time this function is executed. */
+UNIV_INLINE
+void
+rw_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_INLINE
+void
+rw_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 (lock->waiters && (lock->writer_count == 0)) {
+
+ sg = TRUE;
+ rw_lock_set_waiters(lock, 0);
+ }
+
+ mutex_exit(&(lock->mutex));
+
+ if (sg == TRUE) {
+ 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, and
+none else will access the lock durint the time this function is executed. */
+UNIV_INLINE
+void
+rw_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
+}