mariadb/storage/innobase/include/ib0mutex.h

819 lines
18 KiB
C
Raw Normal View History

/*****************************************************************************
Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation. All Rights Reserved.
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.,
2019-05-13 17:47:26 +03:00
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
*****************************************************************************/
/******************************************************************//**
@file include/ib0mutex.h
Policy based mutexes.
Created 2013-03-26 Sunny Bains.
***********************************************************************/
#ifndef UNIV_INNOCHECKSUM
#ifndef ib0mutex_h
#define ib0mutex_h
#include "ut0ut.h"
#include "ut0rnd.h"
#include "os0event.h"
#include "sync0arr.h"
/** OS mutex for tracking lock/unlock for debugging */
template <template <typename> class Policy = NoPolicy>
struct OSTrackMutex {
typedef Policy<OSTrackMutex> MutexPolicy;
explicit OSTrackMutex(bool destroy_mutex_at_exit = true)
UNIV_NOTHROW
{
ut_d(m_freed = true);
ut_d(m_locked = false);
ut_d(m_destroy_at_exit = destroy_mutex_at_exit);
}
~OSTrackMutex() UNIV_NOTHROW
{
ut_ad(!m_destroy_at_exit || !m_locked);
}
/** Initialise the mutex.
@param[in] id Mutex ID
@param[in] filename File where mutex was created
@param[in] line Line in filename */
void init(
latch_id_t id,
const char* filename,
uint32_t line)
UNIV_NOTHROW
{
ut_ad(m_freed);
ut_ad(!m_locked);
m_mutex.init();
ut_d(m_freed = false);
}
/** Destroy the mutex */
void destroy() UNIV_NOTHROW
{
ut_ad(!m_locked);
ut_ad(!m_freed);
m_mutex.destroy();
ut_d(m_freed = true);
}
/** Release the mutex. */
void exit() UNIV_NOTHROW
{
ut_ad(m_locked);
ut_d(m_locked = false);
ut_ad(!m_freed);
m_mutex.exit();
}
/** Acquire the mutex.
@param[in] max_spins max number of spins
@param[in] max_delay max delay per spin
@param[in] filename from where called
@param[in] line within filename */
void enter(
uint32_t max_spins,
uint32_t max_delay,
const char* filename,
uint32_t line)
UNIV_NOTHROW
{
ut_ad(!m_freed);
m_mutex.enter();
ut_ad(!m_locked);
ut_d(m_locked = true);
}
/** @return true if locking succeeded */
bool try_lock() UNIV_NOTHROW
{
ut_ad(!m_freed);
bool locked = m_mutex.try_lock();
if (locked) {
ut_ad(!m_locked);
ut_d(m_locked = locked);
}
return(locked);
}
/** @return non-const version of the policy */
MutexPolicy& policy()
UNIV_NOTHROW
{
return(m_policy);
}
/** @return the const version of the policy */
const MutexPolicy& policy() const
UNIV_NOTHROW
{
return(m_policy);
}
private:
#ifdef UNIV_DEBUG
/** true if the mutex has not be initialized */
bool m_freed;
/** true if the mutex has been locked. */
bool m_locked;
/** Do/Dont destroy mutex at exit */
bool m_destroy_at_exit;
#endif /* UNIV_DEBUG */
/** OS Mutex instance */
OSMutex m_mutex;
/** Policy data */
MutexPolicy m_policy;
};
#ifdef HAVE_IB_LINUX_FUTEX
#include <linux/futex.h>
#include <sys/syscall.h>
/** Mutex implementation that used the Linux futex. */
template <template <typename> class Policy = NoPolicy>
struct TTASFutexMutex {
typedef Policy<TTASFutexMutex> MutexPolicy;
TTASFutexMutex() UNIV_NOTHROW
:
m_lock_word(MUTEX_STATE_UNLOCKED)
{
/* Check that lock_word is aligned. */
ut_ad(!((ulint) &m_lock_word % sizeof(ulint)));
}
~TTASFutexMutex()
{
ut_a(m_lock_word == MUTEX_STATE_UNLOCKED);
}
/** Called when the mutex is "created". Note: Not from the constructor
but when the mutex is initialised.
@param[in] id Mutex ID
@param[in] filename File where mutex was created
@param[in] line Line in filename */
void init(
latch_id_t id,
const char* filename,
uint32_t line)
UNIV_NOTHROW
{
ut_a(m_lock_word == MUTEX_STATE_UNLOCKED);
}
/** Destroy the mutex. */
void destroy() UNIV_NOTHROW
{
/* The destructor can be called at shutdown. */
ut_a(m_lock_word == MUTEX_STATE_UNLOCKED);
}
/** Acquire the mutex.
@param[in] max_spins max number of spins
@param[in] max_delay max delay per spin
@param[in] filename from where called
@param[in] line within filename */
void enter(
uint32_t max_spins,
uint32_t max_delay,
const char* filename,
uint32_t line) UNIV_NOTHROW
{
uint32_t n_spins, n_waits;
for (n_spins= 0; n_spins < max_spins; n_spins++) {
if (try_lock()) {
m_policy.add(n_spins, 0);
return;
}
ut_delay(ut_rnd_interval(0, max_delay));
}
for (n_waits= 0;; n_waits++) {
if (my_atomic_fas32_explicit(&m_lock_word,
MUTEX_STATE_WAITERS,
MY_MEMORY_ORDER_ACQUIRE)
== MUTEX_STATE_UNLOCKED) {
break;
}
syscall(SYS_futex, &m_lock_word,
FUTEX_WAIT_PRIVATE, MUTEX_STATE_WAITERS,
0, 0, 0);
}
m_policy.add(n_spins, n_waits);
}
/** Release the mutex. */
void exit() UNIV_NOTHROW
{
if (my_atomic_fas32_explicit(&m_lock_word,
MUTEX_STATE_UNLOCKED,
MY_MEMORY_ORDER_RELEASE)
== MUTEX_STATE_WAITERS) {
syscall(SYS_futex, &m_lock_word, FUTEX_WAKE_PRIVATE,
1, 0, 0, 0);
}
}
/** Try and lock the mutex.
@return true if successful */
bool try_lock() UNIV_NOTHROW
{
int32 oldval = MUTEX_STATE_UNLOCKED;
return(my_atomic_cas32_strong_explicit(&m_lock_word, &oldval,
MUTEX_STATE_LOCKED,
MY_MEMORY_ORDER_ACQUIRE,
MY_MEMORY_ORDER_RELAXED));
}
/** @return non-const version of the policy */
MutexPolicy& policy() UNIV_NOTHROW
{
return(m_policy);
}
/** @return const version of the policy */
const MutexPolicy& policy() const UNIV_NOTHROW
{
return(m_policy);
}
private:
/** Policy data */
MutexPolicy m_policy;
/** lock_word is the target of the atomic test-and-set instruction
when atomic operations are enabled. */
int32 m_lock_word;
};
#endif /* HAVE_IB_LINUX_FUTEX */
template <template <typename> class Policy = NoPolicy>
struct TTASMutex {
typedef Policy<TTASMutex> MutexPolicy;
TTASMutex() UNIV_NOTHROW
:
m_lock_word(MUTEX_STATE_UNLOCKED)
{
/* Check that lock_word is aligned. */
ut_ad(!((ulint) &m_lock_word % sizeof(ulint)));
}
~TTASMutex()
{
ut_ad(m_lock_word == MUTEX_STATE_UNLOCKED);
}
/** Called when the mutex is "created". Note: Not from the constructor
but when the mutex is initialised.
@param[in] id Mutex ID
@param[in] filename File where mutex was created
@param[in] line Line in filename */
void init(
latch_id_t id,
const char* filename,
uint32_t line)
UNIV_NOTHROW
{
ut_ad(m_lock_word == MUTEX_STATE_UNLOCKED);
}
/** Destroy the mutex. */
void destroy() UNIV_NOTHROW
{
/* The destructor can be called at shutdown. */
ut_ad(m_lock_word == MUTEX_STATE_UNLOCKED);
}
/** Try and lock the mutex.
@return true on success */
bool try_lock() UNIV_NOTHROW
{
int32 oldval = MUTEX_STATE_UNLOCKED;
return(my_atomic_cas32_strong_explicit(&m_lock_word, &oldval,
MUTEX_STATE_LOCKED,
MY_MEMORY_ORDER_ACQUIRE,
MY_MEMORY_ORDER_RELAXED));
}
/** Release the mutex. */
void exit() UNIV_NOTHROW
{
ut_ad(m_lock_word == MUTEX_STATE_LOCKED);
my_atomic_store32_explicit(&m_lock_word, MUTEX_STATE_UNLOCKED,
MY_MEMORY_ORDER_RELEASE);
}
/** Acquire the mutex.
@param max_spins max number of spins
@param max_delay max delay per spin
@param filename from where called
@param line within filename */
void enter(
uint32_t max_spins,
uint32_t max_delay,
const char* filename,
uint32_t line) UNIV_NOTHROW
{
const uint32_t step = max_spins;
uint32_t n_spins = 0;
while (!try_lock()) {
ut_delay(ut_rnd_interval(0, max_delay));
if (++n_spins == max_spins) {
os_thread_yield();
max_spins+= step;
}
}
m_policy.add(n_spins, 0);
}
/** @return non-const version of the policy */
MutexPolicy& policy() UNIV_NOTHROW
{
return(m_policy);
}
/** @return const version of the policy */
const MutexPolicy& policy() const UNIV_NOTHROW
{
return(m_policy);
}
private:
// Disable copying
TTASMutex(const TTASMutex&);
TTASMutex& operator=(const TTASMutex&);
/** Policy data */
MutexPolicy m_policy;
/** lock_word is the target of the atomic test-and-set instruction
when atomic operations are enabled. */
int32 m_lock_word;
};
template <template <typename> class Policy = NoPolicy>
struct TTASEventMutex {
typedef Policy<TTASEventMutex> MutexPolicy;
TTASEventMutex()
UNIV_NOTHROW
:
m_lock_word(MUTEX_STATE_UNLOCKED),
m_event()
{
/* Check that lock_word is aligned. */
ut_ad(!((ulint) &m_lock_word % sizeof(ulint)));
}
~TTASEventMutex()
UNIV_NOTHROW
{
ut_ad(m_lock_word == MUTEX_STATE_UNLOCKED);
}
/** Called when the mutex is "created". Note: Not from the constructor
but when the mutex is initialised.
@param[in] id Mutex ID
@param[in] filename File where mutex was created
@param[in] line Line in filename */
void init(
latch_id_t id,
const char* filename,
uint32_t line)
UNIV_NOTHROW
{
ut_a(m_event == 0);
ut_a(m_lock_word == MUTEX_STATE_UNLOCKED);
m_event = os_event_create(sync_latch_get_name(id));
}
/** This is the real desctructor. This mutex can be created in BSS and
its desctructor will be called on exit(). We can't call
os_event_destroy() at that stage. */
void destroy()
UNIV_NOTHROW
{
ut_ad(m_lock_word == MUTEX_STATE_UNLOCKED);
/* We have to free the event before InnoDB shuts down. */
os_event_destroy(m_event);
m_event = 0;
}
/** Try and lock the mutex. Note: POSIX returns 0 on success.
@return true on success */
bool try_lock()
UNIV_NOTHROW
{
int32 oldval = MUTEX_STATE_UNLOCKED;
return(my_atomic_cas32_strong_explicit(&m_lock_word, &oldval,
MUTEX_STATE_LOCKED,
MY_MEMORY_ORDER_ACQUIRE,
MY_MEMORY_ORDER_RELAXED));
}
/** Release the mutex. */
void exit()
UNIV_NOTHROW
{
if (my_atomic_fas32_explicit(&m_lock_word,
MUTEX_STATE_UNLOCKED,
MY_MEMORY_ORDER_RELEASE)
== MUTEX_STATE_WAITERS) {
os_event_set(m_event);
sync_array_object_signalled();
}
}
/** Acquire the mutex.
@param[in] max_spins max number of spins
@param[in] max_delay max delay per spin
@param[in] filename from where called
@param[in] line within filename */
void enter(
uint32_t max_spins,
uint32_t max_delay,
const char* filename,
uint32_t line)
UNIV_NOTHROW
{
uint32_t n_spins = 0;
uint32_t n_waits = 0;
const uint32_t step = max_spins;
while (!try_lock()) {
if (n_spins++ == max_spins) {
max_spins += step;
n_waits++;
os_thread_yield();
sync_cell_t* cell;
sync_array_t *sync_arr = sync_array_get_and_reserve_cell(
this,
(m_policy.get_id() == LATCH_ID_BUF_BLOCK_MUTEX
|| m_policy.get_id() == LATCH_ID_BUF_POOL_ZIP)
? SYNC_BUF_BLOCK
: SYNC_MUTEX,
filename, line, &cell);
int32 oldval = MUTEX_STATE_LOCKED;
my_atomic_cas32_strong_explicit(&m_lock_word, &oldval,
MUTEX_STATE_WAITERS,
MY_MEMORY_ORDER_RELAXED,
MY_MEMORY_ORDER_RELAXED);
if (oldval == MUTEX_STATE_UNLOCKED) {
sync_array_free_cell(sync_arr, cell);
} else {
sync_array_wait_event(sync_arr, cell);
}
} else {
ut_delay(ut_rnd_interval(0, max_delay));
}
}
m_policy.add(n_spins, n_waits);
}
/** @return the lock state. */
int32 state() const
UNIV_NOTHROW
{
2018-03-22 22:47:40 +04:00
return(my_atomic_load32_explicit(const_cast<int32*>
(&m_lock_word),
fix data races srv_last_monitor_time: make all accesses relaxed atomical WARNING: ThreadSanitizer: data race (pid=12041) Write of size 8 at 0x000003949278 by thread T26 (mutexes: write M226445748578513120): #0 thd_destructor_proxy storage/innobase/handler/ha_innodb.cc:314:14 (mysqld+0x19b5505) Previous read of size 8 at 0x000003949278 by main thread: #0 innobase_init(void*) storage/innobase/handler/ha_innodb.cc:4180:11 (mysqld+0x1a03404) #1 ha_initialize_handlerton(st_plugin_int*) sql/handler.cc:522:31 (mysqld+0xc5ec73) #2 plugin_initialize(st_mem_root*, st_plugin_int*, int*, char**, bool) sql/sql_plugin.cc:1447:9 (mysqld+0x134908d) #3 plugin_init(int*, char**, int) sql/sql_plugin.cc:1729:15 (mysqld+0x13484f0) #4 init_server_components() sql/mysqld.cc:5345:7 (mysqld+0xbf720f) #5 mysqld_main(int, char**) sql/mysqld.cc:5940:7 (mysqld+0xbf107d) #6 main sql/main.cc:25:10 (mysqld+0xbe971b) Location is global 'srv_running' of size 8 at 0x000003949278 (mysqld+0x000003949278) WARNING: ThreadSanitizer: data race (pid=27869) Atomic write of size 4 at 0x7b4800000c00 by thread T8: #0 __tsan_atomic32_exchange llvm/projects/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cc:589 (mysqld+0xbd4eac) #1 TTASEventMutex<GenericPolicy>::exit() storage/innobase/include/ib0mutex.h:467:7 (mysqld+0x1a8d4cb) #2 PolicyMutex<TTASEventMutex<GenericPolicy> >::exit() storage/innobase/include/ib0mutex.h:609:10 (mysqld+0x1a7839e) #3 fil_validate() storage/innobase/fil/fil0fil.cc:5535:2 (mysqld+0x1abd913) #4 fil_validate_skip() storage/innobase/fil/fil0fil.cc:204:9 (mysqld+0x1aba601) #5 fil_aio_wait(unsigned long) storage/innobase/fil/fil0fil.cc:5296:2 (mysqld+0x1abbae6) #6 io_handler_thread storage/innobase/srv/srv0start.cc:340:3 (mysqld+0x21abe1e) Previous read of size 4 at 0x7b4800000c00 by main thread (mutexes: write M1273, write M1271): #0 TTASEventMutex<GenericPolicy>::state() const storage/innobase/include/ib0mutex.h:530:10 (mysqld+0x21c66e2) #1 sync_array_detect_deadlock(sync_array_t*, sync_cell_t*, sync_cell_t*, unsigned long) storage/innobase/sync/sync0arr.cc:746:14 (mysqld+0x21c1c7a) #2 sync_array_wait_event(sync_array_t*, sync_cell_t*&) storage/innobase/sync/sync0arr.cc:465:6 (mysqld+0x21c1708) #3 TTASEventMutex<GenericPolicy>::enter(unsigned int, unsigned int, char const*, unsigned int) storage/innobase/include/ib0mutex.h:516:6 (mysqld+0x1a8c206) #4 PolicyMutex<TTASEventMutex<GenericPolicy> >::enter(unsigned int, unsigned int, char const*, unsigned int) storage/innobase/include/ib0mutex.h:635:10 (mysqld+0x1a782c3) #5 fil_mutex_enter_and_prepare_for_io(unsigned long) storage/innobase/fil/fil0fil.cc:1131:3 (mysqld+0x1a9a92e) #6 fil_io(IORequest const&, bool, page_id_t const&, page_size_t const&, unsigned long, unsigned long, void*, void*, bool) storage/innobase/fil/fil0fil.cc:5082:2 (mysqld+0x1ab8de2) #7 buf_flush_write_block_low(buf_page_t*, buf_flush_t, bool) storage/innobase/buf/buf0flu.cc:1112:3 (mysqld+0x1cb970a) #8 buf_flush_page(buf_pool_t*, buf_page_t*, buf_flush_t, bool) storage/innobase/buf/buf0flu.cc:1270:3 (mysqld+0x1cb7d70) #9 buf_flush_try_neighbors(page_id_t const&, buf_flush_t, unsigned long, unsigned long) storage/innobase/buf/buf0flu.cc:1493:9 (mysqld+0x1cc9674) #10 buf_flush_page_and_try_neighbors(buf_page_t*, buf_flush_t, unsigned long, unsigned long*) storage/innobase/buf/buf0flu.cc:1565:13 (mysqld+0x1cbadf3) #11 buf_do_flush_list_batch(buf_pool_t*, unsigned long, unsigned long) storage/innobase/buf/buf0flu.cc:1825:3 (mysqld+0x1cbbcb8) #12 buf_flush_batch(buf_pool_t*, buf_flush_t, unsigned long, unsigned long, flush_counters_t*) storage/innobase/buf/buf0flu.cc:1895:16 (mysqld+0x1cbb459) #13 buf_flush_do_batch(buf_pool_t*, buf_flush_t, unsigned long, unsigned long, flush_counters_t*) storage/innobase/buf/buf0flu.cc:2065:2 (mysqld+0x1cbcfe1) #14 buf_flush_lists(unsigned long, unsigned long, unsigned long*) storage/innobase/buf/buf0flu.cc:2167:8 (mysqld+0x1cbd5a3) #15 log_preflush_pool_modified_pages(unsigned long) storage/innobase/log/log0log.cc:1400:13 (mysqld+0x1eefc3b) #16 log_make_checkpoint_at(unsigned long, bool) storage/innobase/log/log0log.cc:1751:10 (mysqld+0x1eefb16) #17 buf_dblwr_create() storage/innobase/buf/buf0dblwr.cc:335:2 (mysqld+0x1cd2141) #18 innobase_start_or_create_for_mysql() storage/innobase/srv/srv0start.cc:2539:10 (mysqld+0x21b4d8e) #19 innobase_init(void*) storage/innobase/handler/ha_innodb.cc:4193:8 (mysqld+0x1a5e3d7) #20 ha_initialize_handlerton(st_plugin_int*) sql/handler.cc:522:31 (mysqld+0xc74d33) #21 plugin_initialize(st_mem_root*, st_plugin_int*, int*, char**, bool) sql/sql_plugin.cc:1447:9 (mysqld+0x1376d5d) #22 plugin_init(int*, char**, int) sql/sql_plugin.cc:1729:15 (mysqld+0x13761c0) #23 init_server_components() sql/mysqld.cc:5348:7 (mysqld+0xc0d0ff) #24 mysqld_main(int, char**) sql/mysqld.cc:5943:7 (mysqld+0xc06f9d) #25 main sql/main.cc:25:10 (mysqld+0xbff71b) WARNING: ThreadSanitizer: data race (pid=29031) Write of size 8 at 0x0000039e48e0 by thread T15: #0 srv_monitor_thread storage/innobase/srv/srv0srv.cc:1699:24 (mysqld+0x21a254e) Previous write of size 8 at 0x0000039e48e0 by thread T14: #0 srv_refresh_innodb_monitor_stats() storage/innobase/srv/srv0srv.cc:1165:24 (mysqld+0x21a3124) #1 srv_error_monitor_thread storage/innobase/srv/srv0srv.cc:1836:3 (mysqld+0x21a2d40) Location is global 'srv_last_monitor_time' of size 8 at 0x0000039e48e0 (mysqld+0x0000039e48e0)
2018-01-31 20:30:46 +03:00
MY_MEMORY_ORDER_RELAXED));
}
/** The event that the mutex will wait in sync0arr.cc
@return even instance */
os_event_t event()
UNIV_NOTHROW
{
return(m_event);
}
/** @return non-const version of the policy */
MutexPolicy& policy()
UNIV_NOTHROW
{
return(m_policy);
}
/** @return const version of the policy */
const MutexPolicy& policy() const
UNIV_NOTHROW
{
return(m_policy);
}
private:
/** Disable copying */
TTASEventMutex(const TTASEventMutex&);
TTASEventMutex& operator=(const TTASEventMutex&);
/** lock_word is the target of the atomic test-and-set instruction
when atomic operations are enabled. */
int32 m_lock_word;
/** Used by sync0arr.cc for the wait queue */
os_event_t m_event;
/** Policy data */
MutexPolicy m_policy;
};
/** Mutex interface for all policy mutexes. This class handles the interfacing
with the Performance Schema instrumentation. */
template <typename MutexImpl>
struct PolicyMutex
{
typedef MutexImpl MutexType;
typedef typename MutexImpl::MutexPolicy Policy;
PolicyMutex() UNIV_NOTHROW : m_impl()
{
#ifdef UNIV_PFS_MUTEX
m_ptr = 0;
#endif /* UNIV_PFS_MUTEX */
}
~PolicyMutex() { }
/** @return non-const version of the policy */
Policy& policy() UNIV_NOTHROW
{
return(m_impl.policy());
}
/** @return const version of the policy */
const Policy& policy() const UNIV_NOTHROW
{
return(m_impl.policy());
}
/** Release the mutex. */
void exit() UNIV_NOTHROW
{
#ifdef UNIV_PFS_MUTEX
pfs_exit();
#endif /* UNIV_PFS_MUTEX */
policy().release(m_impl);
m_impl.exit();
}
/** Acquire the mutex.
@param n_spins max number of spins
@param n_delay max delay per spin
@param name filename where locked
@param line line number where locked */
void enter(
uint32_t n_spins,
uint32_t n_delay,
const char* name,
uint32_t line) UNIV_NOTHROW
{
#ifdef UNIV_PFS_MUTEX
/* Note: locker is really an alias for state. That's why
it has to be in the same scope during pfs_end(). */
PSI_mutex_locker_state state;
PSI_mutex_locker* locker;
locker = pfs_begin_lock(&state, name, line);
#endif /* UNIV_PFS_MUTEX */
policy().enter(m_impl, name, line);
m_impl.enter(n_spins, n_delay, name, line);
policy().locked(m_impl, name, line);
#ifdef UNIV_PFS_MUTEX
pfs_end(locker, 0);
#endif /* UNIV_PFS_MUTEX */
}
/** Try and lock the mutex, return 0 on SUCCESS and 1 otherwise.
@param name filename where locked
@param line line number where locked */
int trylock(const char* name, uint32_t line) UNIV_NOTHROW
{
#ifdef UNIV_PFS_MUTEX
/* Note: locker is really an alias for state. That's why
it has to be in the same scope during pfs_end(). */
PSI_mutex_locker_state state;
PSI_mutex_locker* locker;
locker = pfs_begin_trylock(&state, name, line);
#endif /* UNIV_PFS_MUTEX */
/* There is a subtlety here, we check the mutex ordering
after locking here. This is only done to avoid add and
then remove if the trylock was unsuccesful. */
int ret = m_impl.try_lock() ? 0 : 1;
if (ret == 0) {
policy().enter(m_impl, name, line);
policy().locked(m_impl, name, line);
}
#ifdef UNIV_PFS_MUTEX
pfs_end(locker, 0);
#endif /* UNIV_PFS_MUTEX */
return(ret);
}
#ifdef UNIV_DEBUG
/** @return true if the thread owns the mutex. */
bool is_owned() const UNIV_NOTHROW
{
return(policy().is_owned());
}
#endif /* UNIV_DEBUG */
/**
Initialise the mutex.
@param[in] id Mutex ID
@param[in] filename file where created
@param[in] line line number in file where created */
void init(
latch_id_t id,
const char* filename,
uint32_t line)
UNIV_NOTHROW
{
#ifdef UNIV_PFS_MUTEX
pfs_add(sync_latch_get_pfs_key(id));
#endif /* UNIV_PFS_MUTEX */
m_impl.init(id, filename, line);
policy().init(m_impl, id, filename, line);
}
/** Free resources (if any) */
void destroy() UNIV_NOTHROW
{
#ifdef UNIV_PFS_MUTEX
pfs_del();
#endif /* UNIV_PFS_MUTEX */
m_impl.destroy();
policy().destroy();
}
/** Required for os_event_t */
operator sys_mutex_t*() UNIV_NOTHROW
{
return(m_impl.operator sys_mutex_t*());
}
#ifdef UNIV_PFS_MUTEX
/** Performance schema monitoring - register mutex with PFS.
Note: This is public only because we want to get around an issue
with registering a subset of buffer pool pages with PFS when
PFS_GROUP_BUFFER_SYNC is defined. Therefore this has to then
be called by external code (see buf0buf.cc).
@param key - Performance Schema key. */
void pfs_add(mysql_pfs_key_t key) UNIV_NOTHROW
{
ut_ad(m_ptr == 0);
m_ptr = PSI_MUTEX_CALL(init_mutex)(key, this);
}
private:
/** Performance schema monitoring.
@param state - PFS locker state
@param name - file name where locked
@param line - line number in file where locked */
PSI_mutex_locker* pfs_begin_lock(
PSI_mutex_locker_state* state,
const char* name,
uint32_t line) UNIV_NOTHROW
{
if (m_ptr != 0) {
return(PSI_MUTEX_CALL(start_mutex_wait)(
state, m_ptr,
PSI_MUTEX_LOCK, name, (uint) line));
}
return(0);
}
/** Performance schema monitoring.
@param state - PFS locker state
@param name - file name where locked
@param line - line number in file where locked */
PSI_mutex_locker* pfs_begin_trylock(
PSI_mutex_locker_state* state,
const char* name,
uint32_t line) UNIV_NOTHROW
{
if (m_ptr != 0) {
return(PSI_MUTEX_CALL(start_mutex_wait)(
state, m_ptr,
PSI_MUTEX_TRYLOCK, name, (uint) line));
}
return(0);
}
/** Performance schema monitoring
@param locker - PFS identifier
@param ret - 0 for success and 1 for failure */
void pfs_end(PSI_mutex_locker* locker, int ret) UNIV_NOTHROW
{
if (locker != 0) {
PSI_MUTEX_CALL(end_mutex_wait)(locker, ret);
}
}
/** Performance schema monitoring - register mutex release */
void pfs_exit()
{
if (m_ptr != 0) {
PSI_MUTEX_CALL(unlock_mutex)(m_ptr);
}
}
/** Performance schema monitoring - deregister */
void pfs_del()
{
if (m_ptr != 0) {
PSI_MUTEX_CALL(destroy_mutex)(m_ptr);
m_ptr = 0;
}
}
#endif /* UNIV_PFS_MUTEX */
private:
/** The mutex implementation */
MutexImpl m_impl;
#ifdef UNIV_PFS_MUTEX
/** The performance schema instrumentation hook. */
PSI_mutex* m_ptr;
#endif /* UNIV_PFS_MUTEX */
};
#endif /* ib0mutex_h */
#endif /* !UNIV_INNOCHECKSUM */