📄 sync0sync.ic
字号:
/******************************************************Mutex, the basic synchronization primitive(c) 1995 Innobase OyCreated 9/5/1995 Heikki Tuuri*******************************************************//**********************************************************************Sets the waiters field in a mutex. */voidmutex_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, thefunction spins a preset time (controlled by SYNC_SPIN_ROUNDS) waitingfor the mutex before suspending the thread. */voidmutex_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. */voidmutex_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. */voidmutex_signal_object(/*================*/ mutex_t* mutex); /* in: mutex *//**********************************************************************Performs an atomic test-and-set instruction to the lock_word field of amutex. */UNIV_INLINEulintmutex_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. Thisinstruction also serializes memory operations to the program order. */UNIV_INLINEvoidmutex_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_INLINEulintmutex_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_INLINEulintmutex_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_INLINEvoidmutex_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 functionspins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for the mutexbefore suspending the thread. */UNIV_INLINEvoidmutex_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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -