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.ic267
1 files changed, 267 insertions, 0 deletions
diff --git a/storage/innobase/include/sync0sync.ic b/storage/innobase/include/sync0sync.ic
new file mode 100644
index 00000000000..b3fde61db5e
--- /dev/null
+++ b/storage/innobase/include/sync0sync.ic
@@ -0,0 +1,267 @@
+/******************************************************
+Mutex, the basic synchronization primitive
+
+(c) 1995 Innobase Oy
+
+Created 9/5/1995 Heikki Tuuri
+*******************************************************/
+
+/**********************************************************************
+Sets the waiters field in a mutex. */
+
+void
+mutex_set_waiters(
+/*==============*/
+ 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. */
+
+void
+mutex_spin_wait(
+/*============*/
+ 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. */
+
+void
+mutex_set_debug_info(
+/*=================*/
+ 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. */
+
+void
+mutex_signal_object(
+/*================*/
+ mutex_t* mutex); /* in: mutex */
+
+/**********************************************************************
+Performs an atomic test-and-set instruction to the lock_word field of a
+mutex. */
+UNIV_INLINE
+ulint
+mutex_test_and_set(
+/*===============*/
+ /* out: the previous value of lock_word: 0 or
+ 1 */
+ mutex_t* mutex) /* in: mutex */
+{
+#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
+ ulint res;
+ ulint* lw; /* assembler code is used to ensure that
+ lock_word is loaded from memory */
+ ut_ad(mutex);
+ ut_ad(sizeof(ulint) == 4);
+
+ lw = &(mutex->lock_word);
+
+ __asm MOV ECX, lw
+ __asm MOV EDX, 1
+ __asm XCHG EDX, DWORD PTR [ECX]
+ __asm MOV res, EDX
+
+ /* The fence below would prevent this thread from reading the data
+ structure protected by the mutex before the test-and-set operation is
+ committed, but the fence is apparently not needed:
+
+ In a posting to comp.arch newsgroup (August 10, 1997) Andy Glew said
+ that in P6 a LOCKed instruction like XCHG establishes a fence with
+ respect to memory reads and writes and thus an explicit fence is not
+ needed. In P5 he seemed to agree with a previous newsgroup poster that
+ LOCKed instructions serialize all instruction execution, and,
+ consequently, also memory operations. This is confirmed in Intel
+ Software Dev. Manual, Vol. 3. */
+
+ /* mutex_fence(); */
+
+ return(res);
+#elif defined(not_defined) && defined(__GNUC__) && defined(UNIV_INTEL_X86)
+ ulint* lw;
+ ulint res;
+
+ lw = &(mutex->lock_word);
+
+ /* In assembly we use the so-called AT & T syntax where
+ the order of operands is inverted compared to the ordinary Intel
+ syntax. The 'l' after the mnemonics denotes a 32-bit operation.
+ The line after the code tells which values come out of the asm
+ code, and the second line tells the input to the asm code. */
+
+ asm volatile("movl $1, %%eax; xchgl (%%ecx), %%eax" :
+ "=eax" (res), "=m" (*lw) :
+ "ecx" (lw));
+ return(res);
+#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;
+ }
+
+ return(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(
+/*==================*/
+ mutex_t* mutex) /* in: mutex */
+{
+#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
+ ulint* lw; /* assembler code is used to ensure that
+ lock_word is loaded from memory */
+ ut_ad(mutex);
+
+ lw = &(mutex->lock_word);
+
+ __asm MOV EDX, 0
+ __asm MOV ECX, lw
+ __asm XCHG EDX, DWORD PTR [ECX]
+#elif defined(not_defined) && defined(__GNUC__) && defined(UNIV_INTEL_X86)
+ ulint* lw;
+
+ lw = &(mutex->lock_word);
+
+ /* In assembly we use the so-called AT & T syntax where
+ the order of operands is inverted compared to the ordinary Intel
+ syntax. The 'l' after the mnemonics denotes a 32-bit operation. */
+
+ asm volatile("movl $0, %%eax; xchgl (%%ecx), %%eax" :
+ "=m" (*lw) :
+ "ecx" (lw) :
+ "eax"); /* gcc does not seem to understand
+ that our asm code resets eax: tell it
+ explicitly that after the third ':' */
+#else
+ mutex->lock_word = 0;
+
+ os_fast_mutex_unlock(&(mutex->os_fast_mutex));
+#endif
+}
+
+/**********************************************************************
+Gets the value of the lock word. */
+UNIV_INLINE
+ulint
+mutex_get_lock_word(
+/*================*/
+ mutex_t* mutex) /* in: mutex */
+{
+volatile ulint* ptr; /* declared volatile to ensure that
+ lock_word is loaded from memory */
+ ut_ad(mutex);
+
+ ptr = &(mutex->lock_word);
+
+ return(*ptr);
+}
+
+/**********************************************************************
+Gets the waiters field in a mutex. */
+UNIV_INLINE
+ulint
+mutex_get_waiters(
+/*==============*/
+ /* out: value to set */
+ mutex_t* mutex) /* in: mutex */
+{
+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 */
+}
+
+/**********************************************************************
+Unlocks a mutex owned by the current thread. */
+UNIV_INLINE
+void
+mutex_exit(
+/*=======*/
+ mutex_t* mutex) /* in: pointer to mutex */
+{
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(mutex_own(mutex));
+
+ mutex->thread_id = ULINT_UNDEFINED;
+
+ 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 10 seconds
+ 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(
+/*=============*/
+ 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));
+
+ /* 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. */
+
+#ifndef UNIV_HOTBACKUP
+ mutex->count_using++;
+#endif /* UNIV_HOTBACKUP */
+
+ if (!mutex_test_and_set(mutex))
+ {
+#ifdef UNIV_SYNC_DEBUG
+ mutex_set_debug_info(mutex, file_name, line);
+#endif
+ return; /* Succeeded! */
+ }
+
+ mutex_spin_wait(mutex, file_name, line);
+
+}