mirror of
https://github.com/MariaDB/server.git
synced 2025-01-31 02:51:44 +01:00
296 lines
7.3 KiB
C++
296 lines
7.3 KiB
C++
/*****************************************************************************
|
|
|
|
Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
|
Copyright (c) 2017, 2018, MariaDB Corporation.
|
|
|
|
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, Fifth Floor, Boston, MA 02110-1335 USA
|
|
|
|
*****************************************************************************/
|
|
|
|
/******************************************************************//**
|
|
@file include/sync0policy.h
|
|
Policies for mutexes.
|
|
|
|
Created 2012-08-21 Sunny Bains.
|
|
***********************************************************************/
|
|
|
|
#ifndef sync0policy_h
|
|
#define sync0policy_h
|
|
|
|
#include "ut0rnd.h"
|
|
#include "os0thread.h"
|
|
#include "srv0mon.h"
|
|
#include "sync0debug.h"
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
template <typename Mutex> class MutexDebug: public latch_t
|
|
{
|
|
/** Mutex to check for lock order violation */
|
|
const Mutex *m_mutex;
|
|
/** Filename from where enter was called */
|
|
const char *m_filename;
|
|
/** Line mumber in filename */
|
|
unsigned m_line;
|
|
/** Thread ID of the thread that owns the mutex */
|
|
os_thread_id_t m_thread_id;
|
|
/** Mutex protecting the above members */
|
|
mutable OSMutex m_debug_mutex;
|
|
|
|
|
|
void set(const Mutex *mutex, const char *filename, unsigned line,
|
|
os_thread_id_t thread_id)
|
|
{
|
|
m_debug_mutex.enter();
|
|
m_mutex= mutex;
|
|
m_filename= filename;
|
|
m_line= line;
|
|
m_thread_id= thread_id;
|
|
m_debug_mutex.exit();
|
|
}
|
|
|
|
|
|
const MutexDebug get() const
|
|
{
|
|
MutexDebug ret;
|
|
m_debug_mutex.enter();
|
|
ret.m_mutex= m_mutex;
|
|
ret.m_filename= m_filename;
|
|
ret.m_line= m_line;
|
|
ret.m_thread_id= m_thread_id;
|
|
m_debug_mutex.exit();
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
Called either when mutex is locked or destroyed. Thus members are protected
|
|
from concurrent modification.
|
|
*/
|
|
void assert_clean_context()
|
|
{
|
|
ut_ad(!m_mutex);
|
|
ut_ad(!m_filename);
|
|
ut_ad(!m_line);
|
|
ut_ad(m_thread_id == os_thread_id_t(ULINT_UNDEFINED));
|
|
}
|
|
|
|
|
|
public:
|
|
/**
|
|
Called when the mutex is "created". Note: Not from the constructor
|
|
but when the mutex is initialised.
|
|
@param[in] id Mutex ID
|
|
*/
|
|
void init(latch_id_t id)
|
|
{
|
|
ut_ad(id != LATCH_ID_NONE);
|
|
m_id= id;
|
|
m_debug_mutex.init();
|
|
set(0, 0, 0, os_thread_id_t(ULINT_UNDEFINED));
|
|
}
|
|
|
|
|
|
/** Mutex is being destroyed. */
|
|
void destroy()
|
|
{
|
|
assert_clean_context();
|
|
m_debug_mutex.destroy();
|
|
}
|
|
|
|
|
|
/**
|
|
Called when an attempt is made to lock the mutex
|
|
@param[in] mutex Mutex instance to be locked
|
|
@param[in] filename Filename from where it was called
|
|
@param[in] line Line number from where it was called
|
|
*/
|
|
void enter(const Mutex &mutex, const char *filename, unsigned line)
|
|
{
|
|
MutexDebug context;
|
|
ut_ad(!is_owned());
|
|
context.init(m_id);
|
|
context.set(&mutex, filename, line, os_thread_get_curr_id());
|
|
/* Check for latch order violation. */
|
|
sync_check_lock_validate(&context);
|
|
context.set(0, 0, 0, os_thread_id_t(ULINT_UNDEFINED));
|
|
context.destroy();
|
|
}
|
|
|
|
|
|
/**
|
|
Called when the mutex is locked
|
|
@param[in] mutex Mutex instance that was locked
|
|
@param[in] filename Filename from where it was called
|
|
@param[in] line Line number from where it was called
|
|
*/
|
|
void locked(const Mutex &mutex, const char *filename, unsigned line)
|
|
{
|
|
assert_clean_context();
|
|
set(&mutex, filename, line, os_thread_get_curr_id());
|
|
sync_check_lock_granted(this);
|
|
}
|
|
|
|
|
|
/**
|
|
Called when the mutex is released
|
|
@param[in] mutex Mutex that was released
|
|
*/
|
|
void release(const Mutex &mutex)
|
|
{
|
|
ut_ad(is_owned());
|
|
set(0, 0, 0, os_thread_id_t(ULINT_UNDEFINED));
|
|
sync_check_unlock(this);
|
|
}
|
|
|
|
|
|
/** @return true if thread owns the mutex */
|
|
bool is_owned() const
|
|
{
|
|
return os_thread_eq(get_thread_id(), os_thread_get_curr_id());
|
|
}
|
|
|
|
|
|
/** @return the name of the file from the mutex was acquired */
|
|
const char* get_enter_filename() const { return get().m_filename; }
|
|
|
|
|
|
/** @return the name of the file from the mutex was acquired */
|
|
unsigned get_enter_line() const { return get().m_line; }
|
|
|
|
|
|
/** @return id of the thread that was trying to acquire the mutex */
|
|
os_thread_id_t get_thread_id() const { return get().m_thread_id; }
|
|
|
|
|
|
/**
|
|
Print information about the latch
|
|
@return the string representation
|
|
*/
|
|
virtual std::string to_string() const
|
|
{
|
|
std::ostringstream msg;
|
|
const MutexDebug ctx= get();
|
|
|
|
msg << m_mutex->policy().to_string();
|
|
if (ctx.m_mutex)
|
|
msg << " addr: " << ctx.m_mutex << " acquired: "
|
|
<< sync_basename(ctx.get_enter_filename()) << ":"
|
|
<< ctx.get_enter_line();
|
|
else
|
|
msg << "Not locked";
|
|
|
|
return(msg.str());
|
|
}
|
|
};
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
/** Collect the metrics per mutex instance, no aggregation. */
|
|
template <typename Mutex>
|
|
struct GenericPolicy
|
|
{
|
|
public:
|
|
/** 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(
|
|
const Mutex&,
|
|
latch_id_t id,
|
|
const char* filename,
|
|
uint32_t line)
|
|
UNIV_NOTHROW
|
|
{
|
|
m_id = id;
|
|
|
|
latch_meta_t& meta = sync_latch_get_meta(id);
|
|
|
|
ut_ad(meta.get_id() == id);
|
|
|
|
meta.get_counter()->single_register(&m_count);
|
|
|
|
m_filename = filename;
|
|
m_line = line;
|
|
}
|
|
|
|
/** Called when the mutex is destroyed. */
|
|
void destroy()
|
|
UNIV_NOTHROW
|
|
{
|
|
latch_meta_t& meta = sync_latch_get_meta(m_id);
|
|
|
|
meta.get_counter()->single_deregister(&m_count);
|
|
}
|
|
|
|
/** Called after a successful mutex acquire.
|
|
@param[in] n_spins Number of times the thread did
|
|
spins while trying to acquire the mutex
|
|
@param[in] n_waits Number of times the thread waited
|
|
in some type of OS queue */
|
|
void add(
|
|
uint32_t n_spins,
|
|
uint32_t n_waits)
|
|
UNIV_NOTHROW
|
|
{
|
|
/* Currently global on/off. Keeps things simple and fast */
|
|
|
|
if (!m_count.m_enabled) {
|
|
|
|
return;
|
|
}
|
|
|
|
m_count.m_spins += n_spins;
|
|
m_count.m_waits += n_waits;
|
|
|
|
++m_count.m_calls;
|
|
}
|
|
|
|
/** Print the information about the latch
|
|
@return the string representation */
|
|
std::string print() const
|
|
UNIV_NOTHROW;
|
|
|
|
/** @return the latch ID */
|
|
latch_id_t get_id() const
|
|
UNIV_NOTHROW
|
|
{
|
|
return(m_id);
|
|
}
|
|
|
|
|
|
/** @return the string representation */
|
|
std::string to_string() const
|
|
{
|
|
return sync_mutex_to_string(get_id(),
|
|
std::string(m_filename)
|
|
.append(":")
|
|
.append(std::to_string(m_line)));
|
|
}
|
|
|
|
#ifdef UNIV_DEBUG
|
|
MutexDebug<Mutex> context;
|
|
#endif
|
|
|
|
private:
|
|
const char *m_filename;
|
|
uint32_t m_line;
|
|
|
|
/** The user visible counters, registered with the meta-data. */
|
|
latch_meta_t::CounterType::Count m_count;
|
|
|
|
/** Latch meta data ID */
|
|
latch_id_t m_id;
|
|
};
|
|
|
|
#endif /* sync0policy_h */
|