summaryrefslogtreecommitdiff
path: root/storage/innobase/include/sync0sync.ic
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/include/sync0sync.ic')
-rw-r--r--storage/innobase/include/sync0sync.ic414
1 files changed, 414 insertions, 0 deletions
diff --git a/storage/innobase/include/sync0sync.ic b/storage/innobase/include/sync0sync.ic
new file mode 100644
index 00000000000..616e53d4aac
--- /dev/null
+++ b/storage/innobase/include/sync0sync.ic
@@ -0,0 +1,414 @@
+/*****************************************************************************
+
+Copyright (c) 1995, 2009, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2008, Google Inc.
+
+Portions of this file contain modifications contributed and copyrighted by
+Google, Inc. Those modifications are gratefully acknowledged and are described
+briefly in the InnoDB documentation. The contributions by Google are
+incorporated with their permission, and subject to the conditions contained in
+the file COPYING.Google.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file include/sync0sync.ic
+Mutex, the basic synchronization primitive
+
+Created 9/5/1995 Heikki Tuuri
+*******************************************************/
+
+/******************************************************************//**
+Sets the waiters field in a mutex. */
+UNIV_INTERN
+void
+mutex_set_waiters(
+/*==============*/
+ ib_mutex_t* mutex, /*!< in: mutex */
+ ulint n); /*!< in: value to set */
+/******************************************************************//**
+Reserves a mutex for the current thread. If the mutex is reserved, the
+function spins a preset time (controlled by SYNC_SPIN_ROUNDS) waiting
+for the mutex before suspending the thread. */
+UNIV_INTERN
+void
+mutex_spin_wait(
+/*============*/
+ ib_mutex_t* mutex, /*!< in: pointer to mutex */
+ const char* file_name, /*!< in: file name where mutex
+ requested */
+ ulint line); /*!< in: line where requested */
+#ifdef UNIV_SYNC_DEBUG
+/******************************************************************//**
+Sets the debug information for a reserved mutex. */
+UNIV_INTERN
+void
+mutex_set_debug_info(
+/*=================*/
+ ib_mutex_t* mutex, /*!< in: mutex */
+ const char* file_name, /*!< in: file where requested */
+ ulint line); /*!< in: line where requested */
+#endif /* UNIV_SYNC_DEBUG */
+/******************************************************************//**
+Releases the threads waiting in the primary wait array for this mutex. */
+UNIV_INTERN
+void
+mutex_signal_object(
+/*================*/
+ ib_mutex_t* mutex); /*!< in: mutex */
+
+/******************************************************************//**
+Performs an atomic test-and-set instruction to the lock_word field of a
+mutex.
+@return the previous value of lock_word: 0 or 1 */
+UNIV_INLINE
+byte
+ib_mutex_test_and_set(
+/*===============*/
+ ib_mutex_t* mutex) /*!< in: mutex */
+{
+#if defined(HAVE_ATOMIC_BUILTINS)
+# if defined(HAVE_ATOMIC_BUILTINS_BYTE)
+ return(os_atomic_test_and_set_byte(&mutex->lock_word, 1));
+# else
+ return(os_atomic_test_and_set_ulint(&mutex->lock_word, 1));
+# endif
+#else
+ ibool ret;
+
+ ret = os_fast_mutex_trylock(&(mutex->os_fast_mutex));
+
+ if (ret == 0) {
+ /* We check that os_fast_mutex_trylock does not leak
+ and allow race conditions */
+ ut_a(mutex->lock_word == 0);
+
+ mutex->lock_word = 1;
+ os_wmb;
+ }
+
+ return((byte) ret);
+#endif
+}
+
+/******************************************************************//**
+Performs a reset instruction to the lock_word field of a mutex. This
+instruction also serializes memory operations to the program order. */
+UNIV_INLINE
+void
+mutex_reset_lock_word(
+/*==================*/
+ ib_mutex_t* mutex) /*!< in: mutex */
+{
+#if defined(HAVE_ATOMIC_BUILTINS)
+ /* In theory __sync_lock_release should be used to release the lock.
+ Unfortunately, it does not work properly alone. The workaround is
+ that more conservative __sync_lock_test_and_set is used instead. */
+# if defined(HAVE_ATOMIC_BUILTINS_BYTE)
+ os_atomic_test_and_set_byte(&mutex->lock_word, 0);
+# else
+ os_atomic_test_and_set_ulint(&mutex->lock_word, 0);
+# endif
+#else
+ mutex->lock_word = 0;
+
+ os_fast_mutex_unlock(&(mutex->os_fast_mutex));
+#endif
+}
+
+/******************************************************************//**
+Gets the value of the lock word. */
+UNIV_INLINE
+lock_word_t
+mutex_get_lock_word(
+/*================*/
+ const ib_mutex_t* mutex) /*!< in: mutex */
+{
+ ut_ad(mutex);
+
+ return(mutex->lock_word);
+}
+
+/******************************************************************//**
+Gets the waiters field in a mutex.
+@return value to set */
+UNIV_INLINE
+ulint
+mutex_get_waiters(
+/*==============*/
+ const ib_mutex_t* mutex) /*!< in: mutex */
+{
+ const volatile ulint* ptr; /*!< declared volatile to ensure that
+ the value is read from memory */
+ ut_ad(mutex);
+
+ ptr = &(mutex->waiters);
+
+ return(*ptr); /* Here we assume that the read of a single
+ word from memory is atomic */
+}
+
+/******************************************************************//**
+NOTE! Use the corresponding macro mutex_exit(), not directly this function!
+Unlocks a mutex owned by the current thread. */
+UNIV_INLINE
+void
+mutex_exit_func(
+/*============*/
+ ib_mutex_t* mutex) /*!< in: pointer to mutex */
+{
+ ut_ad(mutex_own(mutex));
+
+ ut_d(mutex->thread_id = (os_thread_id_t) ULINT_UNDEFINED);
+
+#ifdef UNIV_SYNC_DEBUG
+ sync_thread_reset_level(mutex);
+#endif
+ mutex_reset_lock_word(mutex);
+
+ /* A problem: we assume that mutex_reset_lock word
+ is a memory barrier, that is when we read the waiters
+ field next, the read must be serialized in memory
+ after the reset. A speculative processor might
+ perform the read first, which could leave a waiting
+ thread hanging indefinitely.
+
+ Our current solution call every second
+ sync_arr_wake_threads_if_sema_free()
+ to wake up possible hanging threads if
+ they are missed in mutex_signal_object. */
+
+ if (mutex_get_waiters(mutex) != 0) {
+
+ mutex_signal_object(mutex);
+ }
+
+#ifdef UNIV_SYNC_PERF_STAT
+ mutex_exit_count++;
+#endif
+}
+
+/******************************************************************//**
+Locks a mutex for the current thread. If the mutex is reserved, the function
+spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for the mutex
+before suspending the thread. */
+UNIV_INLINE
+void
+mutex_enter_func(
+/*=============*/
+ ib_mutex_t* mutex, /*!< in: pointer to mutex */
+ const char* file_name, /*!< in: file name where locked */
+ ulint line) /*!< in: line where locked */
+{
+ ut_ad(mutex_validate(mutex));
+ ut_ad(!mutex_own(mutex));
+
+ /* Note that we do not peek at the value of lock_word before trying
+ the atomic test_and_set; we could peek, and possibly save time. */
+
+ if (!ib_mutex_test_and_set(mutex)) {
+ ut_d(mutex->thread_id = os_thread_get_curr_id());
+#ifdef UNIV_SYNC_DEBUG
+ mutex_set_debug_info(mutex, file_name, line);
+#endif
+ return; /* Succeeded! */
+ }
+
+ mutex_spin_wait(mutex, file_name, line);
+}
+
+#ifdef UNIV_PFS_MUTEX
+/******************************************************************//**
+NOTE! Please use the corresponding macro mutex_enter(), not directly
+this function!
+This is a performance schema instrumented wrapper function for
+mutex_enter_func(). */
+UNIV_INLINE
+void
+pfs_mutex_enter_func(
+/*=================*/
+ ib_mutex_t* mutex, /*!< in: pointer to mutex */
+ const char* file_name, /*!< in: file name where locked */
+ ulint line) /*!< in: line where locked */
+{
+ if (mutex->pfs_psi != NULL) {
+ PSI_mutex_locker* locker;
+ PSI_mutex_locker_state state;
+
+ locker = PSI_MUTEX_CALL(start_mutex_wait)(
+ &state, mutex->pfs_psi,
+ PSI_MUTEX_LOCK, file_name,
+ static_cast<uint>(line));
+
+ mutex_enter_func(mutex, file_name, line);
+
+ if (locker != NULL) {
+ PSI_MUTEX_CALL(end_mutex_wait)(locker, 0);
+ }
+ } else {
+ mutex_enter_func(mutex, file_name, line);
+ }
+}
+
+/********************************************************************//**
+NOTE! Please use the corresponding macro mutex_enter_nowait(), not directly
+this function!
+This is a performance schema instrumented wrapper function for
+mutex_enter_nowait_func.
+@return 0 if succeed, 1 if not */
+UNIV_INLINE
+ulint
+pfs_mutex_enter_nowait_func(
+/*========================*/
+ ib_mutex_t* mutex, /*!< in: pointer to mutex */
+ const char* file_name, /*!< in: file name where mutex
+ requested */
+ ulint line) /*!< in: line where requested */
+{
+ ulint ret;
+
+ if (mutex->pfs_psi != NULL) {
+ PSI_mutex_locker* locker;
+ PSI_mutex_locker_state state;
+
+ locker = PSI_MUTEX_CALL(start_mutex_wait)(
+ &state, mutex->pfs_psi,
+ PSI_MUTEX_TRYLOCK, file_name,
+ static_cast<uint>(line));
+
+ ret = mutex_enter_nowait_func(mutex, file_name, line);
+
+ if (locker != NULL) {
+ PSI_MUTEX_CALL(end_mutex_wait)(locker, (int) ret);
+ }
+ } else {
+ ret = mutex_enter_nowait_func(mutex, file_name, line);
+ }
+
+ return(ret);
+}
+
+/******************************************************************//**
+NOTE! Please use the corresponding macro mutex_exit(), not directly
+this function!
+A wrap function of mutex_exit_func() with performance schema instrumentation.
+Unlocks a mutex owned by the current thread. */
+UNIV_INLINE
+void
+pfs_mutex_exit_func(
+/*================*/
+ ib_mutex_t* mutex) /*!< in: pointer to mutex */
+{
+ if (mutex->pfs_psi != NULL) {
+ PSI_MUTEX_CALL(unlock_mutex)(mutex->pfs_psi);
+ }
+
+ mutex_exit_func(mutex);
+}
+
+/******************************************************************//**
+NOTE! Please use the corresponding macro mutex_create(), not directly
+this function!
+A wrapper function for mutex_create_func(), registers the mutex
+with performance schema if "UNIV_PFS_MUTEX" is defined when
+creating the mutex */
+UNIV_INLINE
+void
+pfs_mutex_create_func(
+/*==================*/
+ mysql_pfs_key_t key, /*!< in: Performance Schema key */
+ ib_mutex_t* mutex, /*!< in: pointer to memory */
+# ifdef UNIV_DEBUG
+ const char* cmutex_name, /*!< in: mutex name */
+# ifdef UNIV_SYNC_DEBUG
+ ulint level, /*!< in: level */
+# endif /* UNIV_SYNC_DEBUG */
+# endif /* UNIV_DEBUG */
+ const char* cfile_name, /*!< in: file name where created */
+ ulint cline) /*!< in: file line where created */
+{
+ mutex->pfs_psi = PSI_MUTEX_CALL(init_mutex)(key, mutex);
+
+ mutex_create_func(mutex,
+# ifdef UNIV_DEBUG
+ cmutex_name,
+# ifdef UNIV_SYNC_DEBUG
+ level,
+# endif /* UNIV_SYNC_DEBUG */
+# endif /* UNIV_DEBUG */
+ cfile_name,
+ cline);
+}
+
+/******************************************************************//**
+NOTE! Please use the corresponding macro mutex_free(), not directly
+this function!
+Wrapper function for mutex_free_func(). Also destroys the performance
+schema probes when freeing the mutex */
+UNIV_INLINE
+void
+pfs_mutex_free_func(
+/*================*/
+ ib_mutex_t* mutex) /*!< in: mutex */
+{
+ if (mutex->pfs_psi != NULL) {
+ PSI_MUTEX_CALL(destroy_mutex)(mutex->pfs_psi);
+ mutex->pfs_psi = NULL;
+ }
+
+ mutex_free_func(mutex);
+}
+
+#endif /* UNIV_PFS_MUTEX */
+
+#ifndef HAVE_ATOMIC_BUILTINS
+/**********************************************************//**
+Function that uses a mutex to decrement a variable atomically */
+UNIV_INLINE
+void
+os_atomic_dec_ulint_func(
+/*=====================*/
+ ib_mutex_t* mutex, /*!< in: mutex guarding the dec */
+ volatile ulint* var, /*!< in/out: variable to decrement */
+ ulint delta) /*!< in: delta to decrement */
+{
+ mutex_enter(mutex);
+
+ /* I don't think we will encounter a situation where
+ this check will not be required. */
+ ut_ad(*var >= delta);
+
+ *var -= delta;
+
+ mutex_exit(mutex);
+}
+
+/**********************************************************//**
+Function that uses a mutex to increment a variable atomically */
+UNIV_INLINE
+void
+os_atomic_inc_ulint_func(
+/*=====================*/
+ ib_mutex_t* mutex, /*!< in: mutex guarding the increment */
+ volatile ulint* var, /*!< in/out: variable to increment */
+ ulint delta) /*!< in: delta to increment */
+{
+ mutex_enter(mutex);
+
+ *var += delta;
+
+ mutex_exit(mutex);
+}
+#endif /* !HAVE_ATOMIC_BUILTINS */