Internals: Add mutex to V3Error (#3680)

This commit is contained in:
Kamil Rakoczy
2023-02-09 22:15:37 -05:00
committed by GitHub
parent 4eb280601e
commit 93d50c4499
19 changed files with 505 additions and 267 deletions
+114 -119
View File
@@ -25,24 +25,6 @@ VL_DEFINE_DEBUG_FUNCTIONS;
// clang-format on
//======================================================================
// Statics
int V3Error::s_errCount = 0;
int V3Error::s_warnCount = 0;
int V3Error::s_debugDefault = 0;
int V3Error::s_errorLimit = V3Error::MAX_ERRORS;
bool V3Error::s_warnFatal = true;
int V3Error::s_tellManual = 0;
std::ostringstream V3Error::s_errorStr; // Error string being formed
V3ErrorCode V3Error::s_errorCode = V3ErrorCode::EC_FATAL;
bool V3Error::s_errorContexted = false;
bool V3Error::s_errorSuppressed = false;
std::array<bool, V3ErrorCode::_ENUM_MAX> V3Error::s_describedEachWarn;
std::array<bool, V3ErrorCode::_ENUM_MAX> V3Error::s_pretendError;
bool V3Error::s_describedWarnings = false;
bool V3Error::s_describedWeb = false;
V3Error::MessagesSet V3Error::s_messages;
V3Error::ErrorExitCb V3Error::s_errorExitCb = nullptr;
struct v3errorIniter {
v3errorIniter() { V3Error::init(); }
@@ -65,51 +47,10 @@ V3ErrorCode::V3ErrorCode(const char* msgp) {
}
//######################################################################
// V3Error class functions
// V3ErrorGuarded class functions
//
void V3Error::init() {
for (int i = 0; i < V3ErrorCode::_ENUM_MAX; i++) {
s_describedEachWarn[i] = false;
s_pretendError[i] = V3ErrorCode{i}.pretendError();
}
if (VL_UNCOVERABLE(string(V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()) != " MAX")) {
v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged");
}
}
string V3Error::lineStr(const char* filename, int lineno) {
std::ostringstream out;
const char* const fnslashp = std::strrchr(filename, '/');
if (fnslashp) filename = fnslashp + 1;
out << filename << ":" << std::dec << lineno << ":";
const char* const spaces = " ";
size_t numsp = out.str().length();
if (numsp > 20) numsp = 20;
out << (spaces + numsp);
return out.str();
}
void V3Error::incErrors() {
s_errCount++;
if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse
v3fatalExit("Exiting due to too many errors encountered; --error-limit=" //
<< errorCount() << endl);
}
}
void V3Error::abortIfWarnings() {
const bool exwarn = warnFatal() && warnCount();
if (errorCount() && exwarn) {
v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s), " //
<< warnCount() << " warning(s)\n");
} else if (errorCount()) {
v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s)\n");
} else if (exwarn) {
v3fatalExit("Exiting due to " << std::dec << warnCount() << " warning(s)\n");
}
}
bool V3Error::isError(V3ErrorCode code, bool supp) {
bool V3ErrorGuarded::isError(V3ErrorCode code, bool supp) VL_REQUIRES(m_mutex) {
if (supp) {
return false;
} else if (code == V3ErrorCode::USERINFO) {
@@ -124,16 +65,16 @@ bool V3Error::isError(V3ErrorCode code, bool supp) {
return true;
} else if (code == V3ErrorCode::EC_ERROR) {
return true;
} else if (code < V3ErrorCode::EC_FIRST_WARN || s_pretendError[code]) {
} else if (code < V3ErrorCode::EC_FIRST_WARN || pretendError(code)) {
return true;
} else {
return false;
}
}
string V3Error::msgPrefix() {
const V3ErrorCode code = s_errorCode;
const bool supp = s_errorSuppressed;
string V3ErrorGuarded::msgPrefix() VL_REQUIRES(m_mutex) {
const V3ErrorCode code = m_errorCode;
const bool supp = m_errorSuppressed;
if (supp) {
return "-arning-suppressed: ";
} else if (code == V3ErrorCode::USERINFO) {
@@ -155,10 +96,7 @@ string V3Error::msgPrefix() {
}
}
//======================================================================
// Abort/exit
void V3Error::vlAbortOrExit() {
void V3ErrorGuarded::vlAbortOrExit() VL_REQUIRES(m_mutex) {
if (V3Error::debugDefault()) {
std::cerr << msgPrefix() << "Aborting since under --debug" << endl;
V3Error::vlAbort();
@@ -167,50 +105,53 @@ void V3Error::vlAbortOrExit() {
}
}
void V3Error::vlAbort() {
VL_GCOV_DUMP();
std::abort();
}
string V3ErrorGuarded::warnMore() VL_REQUIRES(m_mutex) { return string(msgPrefix().size(), ' '); }
//======================================================================
// Global Functions
void V3Error::suppressThisWarning() {
void V3ErrorGuarded::suppressThisWarning() VL_REQUIRES(m_mutex) {
#ifndef V3ERROR_NO_GLOBAL_
V3Stats::addStatSum(std::string{"Warnings, Suppressed "} + s_errorCode.ascii(), 1);
V3Stats::addStatSum(std::string{"Warnings, Suppressed "} + errorCode().ascii(), 1);
#endif
s_errorSuppressed = true;
errorSuppressed(true);
}
string V3Error::warnMore() { return string(msgPrefix().size(), ' '); }
// cppcheck-has-bug-suppress constParameter
void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) {
void V3ErrorGuarded::v3errorEnd(std::ostringstream& sstr, const string& extra)
VL_REQUIRES(m_mutex) {
#if defined(__COVERITY__) || defined(__cppcheck__)
if (s_errorCode == V3ErrorCode::EC_FATAL) __coverity_panic__(x);
if (m_errorCode == V3ErrorCode::EC_FATAL) __coverity_panic__(x);
#endif
// Skip suppressed messages
if (s_errorSuppressed
if (m_errorSuppressed
// On debug, show only non default-off warning to prevent pages of warnings
&& (!debug() || s_errorCode.defaultsOff()))
&& (!debug() || m_errorCode.defaultsOff()))
return;
string msg = msgPrefix() + sstr.str();
if (s_errorSuppressed) { // If suppressed print only first line to reduce verbosity
// If suppressed print only first line to reduce verbosity
if (m_errorSuppressed) {
string::size_type pos;
if ((pos = msg.find('\n')) != string::npos) {
msg.erase(pos, msg.length() - pos);
msg += "...";
}
}
string msg_additional;
{
string::size_type pos;
if ((pos = msg.find(V3Error::warnAdditionalInfo())) != string::npos) {
msg_additional = msg.substr(pos + V3Error::warnAdditionalInfo().size());
msg.erase(pos);
}
}
// Trailing newline (generally not on messages) & remove dup newlines
{
msg += '\n'; // Trailing newlines generally not put on messages so add
string::size_type pos;
while ((pos = msg.find("\n\n")) != string::npos) msg.erase(pos + 1, 1);
while ((pos = msg_additional.find("\n\n")) != string::npos)
msg_additional.erase(pos + 1, 1);
}
// Suppress duplicate messages
if (s_messages.find(msg) != s_messages.end()) return;
s_messages.insert(msg);
if (!m_messages.insert(msg).second) return;
if (!extra.empty()) {
const string extraMsg = warnMore() + extra + "\n";
const size_t pos = msg.find('\n');
@@ -219,44 +160,45 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) {
// Output
if (
#ifndef V3ERROR_NO_GLOBAL_
!(v3Global.opt.quietExit() && s_errorCode == V3ErrorCode::EC_FATALEXIT)
!(v3Global.opt.quietExit() && m_errorCode == V3ErrorCode::EC_FATALEXIT)
#else
true
#endif
) {
std::cerr << msg;
}
if (!s_errorSuppressed
&& !(s_errorCode == V3ErrorCode::EC_INFO || s_errorCode == V3ErrorCode::USERINFO)) {
const bool anError = isError(s_errorCode, s_errorSuppressed);
if (s_errorCode >= V3ErrorCode::EC_FIRST_NAMED && !s_describedWeb) {
s_describedWeb = true;
if (!m_errorSuppressed
&& !(m_errorCode == V3ErrorCode::EC_INFO || m_errorCode == V3ErrorCode::USERINFO)) {
const bool anError = isError(m_errorCode, m_errorSuppressed);
if (m_errorCode >= V3ErrorCode::EC_FIRST_NAMED && !m_describedWeb) {
m_describedWeb = true;
std::cerr << warnMore() << "... For " << (anError ? "error" : "warning")
<< " description see https://verilator.org/warn/" << s_errorCode.ascii()
<< " description see https://verilator.org/warn/" << m_errorCode.ascii()
<< "?v=" << PACKAGE_VERSION_NUMBER_STRING << endl;
}
if (!s_describedEachWarn[s_errorCode] && !s_pretendError[s_errorCode]) {
s_describedEachWarn[s_errorCode] = true;
if (s_errorCode >= V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) {
s_describedWarnings = true;
if (!m_describedEachWarn[m_errorCode] && !m_pretendError[m_errorCode]) {
m_describedEachWarn[m_errorCode] = true;
if (m_errorCode >= V3ErrorCode::EC_FIRST_WARN && !m_describedWarnings) {
m_describedWarnings = true;
std::cerr << warnMore() << "... Use \"/* verilator lint_off "
<< s_errorCode.ascii()
<< m_errorCode.ascii()
<< " */\" and lint_on around source to disable this message." << endl;
}
if (s_errorCode.dangerous()) {
if (m_errorCode.dangerous()) {
std::cerr << warnMore() << "*** See https://verilator.org/warn/"
<< s_errorCode.ascii() << " before disabling this,\n";
<< m_errorCode.ascii() << " before disabling this,\n";
std::cerr << warnMore() << "else you may end up with different sim results."
<< endl;
}
}
if (!msg_additional.empty()) { std::cerr << msg_additional; }
// If first warning is not the user's fault (internal/unsupported) then give the website
// Not later warnings, as a internal may be caused by an earlier problem
if (s_tellManual == 0) {
if (s_errorCode.mentionManual() || sstr.str().find("Unsupported") != string::npos) {
s_tellManual = 1;
if (tellManual() == 0) {
if (m_errorCode.mentionManual() || sstr.str().find("Unsupported") != string::npos) {
tellManual(1);
} else {
s_tellManual = 2;
tellManual(2);
}
}
if (anError) {
@@ -264,26 +206,34 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) {
} else {
incWarnings();
}
if (s_errorCode == V3ErrorCode::EC_FATAL || s_errorCode == V3ErrorCode::EC_FATALEXIT
|| s_errorCode == V3ErrorCode::EC_FATALSRC) {
if (m_errorCode == V3ErrorCode::EC_FATAL || m_errorCode == V3ErrorCode::EC_FATALEXIT
|| m_errorCode == V3ErrorCode::EC_FATALSRC) {
static bool inFatal = false;
if (!inFatal) {
inFatal = true;
if (s_tellManual == 1) {
if (tellManual() == 1) {
std::cerr << warnMore()
<< "... See the manual at https://verilator.org/verilator_doc.html "
"for more assistance."
<< endl;
s_tellManual = 2;
tellManual(2);
}
#ifndef V3ERROR_NO_GLOBAL_
if (dumpTree()) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree", 990));
}
if (debug()) {
if (s_errorExitCb) s_errorExitCb();
V3Stats::statsFinalAll(v3Global.rootp());
V3Stats::statsReport();
if (dumpTree() || debug()) {
V3ThreadPool::s().requestExclusiveAccess([&]() VL_REQUIRES(m_mutex) {
if (dumpTree()) {
v3Global.rootp()->dumpTreeFile(
v3Global.debugFilename("final.tree", 990));
}
if (debug()) {
execErrorExitCb();
V3Stats::statsFinalAll(v3Global.rootp());
V3Stats::statsReport();
}
// Abort in exclusive access to make sure other threads
// don't change error code
vlAbortOrExit();
});
}
#endif
}
@@ -292,7 +242,52 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) {
} else if (anError) {
// We don't dump tree on any error because a Visitor may be in middle of
// a tree cleanup and cause a false broken problem.
if (s_errorExitCb) s_errorExitCb();
execErrorExitCb();
}
}
}
//######################################################################
// V3Error class functions
void V3Error::init() {
for (int i = 0; i < V3ErrorCode::_ENUM_MAX; i++) {
describedEachWarn(static_cast<V3ErrorCode>(i), false);
pretendError(static_cast<V3ErrorCode>(i), V3ErrorCode{i}.pretendError());
}
if (VL_UNCOVERABLE(string(V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()) != " MAX")) {
v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged");
}
}
string V3Error::lineStr(const char* filename, int lineno) VL_PURE {
std::ostringstream out;
const char* const fnslashp = std::strrchr(filename, '/');
if (fnslashp) filename = fnslashp + 1;
out << filename << ":" << std::dec << lineno << ":";
const char* const spaces = " ";
size_t numsp = out.str().length();
if (numsp > 20) numsp = 20;
out << (spaces + numsp);
return out.str();
}
void V3Error::abortIfWarnings() {
const bool exwarn = warnFatal() && warnCount();
if (errorCount() && exwarn) {
v3fatalExit("Exiting due to " << std::dec << V3Error::s().errorCount() << " error(s), " //
<< V3Error::s().warnCount() << " warning(s)\n");
} else if (errorCount()) {
v3fatalExit("Exiting due to " << std::dec << V3Error::s().errorCount() << " error(s)\n");
} else if (exwarn) {
v3fatalExit("Exiting due to " << std::dec << V3Error::s().warnCount() << " warning(s)\n");
}
}
//======================================================================
// Abort/exit
void V3Error::vlAbort() {
VL_GCOV_DUMP();
std::abort();
}