Internals: Always attempt to release resources on termination (#6416)
Replace std::exit with v3Global.exit, and make V3Error::vlAbort call v3Global.shutdown. This gives us an opportunity to release resources to facilitate leak checking even when exiting early on an error. Note we still don't release most resources by default without VL_LEAK_CHECKS, so there is no behaviour change there.
This commit is contained in:
parent
d3aab31bcf
commit
57d8bb5d1f
|
|
@ -97,19 +97,19 @@ void V3ErrorGuarded::vlAbortOrExit() VL_REQUIRES(m_mutex) {
|
|||
std::cerr << msgPrefix() << "Aborting since under --debug" << endl;
|
||||
V3Error::vlAbort();
|
||||
}
|
||||
#ifndef V3ERROR_NO_GLOBAL_
|
||||
else if (v3Global.opt.verilateJobs() > 1
|
||||
&& v3Global.mainThreadId() != std::this_thread::get_id()) {
|
||||
VL_GCOV_DUMP(); // No static destructors are called, thus must be called manually.
|
||||
|
||||
// Exit without triggering any global destructors.
|
||||
// Used to prevent detached V3ThreadPool jobs accessing destroyed static objects.
|
||||
#ifndef V3ERROR_NO_GLOBAL_
|
||||
if (v3Global.opt.verilateJobs() > 1 && v3Global.mainThreadId() != std::this_thread::get_id()) {
|
||||
// No static destructors are called, thus must be called manually.
|
||||
VL_GCOV_DUMP();
|
||||
// Exit without triggering any global destructors. Used to prevent
|
||||
// detached V3ThreadPool jobs accessing destroyed static objects.
|
||||
::_exit(1);
|
||||
}
|
||||
v3Global.vlExit(1);
|
||||
#else
|
||||
std::exit(1);
|
||||
#endif
|
||||
else {
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
string V3ErrorGuarded::warnMoreSpaces() VL_REQUIRES(m_mutex) {
|
||||
|
|
@ -369,6 +369,9 @@ void V3Error::abortIfWarnings() {
|
|||
|
||||
void V3Error::vlAbort() {
|
||||
VL_GCOV_DUMP();
|
||||
#ifndef V3ERROR_NO_GLOBAL_
|
||||
v3Global.shutdown();
|
||||
#endif
|
||||
std::abort();
|
||||
}
|
||||
std::ostringstream& V3Error::v3errorPrep(V3ErrorCode code) VL_ACQUIRE(s().m_mutex) {
|
||||
|
|
|
|||
|
|
@ -459,12 +459,8 @@ public:
|
|||
// ######################################################################
|
||||
|
||||
class V3Error final {
|
||||
// Base class for any object that wants debugging and error reporting
|
||||
// CONSTRUCTORS
|
||||
V3Error() {
|
||||
std::cerr << ("Static class");
|
||||
V3Error::vlAbort();
|
||||
}
|
||||
// Static members only
|
||||
V3Error() = delete;
|
||||
|
||||
public:
|
||||
static V3ErrorGuarded& s() VL_MT_SAFE { // Singleton
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "V3HierBlock.h"
|
||||
#include "V3LinkCells.h"
|
||||
#include "V3Parse.h"
|
||||
#include "V3PreShell.h"
|
||||
#include "V3Stats.h"
|
||||
#include "V3ThreadPool.h"
|
||||
|
||||
|
|
@ -53,11 +54,18 @@ void V3Global::boot() {
|
|||
}
|
||||
|
||||
void V3Global::shutdown() {
|
||||
V3PreShell::shutdown();
|
||||
VL_DO_CLEAR(delete m_hierPlanp, m_hierPlanp = nullptr); // delete nullptr is safe
|
||||
VL_DO_CLEAR(delete m_threadPoolp, m_threadPoolp = nullptr); // delete nullptr is safe
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
if (m_rootp) VL_DO_CLEAR(m_rootp->deleteTree(), m_rootp = nullptr);
|
||||
#endif
|
||||
FileLine::deleteAllRemaining();
|
||||
}
|
||||
|
||||
void V3Global::vlExit(int status) {
|
||||
shutdown();
|
||||
std::exit(status);
|
||||
}
|
||||
|
||||
void V3Global::checkTree() const { rootp()->checkTree(); }
|
||||
|
|
|
|||
|
|
@ -147,6 +147,8 @@ public:
|
|||
void boot();
|
||||
void shutdown(); // Release allocated resources
|
||||
|
||||
void vlExit(int status);
|
||||
|
||||
// ACCESSORS (general)
|
||||
AstNetlist* rootp() const VL_MT_SAFE { return m_rootp; }
|
||||
V3ThreadPool* threadPoolp() const VL_PURE { return m_threadPoolp; }
|
||||
|
|
|
|||
|
|
@ -1272,9 +1272,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
DECL_OPTION("-debugi-", CbPartialMatchVal, [this](const char* optp, const char* valp) {
|
||||
m_debugLevel[optp] = std::atoi(valp);
|
||||
});
|
||||
DECL_OPTION("-debug-abort", CbCall,
|
||||
V3Error::vlAbort)
|
||||
.undocumented(); // See also --debug-sigsegv
|
||||
DECL_OPTION("-debug-abort", CbCall, []() {
|
||||
V3Error::vlAbort();
|
||||
}).undocumented(); // See also --debug-sigseg
|
||||
DECL_OPTION("-debug-check", OnOff, &m_debugCheck);
|
||||
DECL_OPTION("-debug-collision", OnOff, &m_debugCollision).undocumented();
|
||||
DECL_OPTION("-debug-emitv", OnOff, &m_debugEmitV).undocumented();
|
||||
|
|
@ -1392,15 +1392,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
DECL_OPTION("-gdbbt", CbCall, []() {}); // Processed only in bin/verilator shell
|
||||
DECL_OPTION("-generate-key", CbCall, [this]() {
|
||||
cout << protectKeyDefaulted() << endl;
|
||||
std::exit(0);
|
||||
v3Global.vlExit(0);
|
||||
});
|
||||
DECL_OPTION("-getenv", CbVal, [](const char* valp) {
|
||||
cout << V3Options::getenvBuiltins(valp) << endl;
|
||||
std::exit(0);
|
||||
v3Global.vlExit(0);
|
||||
});
|
||||
DECL_OPTION("-get-supported", CbVal, [](const char* valp) {
|
||||
cout << V3Options::getSupported(valp) << endl;
|
||||
std::exit(0);
|
||||
v3Global.vlExit(0);
|
||||
});
|
||||
|
||||
DECL_OPTION("-hierarchical", OnOff, &m_hierarchical);
|
||||
|
|
@ -1719,7 +1719,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
|
||||
DECL_OPTION("-V", CbCall, [this]() {
|
||||
showVersion(true);
|
||||
std::exit(0);
|
||||
v3Global.vlExit(0);
|
||||
});
|
||||
DECL_OPTION("-v", CbVal, [this, &optdir](const char* valp) {
|
||||
V3Options::addLibraryFile(parseFileArg(optdir, valp), work());
|
||||
|
|
@ -1739,7 +1739,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
});
|
||||
DECL_OPTION("-version", CbCall, [this]() {
|
||||
showVersion(false);
|
||||
std::exit(0);
|
||||
v3Global.vlExit(0);
|
||||
});
|
||||
DECL_OPTION("-vpi", OnOff, &m_vpi);
|
||||
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ static void process() {
|
|||
V3Error::abortIfErrors();
|
||||
if (v3Global.opt.debugExitParse()) {
|
||||
cout << "--debug-exit-parse: Exiting after parse\n";
|
||||
std::exit(0);
|
||||
v3Global.vlExit(0);
|
||||
}
|
||||
|
||||
// Convert parseref's to varrefs, and other directly post parsing fixups
|
||||
|
|
@ -173,7 +173,7 @@ static void process() {
|
|||
V3Error::abortIfErrors();
|
||||
if (v3Global.opt.serializeOnly()) emitXmlOrJson();
|
||||
cout << "--debug-exit-uvm23: Exiting after UVM-supported pass\n";
|
||||
std::exit(0);
|
||||
v3Global.vlExit(0);
|
||||
}
|
||||
|
||||
// Remove parameters by cloning modules to de-parameterized versions
|
||||
|
|
@ -204,7 +204,7 @@ static void process() {
|
|||
V3Error::abortIfErrors();
|
||||
if (v3Global.opt.serializeOnly()) emitXmlOrJson();
|
||||
cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n";
|
||||
std::exit(0);
|
||||
v3Global.vlExit(0);
|
||||
}
|
||||
|
||||
// Calculate and check widths, edit tree to TRUNC/EXTRACT any width mismatches
|
||||
|
|
@ -819,7 +819,7 @@ static void execBuildJob() {
|
|||
|
||||
if (exit_code != 0) {
|
||||
v3error(cmdStr << " exited with " << exit_code << std::endl);
|
||||
std::exit(exit_code);
|
||||
v3Global.vlExit(exit_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -832,7 +832,7 @@ static void execHierVerilation() {
|
|||
const int exit_code = V3Os::system(cmdStr);
|
||||
if (exit_code != 0) {
|
||||
v3error(cmdStr << " exited with " << exit_code << std::endl);
|
||||
std::exit(exit_code);
|
||||
v3Global.vlExit(exit_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -884,9 +884,7 @@ int main(int argc, char** argv) {
|
|||
V3DiagSarif::output(true);
|
||||
|
||||
// Explicitly release resources
|
||||
V3PreShell::shutdown();
|
||||
v3Global.shutdown();
|
||||
FileLine::deleteAllRemaining();
|
||||
|
||||
if (!v3Global.opt.quietStats() && !v3Global.opt.preprocOnly()) {
|
||||
V3Stats::addStatPerf(V3Stats::STAT_CPUTIME, cpuTimeTotal.deltaTime());
|
||||
|
|
|
|||
Loading…
Reference in New Issue