scheduler.cc (13244:deedec45898f) scheduler.cc (13245:c666c5d4996b)
1/*
2 * Copyright 2018 Google, Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met: redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer;
8 * redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution;
11 * neither the name of the copyright holders nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * Authors: Gabe Black
28 */
29
30#include "systemc/core/scheduler.hh"
31
32#include "base/fiber.hh"
33#include "base/logging.hh"
34#include "sim/eventq.hh"
35#include "systemc/core/kernel.hh"
36#include "systemc/ext/core/sc_main.hh"
37#include "systemc/ext/utils/sc_report.hh"
38#include "systemc/ext/utils/sc_report_handler.hh"
1/*
2 * Copyright 2018 Google, Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met: redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer;
8 * redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution;
11 * neither the name of the copyright holders nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * Authors: Gabe Black
28 */
29
30#include "systemc/core/scheduler.hh"
31
32#include "base/fiber.hh"
33#include "base/logging.hh"
34#include "sim/eventq.hh"
35#include "systemc/core/kernel.hh"
36#include "systemc/ext/core/sc_main.hh"
37#include "systemc/ext/utils/sc_report.hh"
38#include "systemc/ext/utils/sc_report_handler.hh"
39#include "systemc/utils/tracefile.hh"
39
40namespace sc_gem5
41{
42
43Scheduler::Scheduler() :
44 eq(nullptr), readyEvent(this, false, ReadyPriority),
45 pauseEvent(this, false, PausePriority),
46 stopEvent(this, false, StopPriority),
47 scMain(nullptr), _throwToScMain(nullptr),
48 starvationEvent(this, false, StarvationPriority),
49 _elaborationDone(false), _started(false), _stopNow(false),
50 _status(StatusOther), maxTickEvent(this, false, MaxTickPriority),
40
41namespace sc_gem5
42{
43
44Scheduler::Scheduler() :
45 eq(nullptr), readyEvent(this, false, ReadyPriority),
46 pauseEvent(this, false, PausePriority),
47 stopEvent(this, false, StopPriority),
48 scMain(nullptr), _throwToScMain(nullptr),
49 starvationEvent(this, false, StarvationPriority),
50 _elaborationDone(false), _started(false), _stopNow(false),
51 _status(StatusOther), maxTickEvent(this, false, MaxTickPriority),
51 _numCycles(0), _changeStamp(0), _current(nullptr), initDone(false),
52 runOnce(false)
52 timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0),
53 _changeStamp(0), _current(nullptr), initDone(false), runOnce(false)
53{}
54
55Scheduler::~Scheduler()
56{
57 // Clear out everything that belongs to us to make sure nobody tries to
58 // clear themselves out after the scheduler goes away.
59 clear();
60}
61
62void
63Scheduler::clear()
64{
65 // Delta notifications.
66 while (!deltas.empty())
67 deltas.front()->deschedule();
68
69 // Timed notifications.
70 for (auto &tsp: timeSlots) {
71 TimeSlot *&ts = tsp.second;
72 while (!ts->events.empty())
73 ts->events.front()->deschedule();
74 deschedule(ts);
75 }
76 timeSlots.clear();
77
78 // gem5 events.
79 if (readyEvent.scheduled())
80 deschedule(&readyEvent);
81 if (pauseEvent.scheduled())
82 deschedule(&pauseEvent);
83 if (stopEvent.scheduled())
84 deschedule(&stopEvent);
85 if (starvationEvent.scheduled())
86 deschedule(&starvationEvent);
87 if (maxTickEvent.scheduled())
88 deschedule(&maxTickEvent);
54{}
55
56Scheduler::~Scheduler()
57{
58 // Clear out everything that belongs to us to make sure nobody tries to
59 // clear themselves out after the scheduler goes away.
60 clear();
61}
62
63void
64Scheduler::clear()
65{
66 // Delta notifications.
67 while (!deltas.empty())
68 deltas.front()->deschedule();
69
70 // Timed notifications.
71 for (auto &tsp: timeSlots) {
72 TimeSlot *&ts = tsp.second;
73 while (!ts->events.empty())
74 ts->events.front()->deschedule();
75 deschedule(ts);
76 }
77 timeSlots.clear();
78
79 // gem5 events.
80 if (readyEvent.scheduled())
81 deschedule(&readyEvent);
82 if (pauseEvent.scheduled())
83 deschedule(&pauseEvent);
84 if (stopEvent.scheduled())
85 deschedule(&stopEvent);
86 if (starvationEvent.scheduled())
87 deschedule(&starvationEvent);
88 if (maxTickEvent.scheduled())
89 deschedule(&maxTickEvent);
90 if (timeAdvancesEvent.scheduled())
91 deschedule(&timeAdvancesEvent);
89
90 Process *p;
91 while ((p = initList.getNext()))
92 p->popListNode();
93 while ((p = readyListMethods.getNext()))
94 p->popListNode();
95 while ((p = readyListThreads.getNext()))
96 p->popListNode();
97
98 Channel *c;
99 while ((c = updateList.getNext()))
100 c->popListNode();
101}
102
103void
104Scheduler::initPhase()
105{
106 for (Process *p = initList.getNext(); p; p = initList.getNext()) {
107 p->popListNode();
108
109 if (p->dontInitialize()) {
110 if (!p->hasStaticSensitivities() && !p->internal()) {
111 SC_REPORT_WARNING(
112 "(W558) disable() or dont_initialize() called on "
113 "process with no static sensitivity, it will be "
114 "orphaned", p->name());
115 }
116 } else {
117 p->ready();
118 }
119 }
120
121 runUpdate();
122 runDelta();
123
124 for (auto ets: eventsToSchedule)
125 eq->schedule(ets.first, ets.second);
126 eventsToSchedule.clear();
127
128 if (_started) {
129 if (!runToTime && starved())
130 scheduleStarvationEvent();
131 kernel->status(::sc_core::SC_RUNNING);
132 }
133
134 initDone = true;
135
136 status(StatusOther);
92
93 Process *p;
94 while ((p = initList.getNext()))
95 p->popListNode();
96 while ((p = readyListMethods.getNext()))
97 p->popListNode();
98 while ((p = readyListThreads.getNext()))
99 p->popListNode();
100
101 Channel *c;
102 while ((c = updateList.getNext()))
103 c->popListNode();
104}
105
106void
107Scheduler::initPhase()
108{
109 for (Process *p = initList.getNext(); p; p = initList.getNext()) {
110 p->popListNode();
111
112 if (p->dontInitialize()) {
113 if (!p->hasStaticSensitivities() && !p->internal()) {
114 SC_REPORT_WARNING(
115 "(W558) disable() or dont_initialize() called on "
116 "process with no static sensitivity, it will be "
117 "orphaned", p->name());
118 }
119 } else {
120 p->ready();
121 }
122 }
123
124 runUpdate();
125 runDelta();
126
127 for (auto ets: eventsToSchedule)
128 eq->schedule(ets.first, ets.second);
129 eventsToSchedule.clear();
130
131 if (_started) {
132 if (!runToTime && starved())
133 scheduleStarvationEvent();
134 kernel->status(::sc_core::SC_RUNNING);
135 }
136
137 initDone = true;
138
139 status(StatusOther);
140
141 scheduleTimeAdvancesEvent();
137}
138
139void
140Scheduler::reg(Process *p)
141{
142 if (initDone) {
143 // If not marked as dontInitialize, mark as ready.
144 if (!p->dontInitialize())
145 p->ready();
146 } else {
147 // Otherwise, record that this process should be initialized once we
148 // get there.
149 initList.pushLast(p);
150 }
151}
152
153void
154Scheduler::yield()
155{
156 // Pull a process from the active list.
157 _current = getNextReady();
158 if (!_current) {
159 // There are no more processes, so return control to evaluate.
160 Fiber::primaryFiber()->run();
161 } else {
162 _current->popListNode();
163 // Switch to whatever Fiber is supposed to run this process. All
164 // Fibers which aren't running should be parked at this line.
165 _current->fiber()->run();
166 // If the current process needs to be manually started, start it.
167 if (_current && _current->needsStart()) {
168 _current->needsStart(false);
169 try {
170 _current->run();
171 } catch (...) {
172 throwToScMain();
173 }
174 }
175 }
176 if (_current && _current->excWrapper) {
177 // Make sure this isn't a method process.
178 assert(!_current->needsStart());
179 auto ew = _current->excWrapper;
180 _current->excWrapper = nullptr;
181 ew->throw_it();
182 }
183}
184
185void
186Scheduler::ready(Process *p)
187{
188 if (_stopNow)
189 return;
190
191 if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
192 readyListMethods.pushLast(p);
193 else
194 readyListThreads.pushLast(p);
195
196 if (!inEvaluate())
197 scheduleReadyEvent();
198}
199
200void
201Scheduler::resume(Process *p)
202{
203 if (initDone)
204 ready(p);
205 else
206 initList.pushLast(p);
207}
208
209bool
210listContains(ListNode *list, ListNode *target)
211{
212 ListNode *n = list->nextListNode;
213 while (n != list)
214 if (n == target)
215 return true;
216 return false;
217}
218
219bool
220Scheduler::suspend(Process *p)
221{
222 bool was_ready;
223 if (initDone) {
224 // After initialization, check if we're on a ready list.
225 was_ready = (p->nextListNode != nullptr);
226 p->popListNode();
227 } else {
228 // Nothing is ready before init.
229 was_ready = false;
230 }
231 return was_ready;
232}
233
234void
235Scheduler::requestUpdate(Channel *c)
236{
237 updateList.pushLast(c);
238 if (!inEvaluate())
239 scheduleReadyEvent();
240}
241
242void
243Scheduler::scheduleReadyEvent()
244{
245 // Schedule the evaluate and update phases.
246 if (!readyEvent.scheduled()) {
247 schedule(&readyEvent);
248 if (starvationEvent.scheduled())
249 deschedule(&starvationEvent);
250 }
251}
252
253void
254Scheduler::scheduleStarvationEvent()
255{
256 if (!starvationEvent.scheduled()) {
257 schedule(&starvationEvent);
258 if (readyEvent.scheduled())
259 deschedule(&readyEvent);
260 }
261}
262
263void
264Scheduler::runReady()
265{
142}
143
144void
145Scheduler::reg(Process *p)
146{
147 if (initDone) {
148 // If not marked as dontInitialize, mark as ready.
149 if (!p->dontInitialize())
150 p->ready();
151 } else {
152 // Otherwise, record that this process should be initialized once we
153 // get there.
154 initList.pushLast(p);
155 }
156}
157
158void
159Scheduler::yield()
160{
161 // Pull a process from the active list.
162 _current = getNextReady();
163 if (!_current) {
164 // There are no more processes, so return control to evaluate.
165 Fiber::primaryFiber()->run();
166 } else {
167 _current->popListNode();
168 // Switch to whatever Fiber is supposed to run this process. All
169 // Fibers which aren't running should be parked at this line.
170 _current->fiber()->run();
171 // If the current process needs to be manually started, start it.
172 if (_current && _current->needsStart()) {
173 _current->needsStart(false);
174 try {
175 _current->run();
176 } catch (...) {
177 throwToScMain();
178 }
179 }
180 }
181 if (_current && _current->excWrapper) {
182 // Make sure this isn't a method process.
183 assert(!_current->needsStart());
184 auto ew = _current->excWrapper;
185 _current->excWrapper = nullptr;
186 ew->throw_it();
187 }
188}
189
190void
191Scheduler::ready(Process *p)
192{
193 if (_stopNow)
194 return;
195
196 if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
197 readyListMethods.pushLast(p);
198 else
199 readyListThreads.pushLast(p);
200
201 if (!inEvaluate())
202 scheduleReadyEvent();
203}
204
205void
206Scheduler::resume(Process *p)
207{
208 if (initDone)
209 ready(p);
210 else
211 initList.pushLast(p);
212}
213
214bool
215listContains(ListNode *list, ListNode *target)
216{
217 ListNode *n = list->nextListNode;
218 while (n != list)
219 if (n == target)
220 return true;
221 return false;
222}
223
224bool
225Scheduler::suspend(Process *p)
226{
227 bool was_ready;
228 if (initDone) {
229 // After initialization, check if we're on a ready list.
230 was_ready = (p->nextListNode != nullptr);
231 p->popListNode();
232 } else {
233 // Nothing is ready before init.
234 was_ready = false;
235 }
236 return was_ready;
237}
238
239void
240Scheduler::requestUpdate(Channel *c)
241{
242 updateList.pushLast(c);
243 if (!inEvaluate())
244 scheduleReadyEvent();
245}
246
247void
248Scheduler::scheduleReadyEvent()
249{
250 // Schedule the evaluate and update phases.
251 if (!readyEvent.scheduled()) {
252 schedule(&readyEvent);
253 if (starvationEvent.scheduled())
254 deschedule(&starvationEvent);
255 }
256}
257
258void
259Scheduler::scheduleStarvationEvent()
260{
261 if (!starvationEvent.scheduled()) {
262 schedule(&starvationEvent);
263 if (readyEvent.scheduled())
264 deschedule(&readyEvent);
265 }
266}
267
268void
269Scheduler::runReady()
270{
271 scheduleTimeAdvancesEvent();
272
266 bool empty = readyListMethods.empty() && readyListThreads.empty();
267 lastReadyTick = getCurTick();
268
269 // The evaluation phase.
273 bool empty = readyListMethods.empty() && readyListThreads.empty();
274 lastReadyTick = getCurTick();
275
276 // The evaluation phase.
277 status(StatusEvaluate);
270 do {
271 yield();
272 } while (getNextReady());
273
274 if (!empty) {
275 _numCycles++;
276 _changeStamp++;
277 }
278
279 if (_stopNow) {
280 status(StatusOther);
281 return;
282 }
283
284 runUpdate();
278 do {
279 yield();
280 } while (getNextReady());
281
282 if (!empty) {
283 _numCycles++;
284 _changeStamp++;
285 }
286
287 if (_stopNow) {
288 status(StatusOther);
289 return;
290 }
291
292 runUpdate();
293 if (!traceFiles.empty())
294 trace(true);
285 runDelta();
286
287 if (!runToTime && starved())
288 scheduleStarvationEvent();
289
290 if (runOnce)
291 schedulePause();
292
293 status(StatusOther);
294}
295
296void
297Scheduler::runUpdate()
298{
299 status(StatusUpdate);
300
301 try {
302 Channel *channel = updateList.getNext();
303 while (channel) {
304 channel->popListNode();
305 channel->update();
306 channel = updateList.getNext();
307 }
308 } catch (...) {
309 throwToScMain();
310 }
311}
312
313void
314Scheduler::runDelta()
315{
316 status(StatusDelta);
317
318 try {
319 while (!deltas.empty())
320 deltas.front()->run();
321 } catch (...) {
322 throwToScMain();
323 }
324}
325
326void
327Scheduler::pause()
328{
329 status(StatusPaused);
330 kernel->status(::sc_core::SC_PAUSED);
331 runOnce = false;
332 if (scMain && !scMain->finished())
333 scMain->run();
334}
335
336void
337Scheduler::stop()
338{
339 status(StatusStopped);
340 kernel->stop();
341
342 clear();
343
344 runOnce = false;
345 if (scMain && !scMain->finished())
346 scMain->run();
347}
348
349void
350Scheduler::start(Tick max_tick, bool run_to_time)
351{
352 // We should be running from sc_main. Keep track of that Fiber to return
353 // to later.
354 scMain = Fiber::currentFiber();
355
356 _started = true;
357 status(StatusOther);
358 runToTime = run_to_time;
359
360 maxTick = max_tick;
361 lastReadyTick = getCurTick();
362
363 if (initDone) {
364 if (!runToTime && starved())
365 scheduleStarvationEvent();
366 kernel->status(::sc_core::SC_RUNNING);
367 }
368
369 schedule(&maxTickEvent, maxTick);
295 runDelta();
296
297 if (!runToTime && starved())
298 scheduleStarvationEvent();
299
300 if (runOnce)
301 schedulePause();
302
303 status(StatusOther);
304}
305
306void
307Scheduler::runUpdate()
308{
309 status(StatusUpdate);
310
311 try {
312 Channel *channel = updateList.getNext();
313 while (channel) {
314 channel->popListNode();
315 channel->update();
316 channel = updateList.getNext();
317 }
318 } catch (...) {
319 throwToScMain();
320 }
321}
322
323void
324Scheduler::runDelta()
325{
326 status(StatusDelta);
327
328 try {
329 while (!deltas.empty())
330 deltas.front()->run();
331 } catch (...) {
332 throwToScMain();
333 }
334}
335
336void
337Scheduler::pause()
338{
339 status(StatusPaused);
340 kernel->status(::sc_core::SC_PAUSED);
341 runOnce = false;
342 if (scMain && !scMain->finished())
343 scMain->run();
344}
345
346void
347Scheduler::stop()
348{
349 status(StatusStopped);
350 kernel->stop();
351
352 clear();
353
354 runOnce = false;
355 if (scMain && !scMain->finished())
356 scMain->run();
357}
358
359void
360Scheduler::start(Tick max_tick, bool run_to_time)
361{
362 // We should be running from sc_main. Keep track of that Fiber to return
363 // to later.
364 scMain = Fiber::currentFiber();
365
366 _started = true;
367 status(StatusOther);
368 runToTime = run_to_time;
369
370 maxTick = max_tick;
371 lastReadyTick = getCurTick();
372
373 if (initDone) {
374 if (!runToTime && starved())
375 scheduleStarvationEvent();
376 kernel->status(::sc_core::SC_RUNNING);
377 }
378
379 schedule(&maxTickEvent, maxTick);
380 scheduleTimeAdvancesEvent();
370
371 // Return to gem5 to let it run events, etc.
372 Fiber::primaryFiber()->run();
373
374 if (pauseEvent.scheduled())
375 deschedule(&pauseEvent);
376 if (stopEvent.scheduled())
377 deschedule(&stopEvent);
378 if (maxTickEvent.scheduled())
379 deschedule(&maxTickEvent);
380 if (starvationEvent.scheduled())
381 deschedule(&starvationEvent);
382
383 if (_throwToScMain) {
384 const ::sc_core::sc_report *to_throw = _throwToScMain;
385 _throwToScMain = nullptr;
386 throw *to_throw;
387 }
388}
389
390void
391Scheduler::oneCycle()
392{
393 runOnce = true;
394 scheduleReadyEvent();
395 start(::MaxTick, false);
396}
397
398void
399Scheduler::schedulePause()
400{
401 if (pauseEvent.scheduled())
402 return;
403
404 schedule(&pauseEvent);
405}
406
407void
408Scheduler::throwToScMain(const ::sc_core::sc_report *r)
409{
410 if (!r)
411 r = reportifyException();
412 _throwToScMain = r;
413 status(StatusOther);
414 scMain->run();
415}
416
417void
418Scheduler::scheduleStop(bool finish_delta)
419{
420 if (stopEvent.scheduled())
421 return;
422
423 if (!finish_delta) {
424 _stopNow = true;
425 // If we're not supposed to finish the delta cycle, flush all
426 // pending activity.
427 clear();
428 }
429 schedule(&stopEvent);
430}
431
381
382 // Return to gem5 to let it run events, etc.
383 Fiber::primaryFiber()->run();
384
385 if (pauseEvent.scheduled())
386 deschedule(&pauseEvent);
387 if (stopEvent.scheduled())
388 deschedule(&stopEvent);
389 if (maxTickEvent.scheduled())
390 deschedule(&maxTickEvent);
391 if (starvationEvent.scheduled())
392 deschedule(&starvationEvent);
393
394 if (_throwToScMain) {
395 const ::sc_core::sc_report *to_throw = _throwToScMain;
396 _throwToScMain = nullptr;
397 throw *to_throw;
398 }
399}
400
401void
402Scheduler::oneCycle()
403{
404 runOnce = true;
405 scheduleReadyEvent();
406 start(::MaxTick, false);
407}
408
409void
410Scheduler::schedulePause()
411{
412 if (pauseEvent.scheduled())
413 return;
414
415 schedule(&pauseEvent);
416}
417
418void
419Scheduler::throwToScMain(const ::sc_core::sc_report *r)
420{
421 if (!r)
422 r = reportifyException();
423 _throwToScMain = r;
424 status(StatusOther);
425 scMain->run();
426}
427
428void
429Scheduler::scheduleStop(bool finish_delta)
430{
431 if (stopEvent.scheduled())
432 return;
433
434 if (!finish_delta) {
435 _stopNow = true;
436 // If we're not supposed to finish the delta cycle, flush all
437 // pending activity.
438 clear();
439 }
440 schedule(&stopEvent);
441}
442
443void
444Scheduler::trace(bool delta)
445{
446 for (auto tf: traceFiles)
447 tf->trace(delta);
448}
449
432Scheduler scheduler;
433
434namespace {
435
436void
437throwingReportHandler(const ::sc_core::sc_report &r,
438 const ::sc_core::sc_actions &)
439{
440 throw r;
441}
442
443} // anonymous namespace
444
445const ::sc_core::sc_report *
446reportifyException()
447{
448 ::sc_core::sc_report_handler_proc old_handler =
449 ::sc_core::sc_report_handler::get_handler();
450 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
451
452 try {
453 try {
454 // Rethrow the current exception so we can catch it and throw an
455 // sc_report instead if it's not a type we recognize/can handle.
456 throw;
457 } catch (const ::sc_core::sc_report &) {
458 // It's already a sc_report, so nothing to do.
459 throw;
460 } catch (const ::sc_core::sc_unwind_exception &) {
461 panic("Kill/reset exception escaped a Process::run()");
462 } catch (const std::exception &e) {
463 SC_REPORT_ERROR("uncaught exception", e.what());
464 } catch (const char *msg) {
465 SC_REPORT_ERROR("uncaught exception", msg);
466 } catch (...) {
467 SC_REPORT_ERROR("uncaught exception", "UNKNOWN EXCEPTION");
468 }
469 } catch (const ::sc_core::sc_report &r) {
470 ::sc_core::sc_report_handler::set_handler(old_handler);
471 return &r;
472 }
473 panic("No exception thrown in reportifyException.");
474}
475
476} // namespace sc_gem5
450Scheduler scheduler;
451
452namespace {
453
454void
455throwingReportHandler(const ::sc_core::sc_report &r,
456 const ::sc_core::sc_actions &)
457{
458 throw r;
459}
460
461} // anonymous namespace
462
463const ::sc_core::sc_report *
464reportifyException()
465{
466 ::sc_core::sc_report_handler_proc old_handler =
467 ::sc_core::sc_report_handler::get_handler();
468 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
469
470 try {
471 try {
472 // Rethrow the current exception so we can catch it and throw an
473 // sc_report instead if it's not a type we recognize/can handle.
474 throw;
475 } catch (const ::sc_core::sc_report &) {
476 // It's already a sc_report, so nothing to do.
477 throw;
478 } catch (const ::sc_core::sc_unwind_exception &) {
479 panic("Kill/reset exception escaped a Process::run()");
480 } catch (const std::exception &e) {
481 SC_REPORT_ERROR("uncaught exception", e.what());
482 } catch (const char *msg) {
483 SC_REPORT_ERROR("uncaught exception", msg);
484 } catch (...) {
485 SC_REPORT_ERROR("uncaught exception", "UNKNOWN EXCEPTION");
486 }
487 } catch (const ::sc_core::sc_report &r) {
488 ::sc_core::sc_report_handler::set_handler(old_handler);
489 return &r;
490 }
491 panic("No exception thrown in reportifyException.");
492}
493
494} // namespace sc_gem5