Internals: Add additional mutex exclusion checks. No functional change.
This commit is contained in:
parent
47dcbd4b8a
commit
8c3ad591ae
|
|
@ -241,12 +241,12 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// PUBLIC METHODS
|
// PUBLIC METHODS
|
||||||
void clear() VL_EXCLUDES(m_mutex) {
|
void clear() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
const VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
clearGuts();
|
clearGuts();
|
||||||
}
|
}
|
||||||
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
|
void clearNonMatch(const char* matchp) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
const VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
if (matchp && matchp[0]) {
|
if (matchp && matchp[0]) {
|
||||||
|
|
@ -261,25 +261,25 @@ public:
|
||||||
m_items = newlist;
|
m_items = newlist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void zero() VL_EXCLUDES(m_mutex) {
|
void zero() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
const VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
for (const auto& itemp : m_items) itemp->zero();
|
for (const auto& itemp : m_items) itemp->zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
// We assume there's always call to i/f/p in that order
|
// We assume there's always call to i/f/p in that order
|
||||||
void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
|
void inserti(VerilatedCovImpItem* itemp) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
const VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
assert(!m_insertp);
|
assert(!m_insertp);
|
||||||
m_insertp = itemp;
|
m_insertp = itemp;
|
||||||
}
|
}
|
||||||
void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
|
void insertf(const char* filenamep, int lineno) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
const VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
m_insertFilenamep = filenamep;
|
m_insertFilenamep = filenamep;
|
||||||
m_insertLineno = lineno;
|
m_insertLineno = lineno;
|
||||||
}
|
}
|
||||||
void insertp(const char* ckeyps[VerilatedCovConst::MAX_KEYS],
|
void insertp(const char* ckeyps[VerilatedCovConst::MAX_KEYS],
|
||||||
const char* valps[VerilatedCovConst::MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
const char* valps[VerilatedCovConst::MAX_KEYS]) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
const VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
assert(m_insertp);
|
assert(m_insertp);
|
||||||
// First two key/vals are filename
|
// First two key/vals are filename
|
||||||
|
|
@ -336,7 +336,7 @@ public:
|
||||||
m_insertp = nullptr;
|
m_insertp = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
void write(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
const VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
#ifndef VM_COVERAGE
|
#ifndef VM_COVERAGE
|
||||||
|
|
|
||||||
|
|
@ -99,13 +99,13 @@ private:
|
||||||
public:
|
public:
|
||||||
// METHODS
|
// METHODS
|
||||||
//// Add message to queue (called by producer)
|
//// Add message to queue (called by producer)
|
||||||
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
|
void post(const VerilatedMsg& msg) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
const VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
m_queue.insert(msg); // Pass by value to copy the message into queue
|
m_queue.insert(msg); // Pass by value to copy the message into queue
|
||||||
++m_depth;
|
++m_depth;
|
||||||
}
|
}
|
||||||
/// Service queue until completion (called by consumer)
|
/// Service queue until completion (called by consumer)
|
||||||
void process() VL_EXCLUDES(m_mutex) {
|
void process() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
// Tracking m_depth is redundant to e.g. getting the mutex and looking at queue size,
|
// Tracking m_depth is redundant to e.g. getting the mutex and looking at queue size,
|
||||||
// but on the reader side it's 4x faster to test an atomic then getting a mutex
|
// but on the reader side it's 4x faster to test an atomic then getting a mutex
|
||||||
while (m_depth) {
|
while (m_depth) {
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ void VlThreadPool::tearDownProfilingClientThread() {
|
||||||
t_profilep = nullptr;
|
t_profilep = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlThreadPool::setupProfilingClientThread() {
|
void VlThreadPool::setupProfilingClientThread() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
assert(!t_profilep);
|
assert(!t_profilep);
|
||||||
t_profilep = new ProfileTrace;
|
t_profilep = new ProfileTrace;
|
||||||
// Reserve some space in the thread-local profiling buffer;
|
// Reserve some space in the thread-local profiling buffer;
|
||||||
|
|
@ -126,7 +126,7 @@ void VlThreadPool::setupProfilingClientThread() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlThreadPool::profileAppendAll(const VlProfileRec& rec) {
|
void VlThreadPool::profileAppendAll(const VlProfileRec& rec) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
const VerilatedLockGuard lk(m_mutex);
|
const VerilatedLockGuard lk(m_mutex);
|
||||||
for (const auto& profilep : m_allProfiles) {
|
for (const auto& profilep : m_allProfiles) {
|
||||||
// Every thread's profile trace gets a copy of rec.
|
// Every thread's profile trace gets a copy of rec.
|
||||||
|
|
@ -134,7 +134,8 @@ void VlThreadPool::profileAppendAll(const VlProfileRec& rec) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
|
void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed)
|
||||||
|
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
const VerilatedLockGuard lk(m_mutex);
|
const VerilatedLockGuard lk(m_mutex);
|
||||||
VL_DEBUG_IF(VL_DBG_MSGF("+prof+threads writing to '%s'\n", filenamep););
|
VL_DEBUG_IF(VL_DBG_MSGF("+prof+threads writing to '%s'\n", filenamep););
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ public:
|
||||||
~VlWorkerThread();
|
~VlWorkerThread();
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
inline void dequeWork(ExecRec* workp) {
|
inline void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
// Spin for a while, waiting for new data
|
// Spin for a while, waiting for new data
|
||||||
for (int i = 0; i < VL_LOCK_SPINS; ++i) {
|
for (int i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||||
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) { //
|
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) { //
|
||||||
|
|
@ -233,7 +233,8 @@ public:
|
||||||
m_ready_size.fetch_sub(1, std::memory_order_relaxed);
|
m_ready_size.fetch_sub(1, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
inline void wakeUp() { addTask(nullptr, false, nullptr); }
|
inline void wakeUp() { addTask(nullptr, false, nullptr); }
|
||||||
inline void addTask(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym) {
|
inline void addTask(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym)
|
||||||
|
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
bool notify;
|
bool notify;
|
||||||
{
|
{
|
||||||
const VerilatedLockGuard lk(m_mutex);
|
const VerilatedLockGuard lk(m_mutex);
|
||||||
|
|
@ -286,11 +287,11 @@ public:
|
||||||
t_profilep->emplace_back();
|
t_profilep->emplace_back();
|
||||||
return &(t_profilep->back());
|
return &(t_profilep->back());
|
||||||
}
|
}
|
||||||
void profileAppendAll(const VlProfileRec& rec);
|
void profileAppendAll(const VlProfileRec& rec) VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||||
void profileDump(const char* filenamep, vluint64_t ticksElapsed);
|
void profileDump(const char* filenamep, vluint64_t ticksElapsed) VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||||
// In profiling mode, each executing thread must call
|
// In profiling mode, each executing thread must call
|
||||||
// this once to setup profiling state:
|
// this once to setup profiling state:
|
||||||
void setupProfilingClientThread();
|
void setupProfilingClientThread() VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||||
void tearDownProfilingClientThread();
|
void tearDownProfilingClientThread();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -48,21 +48,21 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Put an element at the back of the queue
|
// Put an element at the back of the queue
|
||||||
void put(T value) {
|
void put(T value) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
m_queue.push_back(value);
|
m_queue.push_back(value);
|
||||||
m_cv.notify_one();
|
m_cv.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put an element at the front of the queue
|
// Put an element at the front of the queue
|
||||||
void put_front(T value) {
|
void put_front(T value) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
m_queue.push_front(value);
|
m_queue.push_front(value);
|
||||||
m_cv.notify_one();
|
m_cv.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get an element from the front of the queue. Blocks if none available
|
// Get an element from the front of the queue. Blocks if none available
|
||||||
T get() {
|
T get() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock(m_mutex);
|
VerilatedLockGuard lock(m_mutex);
|
||||||
m_cv.wait(lock, [this]() VL_REQUIRES(m_mutex) { return !m_queue.empty(); });
|
m_cv.wait(lock, [this]() VL_REQUIRES(m_mutex) { return !m_queue.empty(); });
|
||||||
assert(!m_queue.empty());
|
assert(!m_queue.empty());
|
||||||
|
|
@ -72,7 +72,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non blocking get
|
// Non blocking get
|
||||||
bool tryGet(T& result) {
|
bool tryGet(T& result) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
const VerilatedLockGuard lockGuard(m_mutex);
|
const VerilatedLockGuard lockGuard(m_mutex);
|
||||||
if (m_queue.empty()) return false;
|
if (m_queue.empty()) return false;
|
||||||
result = m_queue.front();
|
result = m_queue.front();
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,7 @@
|
||||||
#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED
|
#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED
|
||||||
#define VL_MT_SAFE_POSTINIT ///< Comment tag that function is threadsafe when VL_THREADED, only
|
#define VL_MT_SAFE_POSTINIT ///< Comment tag that function is threadsafe when VL_THREADED, only
|
||||||
///< during normal operation (post-init)
|
///< during normal operation (post-init)
|
||||||
|
#define VL_MT_SAFE_EXCLUDES(mutex) VL_EXCLUDES(mutex) ///< Threadsafe and uses given mutex
|
||||||
#define VL_MT_UNSAFE ///< Comment tag that function is not threadsafe when VL_THREADED
|
#define VL_MT_UNSAFE ///< Comment tag that function is not threadsafe when VL_THREADED
|
||||||
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED,
|
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED,
|
||||||
///< protected to make sure single-caller
|
///< protected to make sure single-caller
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue