Internals: Split Mutex class used in verilated code and verilator (#4048)
This commit is contained in:
parent
0307d59c1f
commit
b6dcec2710
|
|
@ -30,6 +30,13 @@
|
||||||
#ifndef VERILATOR_VERILATED_H_
|
#ifndef VERILATOR_VERILATED_H_
|
||||||
#define VERILATOR_VERILATED_H_
|
#define VERILATOR_VERILATED_H_
|
||||||
#define VERILATOR_VERILATED_H_INTERNAL_
|
#define VERILATOR_VERILATED_H_INTERNAL_
|
||||||
|
#ifdef VERILATOR_INTERNAL_
|
||||||
|
// This file contains definition of VerilationMutex that should
|
||||||
|
// only be used by verilated code. Verilator itself should use
|
||||||
|
// mutex from V3Mutex.h. Make sure this file isn't included in
|
||||||
|
// verilator code.
|
||||||
|
#error "verilated.h should only be included in verilated code"
|
||||||
|
#endif
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#include "verilatedos.h"
|
#include "verilatedos.h"
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,7 @@ endif
|
||||||
# -lfl not needed as Flex invoked with %nowrap option
|
# -lfl not needed as Flex invoked with %nowrap option
|
||||||
LIBS = $(CFG_LIBS) -lm
|
LIBS = $(CFG_LIBS) -lm
|
||||||
|
|
||||||
|
CPPFLAGS += -DVERILATOR_INTERNAL_
|
||||||
CPPFLAGS += -MMD
|
CPPFLAGS += -MMD
|
||||||
CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include
|
CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include
|
||||||
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ template <typename T>
|
||||||
class V3ConfigWildcardResolver final {
|
class V3ConfigWildcardResolver final {
|
||||||
using Map = std::map<const std::string, T>;
|
using Map = std::map<const std::string, T>;
|
||||||
|
|
||||||
mutable VerilatedMutex m_mutex; // protects members
|
mutable V3Mutex m_mutex; // protects members
|
||||||
Map m_mapWildcard VL_GUARDED_BY(m_mutex); // Wildcard strings to entities
|
Map m_mapWildcard VL_GUARDED_BY(m_mutex); // Wildcard strings to entities
|
||||||
Map m_mapResolved VL_GUARDED_BY(m_mutex); // Resolved strings to converged entities
|
Map m_mapResolved VL_GUARDED_BY(m_mutex); // Resolved strings to converged entities
|
||||||
public:
|
public:
|
||||||
|
|
@ -50,21 +50,21 @@ public:
|
||||||
/// Update into maps from other
|
/// Update into maps from other
|
||||||
void update(const V3ConfigWildcardResolver& other) VL_MT_SAFE_EXCLUDES(m_mutex)
|
void update(const V3ConfigWildcardResolver& other) VL_MT_SAFE_EXCLUDES(m_mutex)
|
||||||
VL_EXCLUDES(other.m_mutex) {
|
VL_EXCLUDES(other.m_mutex) {
|
||||||
VerilatedLockGuard lock{m_mutex};
|
V3LockGuard lock{m_mutex};
|
||||||
VerilatedLockGuard otherLock{other.m_mutex};
|
V3LockGuard otherLock{other.m_mutex};
|
||||||
for (const auto& itr : other.m_mapResolved) m_mapResolved[itr.first].update(itr.second);
|
for (const auto& itr : other.m_mapResolved) m_mapResolved[itr.first].update(itr.second);
|
||||||
for (const auto& itr : other.m_mapWildcard) m_mapWildcard[itr.first].update(itr.second);
|
for (const auto& itr : other.m_mapWildcard) m_mapWildcard[itr.first].update(itr.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access and create a (wildcard) entity
|
// Access and create a (wildcard) entity
|
||||||
T& at(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
T& at(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock{m_mutex};
|
V3LockGuard lock{m_mutex};
|
||||||
// Don't store into wildcards if the name is not a wildcard string
|
// Don't store into wildcards if the name is not a wildcard string
|
||||||
return m_mapWildcard[name];
|
return m_mapWildcard[name];
|
||||||
}
|
}
|
||||||
// Access an entity and resolve wildcards that match it
|
// Access an entity and resolve wildcards that match it
|
||||||
T* resolve(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
T* resolve(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock{m_mutex};
|
V3LockGuard lock{m_mutex};
|
||||||
// Lookup if it was resolved before, typically not
|
// Lookup if it was resolved before, typically not
|
||||||
auto it = m_mapResolved.find(name);
|
auto it = m_mapResolved.find(name);
|
||||||
if (VL_UNLIKELY(it != m_mapResolved.end())) return &it->second;
|
if (VL_UNLIKELY(it != m_mapResolved.end())) return &it->second;
|
||||||
|
|
@ -85,7 +85,7 @@ public:
|
||||||
}
|
}
|
||||||
// Flush on update
|
// Flush on update
|
||||||
void flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
void flush() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock{m_mutex};
|
V3LockGuard lock{m_mutex};
|
||||||
m_mapResolved.clear();
|
m_mapResolved.clear();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
#include "V3Error.h"
|
#include "V3Error.h"
|
||||||
#include "V3FileLine.h"
|
#include "V3FileLine.h"
|
||||||
|
#include "V3Mutex.h"
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
#include "config_build.h"
|
#include "config_build.h"
|
||||||
#include "verilatedos.h"
|
#include "verilatedos.h"
|
||||||
|
|
||||||
#include "verilated_threads.h"
|
#include "V3Mutex.h"
|
||||||
|
|
||||||
// Limited V3 headers here - this is a base class for Vlc etc
|
// Limited V3 headers here - this is a base class for Vlc etc
|
||||||
#include "V3String.h"
|
#include "V3String.h"
|
||||||
|
|
@ -315,7 +315,7 @@ private:
|
||||||
bool m_warnFatal VL_GUARDED_BY(m_mutex) = true; // Option: --warnFatal Warnings are fatal
|
bool m_warnFatal VL_GUARDED_BY(m_mutex) = true; // Option: --warnFatal Warnings are fatal
|
||||||
std::ostringstream m_errorStr VL_GUARDED_BY(m_mutex); // Error string being formed
|
std::ostringstream m_errorStr VL_GUARDED_BY(m_mutex); // Error string being formed
|
||||||
public:
|
public:
|
||||||
VerilatedMutex m_mutex; // Make sure only single thread is in class
|
V3RecursiveMutex m_mutex; // Make sure only single thread is in class
|
||||||
|
|
||||||
string msgPrefix() VL_REQUIRES(m_mutex); // returns %Error/%Warn
|
string msgPrefix() VL_REQUIRES(m_mutex); // returns %Error/%Warn
|
||||||
string warnMore() VL_REQUIRES(m_mutex);
|
string warnMore() VL_REQUIRES(m_mutex);
|
||||||
|
|
@ -408,57 +408,57 @@ public:
|
||||||
static void debugDefault(int level) VL_MT_UNSAFE { s().debugDefault(level); }
|
static void debugDefault(int level) VL_MT_UNSAFE { s().debugDefault(level); }
|
||||||
static int debugDefault() VL_MT_SAFE { return s().debugDefault(); }
|
static int debugDefault() VL_MT_SAFE { return s().debugDefault(); }
|
||||||
static void errorLimit(int level) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static void errorLimit(int level) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
s().errorLimit(level);
|
s().errorLimit(level);
|
||||||
}
|
}
|
||||||
static int errorLimit() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static int errorLimit() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
return s().errorLimit();
|
return s().errorLimit();
|
||||||
}
|
}
|
||||||
static void warnFatal(bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static void warnFatal(bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
s().warnFatal(flag);
|
s().warnFatal(flag);
|
||||||
}
|
}
|
||||||
static bool warnFatal() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static bool warnFatal() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
return s().warnFatal();
|
return s().warnFatal();
|
||||||
}
|
}
|
||||||
// returns %Error/%Warn
|
// returns %Error/%Warn
|
||||||
static string msgPrefix() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static string msgPrefix() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
return s().msgPrefix();
|
return s().msgPrefix();
|
||||||
}
|
}
|
||||||
static int errorCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static int errorCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
return s().errorCount();
|
return s().errorCount();
|
||||||
}
|
}
|
||||||
static bool pretendError(int errorCode) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static bool pretendError(int errorCode) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
return s().pretendError(errorCode);
|
return s().pretendError(errorCode);
|
||||||
}
|
}
|
||||||
static int warnCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static int warnCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
return s().warnCount();
|
return s().warnCount();
|
||||||
}
|
}
|
||||||
static bool errorContexted() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static bool errorContexted() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
return s().errorContexted();
|
return s().errorContexted();
|
||||||
}
|
}
|
||||||
static void errorContexted(bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static void errorContexted(bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
s().errorContexted(flag);
|
s().errorContexted(flag);
|
||||||
}
|
}
|
||||||
static void describedEachWarn(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static void describedEachWarn(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
s().describedEachWarn(code, flag);
|
s().describedEachWarn(code, flag);
|
||||||
}
|
}
|
||||||
// METHODS
|
// METHODS
|
||||||
static void incErrors() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static void incErrors() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
s().incErrors();
|
s().incErrors();
|
||||||
}
|
}
|
||||||
static void incWarnings() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static void incWarnings() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
s().incWarnings();
|
s().incWarnings();
|
||||||
}
|
}
|
||||||
static void init();
|
static void init();
|
||||||
|
|
@ -468,20 +468,20 @@ public:
|
||||||
static void abortIfWarnings();
|
static void abortIfWarnings();
|
||||||
// Suppress next %Warn if user has it off
|
// Suppress next %Warn if user has it off
|
||||||
static void suppressThisWarning() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static void suppressThisWarning() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
s().suppressThisWarning();
|
s().suppressThisWarning();
|
||||||
}
|
}
|
||||||
static void pretendError(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static void pretendError(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
s().pretendError(code, flag);
|
s().pretendError(code, flag);
|
||||||
}
|
}
|
||||||
static string lineStr(const char* filename, int lineno) VL_PURE;
|
static string lineStr(const char* filename, int lineno) VL_PURE;
|
||||||
static V3ErrorCode errorCode() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static V3ErrorCode errorCode() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
return s().errorCode();
|
return s().errorCode();
|
||||||
}
|
}
|
||||||
static void errorExitCb(V3ErrorGuarded::ErrorExitCb cb) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static void errorExitCb(V3ErrorGuarded::ErrorExitCb cb) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
s().errorExitCb(cb);
|
s().errorExitCb(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -492,7 +492,7 @@ public:
|
||||||
// streamed directly to cerr.
|
// streamed directly to cerr.
|
||||||
// Use with caution as this function isn't MT_SAFE.
|
// Use with caution as this function isn't MT_SAFE.
|
||||||
static string warnMoreStandalone() VL_EXCLUDES(s().m_mutex) VL_MT_UNSAFE {
|
static string warnMoreStandalone() VL_EXCLUDES(s().m_mutex) VL_MT_UNSAFE {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
return s().warnMore();
|
return s().warnMore();
|
||||||
}
|
}
|
||||||
// This function marks place in error message from which point message
|
// This function marks place in error message from which point message
|
||||||
|
|
@ -508,18 +508,18 @@ public:
|
||||||
// Internals for v3error()/v3fatal() macros only
|
// Internals for v3error()/v3fatal() macros only
|
||||||
// Error end takes the string stream to output, be careful to seek() as needed
|
// Error end takes the string stream to output, be careful to seek() as needed
|
||||||
static void v3errorPrep(V3ErrorCode code) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static void v3errorPrep(V3ErrorCode code) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
s().v3errorPrep(code);
|
s().v3errorPrep(code);
|
||||||
}
|
}
|
||||||
static std::ostringstream& v3errorStr() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
static std::ostringstream& v3errorStr() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
return s().v3errorStr();
|
return s().v3errorStr();
|
||||||
}
|
}
|
||||||
static void vlAbort();
|
static void vlAbort();
|
||||||
// static, but often overridden in classes.
|
// static, but often overridden in classes.
|
||||||
static void v3errorEnd(std::ostringstream& sstr, const string& extra = "")
|
static void v3errorEnd(std::ostringstream& sstr, const string& extra = "")
|
||||||
VL_MT_SAFE_EXCLUDES(s().m_mutex) VL_MT_SAFE {
|
VL_MT_SAFE_EXCLUDES(s().m_mutex) VL_MT_SAFE {
|
||||||
const VerilatedLockGuard guard{s().m_mutex};
|
const V3RecursiveLockGuard guard{s().m_mutex};
|
||||||
s().v3errorEnd(sstr, extra);
|
s().v3errorEnd(sstr, extra);
|
||||||
}
|
}
|
||||||
// We can't call 's().v3errorEnd' directly in 'v3ErrorEnd'/'v3errorEndFatal',
|
// We can't call 's().v3errorEnd' directly in 'v3ErrorEnd'/'v3errorEndFatal',
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ class V3FileDependImp final {
|
||||||
};
|
};
|
||||||
|
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
VerilatedMutex m_mutex; // Protects members
|
V3Mutex m_mutex; // Protects members
|
||||||
std::set<string> m_filenameSet VL_GUARDED_BY(m_mutex); // Files generated (elim duplicates)
|
std::set<string> m_filenameSet VL_GUARDED_BY(m_mutex); // Files generated (elim duplicates)
|
||||||
std::set<DependFile> m_filenameList; // Files sourced/generated
|
std::set<DependFile> m_filenameList; // Files sourced/generated
|
||||||
|
|
||||||
|
|
@ -123,7 +123,7 @@ class V3FileDependImp final {
|
||||||
public:
|
public:
|
||||||
// ACCESSOR METHODS
|
// ACCESSOR METHODS
|
||||||
void addSrcDepend(const string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
void addSrcDepend(const string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
const V3LockGuard lock{m_mutex};
|
||||||
const auto itFoundPair = m_filenameSet.insert(filename);
|
const auto itFoundPair = m_filenameSet.insert(filename);
|
||||||
if (itFoundPair.second) {
|
if (itFoundPair.second) {
|
||||||
DependFile df{filename, false};
|
DependFile df{filename, false};
|
||||||
|
|
@ -132,7 +132,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void addTgtDepend(const string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
void addTgtDepend(const string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
const V3LockGuard lock{m_mutex};
|
||||||
const auto itFoundPair = m_filenameSet.insert(filename);
|
const auto itFoundPair = m_filenameSet.insert(filename);
|
||||||
if (itFoundPair.second) m_filenameList.insert(DependFile{filename, true});
|
if (itFoundPair.second) m_filenameList.insert(DependFile{filename, true});
|
||||||
}
|
}
|
||||||
|
|
@ -957,7 +957,7 @@ void V3OutCFile::putsGuard() {
|
||||||
|
|
||||||
class VIdProtectImp final {
|
class VIdProtectImp final {
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
VerilatedMutex m_mutex; // Protects members
|
V3Mutex m_mutex; // Protects members
|
||||||
std::map<const std::string, std::string> m_nameMap; // Map of old name into new name
|
std::map<const std::string, std::string> m_nameMap; // Map of old name into new name
|
||||||
std::unordered_set<std::string> m_newIdSet VL_GUARDED_BY(m_mutex); // Which new names exist
|
std::unordered_set<std::string> m_newIdSet VL_GUARDED_BY(m_mutex); // Which new names exist
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -979,7 +979,7 @@ public:
|
||||||
// METHODS
|
// METHODS
|
||||||
string passthru(const string& old) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
string passthru(const string& old) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
if (!v3Global.opt.protectIds()) return old;
|
if (!v3Global.opt.protectIds()) return old;
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
const V3LockGuard lock{m_mutex};
|
||||||
const auto it = m_nameMap.find(old);
|
const auto it = m_nameMap.find(old);
|
||||||
if (it != m_nameMap.end()) {
|
if (it != m_nameMap.end()) {
|
||||||
// No way to go back and correct the older crypt name
|
// No way to go back and correct the older crypt name
|
||||||
|
|
@ -993,7 +993,7 @@ public:
|
||||||
}
|
}
|
||||||
string protectIf(const string& old, bool doIt) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
string protectIf(const string& old, bool doIt) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
if (!v3Global.opt.protectIds() || old.empty() || !doIt) return old;
|
if (!v3Global.opt.protectIds() || old.empty() || !doIt) return old;
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
const V3LockGuard lock{m_mutex};
|
||||||
const auto it = m_nameMap.find(old);
|
const auto it = m_nameMap.find(old);
|
||||||
if (it != m_nameMap.end()) {
|
if (it != m_nameMap.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ void FileLineSingleton::fileNameNumMapDumpXml(std::ostream& os) {
|
||||||
|
|
||||||
FileLineSingleton::msgEnSetIdx_t FileLineSingleton::addMsgEnBitSet(const MsgEnBitSet& bitSet)
|
FileLineSingleton::msgEnSetIdx_t FileLineSingleton::addMsgEnBitSet(const MsgEnBitSet& bitSet)
|
||||||
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
VerilatedLockGuard lock{m_mutex};
|
V3LockGuard lock{m_mutex};
|
||||||
const auto pair = m_internedMsgEnIdxs.emplace(bitSet, 0);
|
const auto pair = m_internedMsgEnIdxs.emplace(bitSet, 0);
|
||||||
msgEnSetIdx_t& idx = pair.first->second;
|
msgEnSetIdx_t& idx = pair.first->second;
|
||||||
if (pair.second) {
|
if (pair.second) {
|
||||||
|
|
@ -418,7 +418,7 @@ string FileLine::warnOther() const VL_REQUIRES(V3Error::s().m_mutex) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
string FileLine::warnOtherStandalone() const VL_EXCLUDES(V3Error::s().m_mutex) VL_MT_UNSAFE {
|
string FileLine::warnOtherStandalone() const VL_EXCLUDES(V3Error::s().m_mutex) VL_MT_UNSAFE {
|
||||||
const VerilatedLockGuard guard{V3Error::s().m_mutex};
|
const V3RecursiveLockGuard guard{V3Error::s().m_mutex};
|
||||||
return warnOther();
|
return warnOther();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,9 @@
|
||||||
#include "config_build.h"
|
#include "config_build.h"
|
||||||
#include "verilatedos.h"
|
#include "verilatedos.h"
|
||||||
|
|
||||||
#include "verilated_threads.h"
|
|
||||||
|
|
||||||
#include "V3Error.h"
|
#include "V3Error.h"
|
||||||
#include "V3LangCode.h"
|
#include "V3LangCode.h"
|
||||||
|
#include "V3Mutex.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
|
@ -52,7 +51,7 @@ class FileLineSingleton final {
|
||||||
using MsgEnBitSet = std::bitset<V3ErrorCode::_ENUM_MAX>;
|
using MsgEnBitSet = std::bitset<V3ErrorCode::_ENUM_MAX>;
|
||||||
|
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
VerilatedMutex m_mutex; // protects members
|
V3Mutex m_mutex; // protects members
|
||||||
std::map<const std::string, fileNameIdx_t> m_namemap; // filenameno for each filename
|
std::map<const std::string, fileNameIdx_t> m_namemap; // filenameno for each filename
|
||||||
std::deque<string> m_names; // filename text for each filenameno
|
std::deque<string> m_names; // filename text for each filenameno
|
||||||
std::deque<V3LangCode> m_languages; // language for each filenameno
|
std::deque<V3LangCode> m_languages; // language for each filenameno
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//*************************************************************************
|
||||||
|
// DESCRIPTION: Verilator: Thread pool for Verilator itself
|
||||||
|
//
|
||||||
|
// Code available from: https://verilator.org
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2005-2023 by Wilson Snyder. This program is free software; you can
|
||||||
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
// Version 2.0.
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Verilator Mutex and LockGuard used only in verilator.
|
||||||
|
///
|
||||||
|
/// This file defines Mutex and LockGuard that is used in verilator
|
||||||
|
/// source code. It shouldn't be used by verilated code.
|
||||||
|
/// In contrast to VerilatedMutex that is used by verilated code,
|
||||||
|
/// this mutex can be configured and disabled when verilation is using
|
||||||
|
/// single thread.
|
||||||
|
///
|
||||||
|
/// This implementation also allows using different base mutex class in
|
||||||
|
/// wrapper V3Mutex class.
|
||||||
|
///
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#ifndef VERILATOR_V3MUTEX_H_
|
||||||
|
#define VERILATOR_V3MUTEX_H_ 1
|
||||||
|
|
||||||
|
#include "verilatedos.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before yielding
|
||||||
|
|
||||||
|
// MutexConfig class that allows to configure how mutex and lockgurads behave
|
||||||
|
// once configured and locked, it cannot be changed. Configuration and lock needs to be
|
||||||
|
// done before starting any additional threads.
|
||||||
|
class V3MutexConfig final {
|
||||||
|
private:
|
||||||
|
// Allows to disable mutexes and lockguards.
|
||||||
|
// Use carefully as it can cause undefined behavior when used inappropriately.
|
||||||
|
// All mutexes needs to be unlocked.
|
||||||
|
bool m_enable = false; // Allows locking on mutexes, default don't lock mutexes
|
||||||
|
bool m_lockConfig = false; // After set, configuration cannot be changed
|
||||||
|
|
||||||
|
V3MutexConfig() = default;
|
||||||
|
~V3MutexConfig() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static V3MutexConfig& s() VL_MT_SAFE {
|
||||||
|
static V3MutexConfig s;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// configures class
|
||||||
|
void configure(bool enable) VL_MT_UNSAFE {
|
||||||
|
if (!s().m_lockConfig) {
|
||||||
|
s().m_enable = enable;
|
||||||
|
s().m_lockConfig = true;
|
||||||
|
} else {
|
||||||
|
// requires <iostream>
|
||||||
|
// avoided to reduce compile time
|
||||||
|
// std::cerr << "%Error: V3Mutex already configured." << std::endl;
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool lockConfig() VL_MT_SAFE { return m_lockConfig; }
|
||||||
|
bool enable() VL_MT_SAFE { return m_enable; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Mutex, wrapped to allow -fthread_safety checks
|
||||||
|
template <typename T>
|
||||||
|
class VL_CAPABILITY("mutex") V3MutexImp final {
|
||||||
|
private:
|
||||||
|
T m_mutex; // Mutex
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Construct mutex (without locking it)
|
||||||
|
V3MutexImp() = default;
|
||||||
|
~V3MutexImp() = default;
|
||||||
|
const V3MutexImp& operator!() const { return *this; } // For -fthread_safety
|
||||||
|
/// Acquire/lock mutex
|
||||||
|
void lock() VL_ACQUIRE() VL_MT_SAFE {
|
||||||
|
if (V3MutexConfig::s().enable()) {
|
||||||
|
// Try to acquire the lock by spinning. If the wait is short,
|
||||||
|
// avoids a trap to the OS plus OS scheduler overhead.
|
||||||
|
if (VL_LIKELY(try_lock())) return; // Short circuit loop
|
||||||
|
for (int i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||||
|
if (VL_LIKELY(try_lock())) return;
|
||||||
|
VL_CPU_RELAX();
|
||||||
|
}
|
||||||
|
// Spinning hasn't worked, pay the cost of blocking.
|
||||||
|
m_mutex.lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Release/unlock mutex
|
||||||
|
void unlock() VL_RELEASE() VL_MT_SAFE {
|
||||||
|
if (V3MutexConfig::s().enable()) { m_mutex.unlock(); }
|
||||||
|
}
|
||||||
|
/// Try to acquire mutex. Returns true on success, and false on failure.
|
||||||
|
bool try_lock() VL_TRY_ACQUIRE(true) VL_MT_SAFE {
|
||||||
|
return V3MutexConfig::s().enable() ? m_mutex.try_lock() : true;
|
||||||
|
}
|
||||||
|
/// Acquire/lock mutex and check for stop request
|
||||||
|
/// It tries to lock the mutex and if it fails, it check if stop request was send.
|
||||||
|
/// It returns after locking mutex.
|
||||||
|
/// This function should be extracted to V3ThreadPool, but due to clang thread-safety
|
||||||
|
/// limitations it needs to be placed here.
|
||||||
|
void lockCheckStopRequest(std::function<void()> checkStopRequestFunction)
|
||||||
|
VL_ACQUIRE() VL_MT_SAFE {
|
||||||
|
if (V3MutexConfig::s().enable()) {
|
||||||
|
while (true) {
|
||||||
|
checkStopRequestFunction();
|
||||||
|
if (m_mutex.try_lock()) return;
|
||||||
|
VL_CPU_RELAX();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
|
||||||
|
template <typename T>
|
||||||
|
class VL_SCOPED_CAPABILITY V3LockGuardImp final {
|
||||||
|
VL_UNCOPYABLE(V3LockGuardImp);
|
||||||
|
|
||||||
|
private:
|
||||||
|
T& m_mutexr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Construct and hold given mutex lock until destruction or unlock()
|
||||||
|
explicit V3LockGuardImp(T& mutexr) VL_ACQUIRE(mutexr) VL_MT_SAFE
|
||||||
|
: m_mutexr(mutexr) { // Need () or GCC 4.8 false warning
|
||||||
|
m_mutexr.lock();
|
||||||
|
}
|
||||||
|
/// Destruct and unlock the mutex
|
||||||
|
~V3LockGuardImp() VL_RELEASE() { m_mutexr.unlock(); }
|
||||||
|
/// Lock the mutex
|
||||||
|
void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); }
|
||||||
|
/// Unlock the mutex
|
||||||
|
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutexr.unlock(); }
|
||||||
|
/// Acquire/lock mutex and check for stop request.
|
||||||
|
/// It tries to lock the mutex and if it fails, it check if stop request was send.
|
||||||
|
/// It returns after locking mutex.
|
||||||
|
/// This function should be extracted to V3ThreadPool, but due to clang thread-safety
|
||||||
|
/// limitations it needs to be placed here.
|
||||||
|
void lockCheckStopRequest(std::function<void()> checkStopRequestFunction)
|
||||||
|
VL_ACQUIRE() VL_MT_SAFE {
|
||||||
|
m_mutexr.lockCheckStopRequest(checkStopRequestFunction);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using V3Mutex = V3MutexImp<std::mutex>;
|
||||||
|
using V3RecursiveMutex = V3MutexImp<std::recursive_mutex>;
|
||||||
|
using V3LockGuard = V3LockGuardImp<V3Mutex>;
|
||||||
|
using V3RecursiveLockGuard = V3LockGuardImp<V3RecursiveMutex>;
|
||||||
|
|
||||||
|
#endif // guard
|
||||||
|
|
@ -2232,8 +2232,10 @@ V3Number& V3Number::opNToI(const V3Number& lhs) {
|
||||||
const string& str = lhs.toString();
|
const string& str = lhs.toString();
|
||||||
for (size_t n = 0; n < str.length(); ++n) {
|
for (size_t n = 0; n < str.length(); ++n) {
|
||||||
const char c = str[str.length() - 1 - n];
|
const char c = str[str.length() - 1 - n];
|
||||||
for (size_t cbit = 0; cbit < 8; ++cbit)
|
for (size_t cbit = 0; cbit < 8; ++cbit) {
|
||||||
setBit(n * 8 + cbit, VL_BITISSET_I(c, cbit) ? 1 : 0);
|
const std::bitset<8> sbit{static_cast<unsigned long long>(c)};
|
||||||
|
setBit(n * 8 + cbit, sbit.test(cbit) ? 1 : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -896,8 +896,8 @@ string V3Options::version() VL_PURE {
|
||||||
}
|
}
|
||||||
|
|
||||||
string V3Options::protectKeyDefaulted() VL_MT_SAFE {
|
string V3Options::protectKeyDefaulted() VL_MT_SAFE {
|
||||||
static VerilatedMutex mutex;
|
static V3Mutex mutex;
|
||||||
const VerilatedLockGuard lock{mutex};
|
const V3LockGuard lock{mutex};
|
||||||
if (m_protectKey.empty()) {
|
if (m_protectKey.empty()) {
|
||||||
// Create a key with a human-readable symbol-like name.
|
// Create a key with a human-readable symbol-like name.
|
||||||
// This conversion drops ~2 bits of entropy out of 256, shouldn't matter.
|
// This conversion drops ~2 bits of entropy out of 256, shouldn't matter.
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "V3Error.h"
|
#include "V3Error.h"
|
||||||
#include "V3LangCode.h"
|
#include "V3LangCode.h"
|
||||||
|
#include "V3Mutex.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@
|
||||||
#include "config_build.h"
|
#include "config_build.h"
|
||||||
#include "verilatedos.h"
|
#include "verilatedos.h"
|
||||||
|
|
||||||
#include "verilated_threads.h"
|
|
||||||
|
|
||||||
// Limited V3 headers here - this is a base class for Vlc etc
|
// Limited V3 headers here - this is a base class for Vlc etc
|
||||||
#include "V3Os.h"
|
#include "V3Os.h"
|
||||||
#include "V3String.h"
|
#include "V3String.h"
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,10 @@ constexpr unsigned int V3ThreadPool::FUTUREWAITFOR_MS;
|
||||||
|
|
||||||
void V3ThreadPool::resize(unsigned n) VL_MT_UNSAFE {
|
void V3ThreadPool::resize(unsigned n) VL_MT_UNSAFE {
|
||||||
// This function is not thread-safe and can result in race between threads
|
// This function is not thread-safe and can result in race between threads
|
||||||
VerilatedLockGuard lock{m_mutex};
|
UASSERT(V3MutexConfig::s().lockConfig(),
|
||||||
VerilatedLockGuard stoppedJobsLock{m_stoppedJobsMutex};
|
"Mutex config needs to be locked before starting ThreadPool");
|
||||||
|
V3LockGuard lock{m_mutex};
|
||||||
|
V3LockGuard stoppedJobsLock{m_stoppedJobsMutex};
|
||||||
UASSERT(m_queue.empty(), "Resizing busy thread pool");
|
UASSERT(m_queue.empty(), "Resizing busy thread pool");
|
||||||
// Shut down old threads
|
// Shut down old threads
|
||||||
m_shutdown = true;
|
m_shutdown = true;
|
||||||
|
|
@ -57,7 +59,7 @@ void V3ThreadPool::workerJobLoop(int id) VL_MT_SAFE {
|
||||||
waitIfStopRequested();
|
waitIfStopRequested();
|
||||||
job_t job;
|
job_t job;
|
||||||
{
|
{
|
||||||
VerilatedLockGuard lock(m_mutex);
|
V3LockGuard lock(m_mutex);
|
||||||
m_cv.wait(lock, [&]() VL_REQUIRES(m_mutex) {
|
m_cv.wait(lock, [&]() VL_REQUIRES(m_mutex) {
|
||||||
return !m_queue.empty() || m_shutdown || m_stopRequested;
|
return !m_queue.empty() || m_shutdown || m_stopRequested;
|
||||||
});
|
});
|
||||||
|
|
@ -82,7 +84,7 @@ void V3ThreadPool::pushJob<void>(std::shared_ptr<std::promise<void>>& prom,
|
||||||
f();
|
f();
|
||||||
prom->set_value();
|
prom->set_value();
|
||||||
} else {
|
} else {
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
const V3LockGuard lock{m_mutex};
|
||||||
m_queue.push([prom, f] {
|
m_queue.push([prom, f] {
|
||||||
f();
|
f();
|
||||||
prom->set_value();
|
prom->set_value();
|
||||||
|
|
@ -95,7 +97,7 @@ void V3ThreadPool::requestExclusiveAccess(const V3ThreadPool::job_t&& exclusiveA
|
||||||
if (willExecuteSynchronously()) {
|
if (willExecuteSynchronously()) {
|
||||||
exclusiveAccessJob();
|
exclusiveAccessJob();
|
||||||
} else {
|
} else {
|
||||||
VerilatedLockGuard stoppedJobLock{m_stoppedJobsMutex};
|
V3LockGuard stoppedJobLock{m_stoppedJobsMutex};
|
||||||
// if some other job already requested exclusive access
|
// if some other job already requested exclusive access
|
||||||
// wait until it stops
|
// wait until it stops
|
||||||
if (stopRequested()) { waitStopRequested(stoppedJobLock); }
|
if (stopRequested()) { waitStopRequested(stoppedJobLock); }
|
||||||
|
|
@ -110,14 +112,13 @@ void V3ThreadPool::requestExclusiveAccess(const V3ThreadPool::job_t&& exclusiveA
|
||||||
}
|
}
|
||||||
|
|
||||||
bool V3ThreadPool::waitIfStopRequested() VL_MT_SAFE {
|
bool V3ThreadPool::waitIfStopRequested() VL_MT_SAFE {
|
||||||
VerilatedLockGuard stoppedJobLock(m_stoppedJobsMutex);
|
V3LockGuard stoppedJobLock(m_stoppedJobsMutex);
|
||||||
if (!stopRequested()) return false;
|
if (!stopRequested()) return false;
|
||||||
waitStopRequested(stoppedJobLock);
|
waitStopRequested(stoppedJobLock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3ThreadPool::waitStopRequested(VerilatedLockGuard& stoppedJobLock)
|
void V3ThreadPool::waitStopRequested(V3LockGuard& stoppedJobLock) VL_REQUIRES(m_stoppedJobsMutex) {
|
||||||
VL_REQUIRES(m_stoppedJobsMutex) {
|
|
||||||
++m_stoppedJobs;
|
++m_stoppedJobs;
|
||||||
m_stoppedJobsCV.notify_all();
|
m_stoppedJobsCV.notify_all();
|
||||||
m_stoppedJobsCV.wait(
|
m_stoppedJobsCV.wait(
|
||||||
|
|
@ -126,8 +127,8 @@ void V3ThreadPool::waitStopRequested(VerilatedLockGuard& stoppedJobLock)
|
||||||
m_stoppedJobsCV.notify_all();
|
m_stoppedJobsCV.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3ThreadPool::waitOtherThreads(VerilatedLockGuard& stoppedJobLock)
|
void V3ThreadPool::waitOtherThreads(V3LockGuard& stoppedJobLock) VL_MT_SAFE_EXCLUDES(m_mutex)
|
||||||
VL_MT_SAFE_EXCLUDES(m_mutex) VL_REQUIRES(m_stoppedJobsMutex) {
|
VL_REQUIRES(m_stoppedJobsMutex) {
|
||||||
++m_stoppedJobs;
|
++m_stoppedJobs;
|
||||||
m_stoppedJobsCV.notify_all();
|
m_stoppedJobsCV.notify_all();
|
||||||
m_cv.notify_all();
|
m_cv.notify_all();
|
||||||
|
|
@ -139,7 +140,7 @@ void V3ThreadPool::waitOtherThreads(VerilatedLockGuard& stoppedJobLock)
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3ThreadPool::selfTest() {
|
void V3ThreadPool::selfTest() {
|
||||||
VerilatedMutex commonMutex;
|
V3Mutex commonMutex;
|
||||||
int commonValue{0};
|
int commonValue{0};
|
||||||
|
|
||||||
auto firstJob = [&](int sleep) -> void {
|
auto firstJob = [&](int sleep) -> void {
|
||||||
|
|
@ -151,7 +152,7 @@ void V3ThreadPool::selfTest() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
auto secondJob = [&](int sleep) -> void {
|
auto secondJob = [&](int sleep) -> void {
|
||||||
VerilatedLockGuard lock{commonMutex};
|
V3LockGuard lock{commonMutex};
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
s().waitIfStopRequested();
|
s().waitIfStopRequested();
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
|
@ -159,7 +160,7 @@ void V3ThreadPool::selfTest() {
|
||||||
commonValue = 1000;
|
commonValue = 1000;
|
||||||
};
|
};
|
||||||
auto thirdJob = [&](int sleep) -> void {
|
auto thirdJob = [&](int sleep) -> void {
|
||||||
VerilatedLockGuard lock{commonMutex};
|
V3LockGuard lock{commonMutex};
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds{sleep});
|
std::this_thread::sleep_for(std::chrono::milliseconds{sleep});
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
s().requestExclusiveAccess([&]() { firstJob(sleep); });
|
s().requestExclusiveAccess([&]() { firstJob(sleep); });
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
#ifndef _V3THREADPOOL_H_
|
#ifndef _V3THREADPOOL_H_
|
||||||
#define _V3THREADPOOL_H_ 1
|
#define _V3THREADPOOL_H_ 1
|
||||||
|
|
||||||
#include "verilated_threads.h"
|
#include "V3Mutex.h"
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
@ -34,7 +34,7 @@ class V3ThreadPool final {
|
||||||
static constexpr unsigned int FUTUREWAITFOR_MS = 100;
|
static constexpr unsigned int FUTUREWAITFOR_MS = 100;
|
||||||
using job_t = std::function<void()>;
|
using job_t = std::function<void()>;
|
||||||
|
|
||||||
mutable VerilatedMutex m_mutex; // Mutex for use by m_queue
|
mutable V3Mutex m_mutex; // Mutex for use by m_queue
|
||||||
std::queue<job_t> m_queue VL_GUARDED_BY(m_mutex); // Queue of jobs
|
std::queue<job_t> m_queue VL_GUARDED_BY(m_mutex); // Queue of jobs
|
||||||
// We don't need to guard this condition_variable as
|
// We don't need to guard this condition_variable as
|
||||||
// both `notify_one` and `notify_all` functions are atomic,
|
// both `notify_one` and `notify_all` functions are atomic,
|
||||||
|
|
@ -42,7 +42,7 @@ class V3ThreadPool final {
|
||||||
// used by this condition_variable, so clang checks that we have mutex locked
|
// used by this condition_variable, so clang checks that we have mutex locked
|
||||||
std::condition_variable_any m_cv; // Conditions to wake up workers
|
std::condition_variable_any m_cv; // Conditions to wake up workers
|
||||||
std::list<std::thread> m_workers; // Worker threads
|
std::list<std::thread> m_workers; // Worker threads
|
||||||
VerilatedMutex m_stoppedJobsMutex; // Used to signal stopped jobs
|
V3Mutex m_stoppedJobsMutex; // Used to signal stopped jobs
|
||||||
// Conditions to wake up stopped jobs
|
// Conditions to wake up stopped jobs
|
||||||
std::condition_variable_any m_stoppedJobsCV VL_GUARDED_BY(m_stoppedJobsMutex);
|
std::condition_variable_any m_stoppedJobsCV VL_GUARDED_BY(m_stoppedJobsMutex);
|
||||||
std::atomic_uint m_stoppedJobs{0}; // Currently stopped jobs waiting for wake up
|
std::atomic_uint m_stoppedJobs{0}; // Currently stopped jobs waiting for wake up
|
||||||
|
|
@ -54,7 +54,7 @@ class V3ThreadPool final {
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
V3ThreadPool() = default;
|
V3ThreadPool() = default;
|
||||||
~V3ThreadPool() {
|
~V3ThreadPool() {
|
||||||
VerilatedLockGuard lock{m_mutex};
|
V3LockGuard lock{m_mutex};
|
||||||
m_queue = {}; // make sure queue is empty
|
m_queue = {}; // make sure queue is empty
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
resize(0);
|
resize(0);
|
||||||
|
|
@ -106,15 +106,15 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stopRequestedStandalone() VL_MT_SAFE_EXCLUDES(m_stoppedJobsMutex) {
|
bool stopRequestedStandalone() VL_MT_SAFE_EXCLUDES(m_stoppedJobsMutex) {
|
||||||
const VerilatedLockGuard lock{m_stoppedJobsMutex};
|
const V3LockGuard lock{m_stoppedJobsMutex};
|
||||||
return stopRequested();
|
return stopRequested();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Waits until exclusive access job completes its job
|
// Waits until exclusive access job completes its job
|
||||||
void waitStopRequested(VerilatedLockGuard& stoppedJobLock) VL_REQUIRES(m_stoppedJobsMutex);
|
void waitStopRequested(V3LockGuard& stoppedJobLock) VL_REQUIRES(m_stoppedJobsMutex);
|
||||||
|
|
||||||
// Waits until all other jobs are stopped
|
// Waits until all other jobs are stopped
|
||||||
void waitOtherThreads(VerilatedLockGuard& stoppedJobLock) VL_MT_SAFE_EXCLUDES(m_mutex)
|
void waitOtherThreads(V3LockGuard& stoppedJobLock) VL_MT_SAFE_EXCLUDES(m_mutex)
|
||||||
VL_REQUIRES(m_stoppedJobsMutex);
|
VL_REQUIRES(m_stoppedJobsMutex);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
@ -146,7 +146,7 @@ std::future<T> V3ThreadPool::enqueue(std::function<T()>&& f) VL_MT_SAFE {
|
||||||
std::shared_ptr<std::promise<T>> prom = std::make_shared<std::promise<T>>();
|
std::shared_ptr<std::promise<T>> prom = std::make_shared<std::promise<T>>();
|
||||||
std::future<T> result = prom->get_future();
|
std::future<T> result = prom->get_future();
|
||||||
pushJob(prom, std::move(f));
|
pushJob(prom, std::move(f));
|
||||||
const VerilatedLockGuard guard{m_mutex};
|
const V3LockGuard guard{m_mutex};
|
||||||
m_cv.notify_one();
|
m_cv.notify_one();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -157,7 +157,7 @@ void V3ThreadPool::pushJob(std::shared_ptr<std::promise<T>>& prom,
|
||||||
if (willExecuteSynchronously()) {
|
if (willExecuteSynchronously()) {
|
||||||
prom->set_value(f());
|
prom->set_value(f());
|
||||||
} else {
|
} else {
|
||||||
const VerilatedLockGuard guard{m_mutex};
|
const V3LockGuard guard{m_mutex};
|
||||||
m_queue.push([prom, f] { prom->set_value(f()); });
|
m_queue.push([prom, f] { prom->set_value(f()); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@
|
||||||
|
|
||||||
void V3Waiver::addEntry(V3ErrorCode errorCode, const std::string& filename, const std::string& str)
|
void V3Waiver::addEntry(V3ErrorCode errorCode, const std::string& filename, const std::string& str)
|
||||||
VL_MT_SAFE_EXCLUDES(s_mutex) {
|
VL_MT_SAFE_EXCLUDES(s_mutex) {
|
||||||
const VerilatedLockGuard lock{s_mutex};
|
|
||||||
if (filename == V3Options::getStdPackagePath()) return;
|
if (filename == V3Options::getStdPackagePath()) return;
|
||||||
|
const V3LockGuard lock{s_mutex};
|
||||||
std::stringstream entry;
|
std::stringstream entry;
|
||||||
const size_t pos = str.find('\n');
|
const size_t pos = str.find('\n');
|
||||||
entry << "lint_off -rule " << errorCode.ascii() << " -file \"*" << filename << "\" -match \""
|
entry << "lint_off -rule " << errorCode.ascii() << " -file \"*" << filename << "\" -match \""
|
||||||
|
|
@ -51,12 +51,12 @@ void V3Waiver::write(const std::string& filename) VL_MT_SAFE_EXCLUDES(s_mutex) {
|
||||||
*ofp << "// 2. Keep the waiver permanently if you are sure this is okay\n";
|
*ofp << "// 2. Keep the waiver permanently if you are sure this is okay\n";
|
||||||
*ofp << "// 3. Keep the waiver temporarily to suppress the output\n\n";
|
*ofp << "// 3. Keep the waiver temporarily to suppress the output\n\n";
|
||||||
|
|
||||||
const VerilatedLockGuard lock{s_mutex};
|
const V3LockGuard lock{s_mutex};
|
||||||
|
|
||||||
if (s_waiverList.empty()) *ofp << "// No waivers needed - great!\n";
|
if (s_waiverList.empty()) *ofp << "// No waivers needed - great!\n";
|
||||||
|
|
||||||
for (const auto& i : s_waiverList) *ofp << "// " << i << "\n\n";
|
for (const auto& i : s_waiverList) *ofp << "// " << i << "\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
VerilatedMutex V3Waiver::s_mutex;
|
V3Mutex V3Waiver::s_mutex;
|
||||||
V3Waiver::WaiverList V3Waiver::s_waiverList;
|
V3Waiver::WaiverList V3Waiver::s_waiverList;
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,8 @@
|
||||||
#ifndef VERILATOR_V3WAIVER_H_
|
#ifndef VERILATOR_V3WAIVER_H_
|
||||||
#define VERILATOR_V3WAIVER_H_
|
#define VERILATOR_V3WAIVER_H_
|
||||||
|
|
||||||
#include "verilated_threads.h"
|
|
||||||
|
|
||||||
#include "V3Error.h"
|
#include "V3Error.h"
|
||||||
|
#include "V3Mutex.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -27,7 +26,7 @@
|
||||||
class V3Waiver final {
|
class V3Waiver final {
|
||||||
// TYPES
|
// TYPES
|
||||||
using WaiverList = std::vector<std::string>;
|
using WaiverList = std::vector<std::string>;
|
||||||
static VerilatedMutex s_mutex; // Protect members
|
static V3Mutex s_mutex; // Protect members
|
||||||
static WaiverList s_waiverList VL_GUARDED_BY(s_mutex);
|
static WaiverList s_waiverList VL_GUARDED_BY(s_mutex);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -590,6 +590,8 @@ static void verilate(const string& argString) {
|
||||||
v3fatalSrc("VERILATOR_DEBUG_SKIP_IDENTICAL w/ --skip-identical: Changes found\n");
|
v3fatalSrc("VERILATOR_DEBUG_SKIP_IDENTICAL w/ --skip-identical: Changes found\n");
|
||||||
} // LCOV_EXCL_STOP
|
} // LCOV_EXCL_STOP
|
||||||
|
|
||||||
|
// Disable mutexes in single-thread verilation
|
||||||
|
V3MutexConfig::s().configure(v3Global.opt.verilateJobs() > 1 /*enable*/);
|
||||||
// Adjust thread pool size
|
// Adjust thread pool size
|
||||||
V3ThreadPool::s().resize(v3Global.opt.verilateJobs());
|
V3ThreadPool::s().resize(v3Global.opt.verilateJobs());
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue