summaryrefslogtreecommitdiff
path: root/src/systemc/core/scheduler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemc/core/scheduler.cc')
-rw-r--r--src/systemc/core/scheduler.cc73
1 files changed, 69 insertions, 4 deletions
diff --git a/src/systemc/core/scheduler.cc b/src/systemc/core/scheduler.cc
index 4c98b68aa..5348e6665 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 @@ Scheduler::Scheduler() :
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 @@ Scheduler::yield()
// 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 @@ Scheduler::pause()
_paused = true;
kernel->status(::sc_core::SC_PAUSED);
runOnce = false;
- scMain->run();
+ if (scMain && !scMain->finished())
+ scMain->run();
}
void
@@ -348,7 +355,8 @@ Scheduler::stop()
clear();
runOnce = false;
- scMain->run();
+ if (scMain && !scMain->finished())
+ scMain->run();
}
void
@@ -385,6 +393,12 @@ Scheduler::start(Tick max_tick, bool run_to_time)
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 @@ Scheduler::schedulePause()
}
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::scheduleStop(bool finish_delta)
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