Gabe Black has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/12601
Change subject: systemc: Fortify how exceptions are caught and passed
around.
......................................................................
systemc: Fortify how exceptions are caught and passed around.
This change tightens up exception catching and makes gem5's systemc
code react to exceptions more in line with the Accellera
implementation. This prevents exceptions from being caught by the
pybind11 integration which makes it very difficult to see where an
exception came from, and makes the output differ by including a
(mostly useless) backtrace.
Change-Id: I7130d53a98fadd137073d1718f780f32f57c658c
---
M src/systemc/core/process.cc
M src/systemc/core/process_types.hh
M src/systemc/core/sc_main.cc
M src/systemc/core/scheduler.cc
M src/systemc/core/scheduler.hh
M src/systemc/ext/utils/sc_report_handler.hh
M src/systemc/tests/config.py
M src/systemc/utils/sc_report_handler.cc
8 files changed, 101 insertions(+), 9 deletions(-)
diff --git a/src/systemc/core/process.cc b/src/systemc/core/process.cc
index 317e8c3..cc2eff5 100644
--- a/src/systemc/core/process.cc
+++ b/src/systemc/core/process.cc
@@ -343,6 +343,8 @@
} catch(const ::sc_core::sc_unwind_exception &exc) {
reset = exc.is_reset();
_isUnwinding = false;
+ } catch (...) {
+ throw;
}
} while (reset);
needsStart(true);
diff --git a/src/systemc/core/process_types.hh
b/src/systemc/core/process_types.hh
index 6f603e7..748c249 100644
--- a/src/systemc/core/process_types.hh
+++ b/src/systemc/core/process_types.hh
@@ -92,7 +92,13 @@
main() override
{
thread->_needsStart = false;
- thread->run();
+ try {
+ thread->run();
+ } catch (...) {
+ thread->terminate();
+ scheduler.throwToScMain();
+ return;
+ }
thread->terminate();
scheduler.yield();
}
diff --git a/src/systemc/core/sc_main.cc b/src/systemc/core/sc_main.cc
index 2637cef..5e1cd4f 100644
--- a/src/systemc/core/sc_main.cc
+++ b/src/systemc/core/sc_main.cc
@@ -79,6 +79,10 @@
} catch (const sc_report &r) {
// There was an exception nobody caught.
resultStr = r.what();
+ } catch (...) {
+ // There was some other type of exception we need to wrap.
+ const sc_report *r = ::sc_gem5::reportifyException();
+ resultStr = r->what();
}
::sc_gem5::Kernel::scMainFinished(true);
::sc_gem5::scheduler.clear();
diff --git a/src/systemc/core/scheduler.cc b/src/systemc/core/scheduler.cc
index 4c98b68..5348e66 100644
--- a/src/systemc/core/scheduler.cc
+++ b/src/systemc/core/scheduler.cc
@@ -34,6 +34,8 @@
#include "sim/eventq.hh"
#include "systemc/core/kernel.hh"
#include "systemc/ext/core/sc_main.hh"
+#include "systemc/ext/utils/sc_report.hh"
+#include "systemc/ext/utils/sc_report_handler.hh"
namespace sc_gem5
{
@@ -42,7 +44,7 @@
eq(nullptr), readyEvent(this, false, ReadyPriority),
pauseEvent(this, false, PausePriority),
stopEvent(this, false, StopPriority),
- scMain(nullptr),
+ scMain(nullptr), _throwToScMain(nullptr),
starvationEvent(this, false, StarvationPriority),
_started(false), _paused(false), _stopped(false), _stopNow(false),
maxTickEvent(this, false, MaxTickPriority),
@@ -184,7 +186,11 @@
// If the current process needs to be manually started, start it.
if (_current && _current->needsStart()) {
_current->needsStart(false);
- _current->run();
+ try {
+ _current->run();
+ } catch (...) {
+ throwToScMain();
+ }
}
}
if (_current && _current->excWrapper) {
@@ -336,7 +342,8 @@
_paused = true;
kernel->status(::sc_core::SC_PAUSED);
runOnce = false;
- scMain->run();
+ if (scMain && !scMain->finished())
+ scMain->run();
}
void
@@ -348,7 +355,8 @@
clear();
runOnce = false;
- scMain->run();
+ if (scMain && !scMain->finished())
+ scMain->run();
}
void
@@ -385,6 +393,12 @@
deschedule(&maxTickEvent);
if (starvationEvent.scheduled())
deschedule(&starvationEvent);
+
+ if (_throwToScMain) {
+ const ::sc_core::sc_report *to_throw = _throwToScMain;
+ _throwToScMain = nullptr;
+ throw *to_throw;
+ }
}
void
@@ -405,6 +419,15 @@
}
void
+Scheduler::throwToScMain(const ::sc_core::sc_report *r)
+{
+ if (!r)
+ r = reportifyException();
+ _throwToScMain = r;
+ scMain->run();
+}
+
+void
Scheduler::scheduleStop(bool finish_delta)
{
if (stopEvent.scheduled())
@@ -421,4 +444,46 @@
Scheduler scheduler;
+namespace {
+
+void
+throwingReportHandler(const ::sc_core::sc_report &r,
+ const ::sc_core::sc_actions &)
+{
+ throw r;
+}
+
+} // anonymous namespace
+
+const ::sc_core::sc_report *
+reportifyException()
+{
+ ::sc_core::sc_report_handler_proc old_handler =
+ ::sc_core::sc_report_handler::get_handler();
+ ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
+
+ try {
+ try {
+ // Rethrow the current exception so we can catch it and throw
an
+ // sc_report instead if it's not a type we recognize/can
handle.
+ throw;
+ } catch (const ::sc_core::sc_report &) {
+ // It's already a sc_report, so nothing to do.
+ throw;
+ } catch (const ::sc_core::sc_unwind_exception &) {
+ panic("Kill/reset exception escaped a Process::run()");
+ } catch (const std::exception &e) {
+ SC_REPORT_ERROR("uncaught exception", e.what());
+ } catch (const char *msg) {
+ SC_REPORT_ERROR("uncaught exception", msg);
+ } catch (...) {
+ SC_REPORT_ERROR("uncaught exception", "UNKNOWN EXCEPTION");
+ }
+ } catch (const ::sc_core::sc_report &r) {
+ ::sc_core::sc_report_handler::set_handler(old_handler);
+ return &r;
+ }
+ panic("No exception thrown in reportifyException.");
+}
+
} // namespace sc_gem5
diff --git a/src/systemc/core/scheduler.hh b/src/systemc/core/scheduler.hh
index 29501bc..dda483f 100644
--- a/src/systemc/core/scheduler.hh
+++ b/src/systemc/core/scheduler.hh
@@ -333,6 +333,8 @@
uint64_t changeStamp() { return _changeStamp; }
+ void throwToScMain(const ::sc_core::sc_report *r=nullptr);
+
private:
typedef const EventBase::Priority Priority;
static Priority DefaultPriority = EventBase::Default_Pri;
@@ -377,7 +379,9 @@
void stop();
EventWrapper<Scheduler, &Scheduler::pause> pauseEvent;
EventWrapper<Scheduler, &Scheduler::stop> stopEvent;
+
Fiber *scMain;
+ const ::sc_core::sc_report *_throwToScMain;
bool
starved()
@@ -437,6 +441,8 @@
scheduler.completeTimeSlot(this);
}
+const ::sc_core::sc_report *reportifyException();
+
} // namespace sc_gem5
#endif // __SYSTEMC_CORE_SCHEDULER_H__
diff --git a/src/systemc/ext/utils/sc_report_handler.hh
b/src/systemc/ext/utils/sc_report_handler.hh
index f65b32c..6ce20af 100644
--- a/src/systemc/ext/utils/sc_report_handler.hh
+++ b/src/systemc/ext/utils/sc_report_handler.hh
@@ -105,6 +105,10 @@
static void set_handler(sc_report_handler_proc);
static void default_handler(const sc_report &, const sc_actions &);
static sc_actions get_new_action_id();
+ // Nonstandard
+ // Returns the current handler so it can be restored if it needs to be
+ // changed temporarily.
+ static sc_report_handler_proc get_handler();
static sc_report *get_cached_report();
static void clear_cached_report();
diff --git a/src/systemc/tests/config.py b/src/systemc/tests/config.py
index 439a682..d9ae749 100755
--- a/src/systemc/tests/config.py
+++ b/src/systemc/tests/config.py
@@ -31,6 +31,7 @@
import m5
import os
import re
+import sys
from m5.objects import SystemC_Kernel, Root
@@ -58,7 +59,5 @@
# generate errors, and as long as their output matches that's still
# considered correct. A "real" systemc config should expect sc_main
# (if present) not to fail.
- scrubbed = re.sub(r'In file: .*$',
- 'In file: <removed by verify.pl>',
- result.message)
- print('\n' + scrubbed)
+ print('\n' + result.message)
+ sys.exit(int(result.code))
diff --git a/src/systemc/utils/sc_report_handler.cc
b/src/systemc/utils/sc_report_handler.cc
index e08ad66..1ca9d97 100644
--- a/src/systemc/utils/sc_report_handler.cc
+++ b/src/systemc/utils/sc_report_handler.cc
@@ -341,6 +341,12 @@
return maxAction;
}
+sc_report_handler_proc
+sc_report_handler::get_handler()
+{
+ return reportHandlerProc;
+}
+
sc_report *
sc_report_handler::get_cached_report()
{
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/12601
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-Change-Id: I7130d53a98fadd137073d1718f780f32f57c658c
Gerrit-Change-Number: 12601
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev