scheduler.cc (13703:bedf6da29c9b) scheduler.cc (13901:b9329102b1d8)
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 "sim/sim_exit.hh"
36#include "systemc/core/kernel.hh"
37#include "systemc/core/sc_main_fiber.hh"
38#include "systemc/ext/core/messages.hh"
39#include "systemc/ext/core/sc_main.hh"
40#include "systemc/ext/utils/sc_report.hh"
41#include "systemc/ext/utils/sc_report_handler.hh"
42#include "systemc/utils/report.hh"
43#include "systemc/utils/tracefile.hh"
44
45namespace sc_gem5
46{
47
48Scheduler::Scheduler() :
49 eq(nullptr), readyEvent(this, false, ReadyPriority),
50 pauseEvent(this, false, PausePriority),
51 stopEvent(this, false, StopPriority), _throwUp(nullptr),
52 starvationEvent(this, false, StarvationPriority),
53 _elaborationDone(false), _started(false), _stopNow(false),
54 _status(StatusOther), maxTick(::MaxTick),
55 maxTickEvent(this, false, MaxTickPriority),
56 timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0),
57 _changeStamp(0), _current(nullptr), initDone(false), runToTime(true),
58 runOnce(false)
59{}
60
61Scheduler::~Scheduler()
62{
63 // Clear out everything that belongs to us to make sure nobody tries to
64 // clear themselves out after the scheduler goes away.
65 clear();
66}
67
68void
69Scheduler::clear()
70{
71 // Delta notifications.
72 while (!deltas.empty())
73 deltas.front()->deschedule();
74
75 // Timed notifications.
76 for (auto &tsp: timeSlots) {
77 TimeSlot *&ts = tsp.second;
78 while (!ts->events.empty())
79 ts->events.front()->deschedule();
80 deschedule(ts);
81 }
82 timeSlots.clear();
83
84 // gem5 events.
85 if (readyEvent.scheduled())
86 deschedule(&readyEvent);
87 if (pauseEvent.scheduled())
88 deschedule(&pauseEvent);
89 if (stopEvent.scheduled())
90 deschedule(&stopEvent);
91 if (starvationEvent.scheduled())
92 deschedule(&starvationEvent);
93 if (maxTickEvent.scheduled())
94 deschedule(&maxTickEvent);
95 if (timeAdvancesEvent.scheduled())
96 deschedule(&timeAdvancesEvent);
97
98 Process *p;
99 while ((p = initList.getNext()))
100 p->popListNode();
101 while ((p = readyListMethods.getNext()))
102 p->popListNode();
103 while ((p = readyListThreads.getNext()))
104 p->popListNode();
105
106 Channel *c;
107 while ((c = updateList.getNext()))
108 c->popListNode();
109}
110
111void
112Scheduler::initPhase()
113{
114 runUpdate();
115
116 for (Process *p = initList.getNext(); p; p = initList.getNext()) {
117 p->popListNode();
118
119 if (p->dontInitialize()) {
120 if (!p->hasStaticSensitivities() && !p->internal()) {
121 SC_REPORT_WARNING(sc_core::SC_ID_DISABLE_WILL_ORPHAN_PROCESS_,
122 p->name());
123 }
124 } else {
125 p->ready();
126 }
127 }
128
129 runDelta();
130
131 for (auto ets: eventsToSchedule)
132 eq->schedule(ets.first, ets.second);
133 eventsToSchedule.clear();
134
135 if (_started) {
136 if (!runToTime && starved())
137 scheduleStarvationEvent();
138 kernel->status(::sc_core::SC_RUNNING);
139 }
140
141 initDone = true;
142
143 status(StatusOther);
144
145 scheduleTimeAdvancesEvent();
146}
147
148void
149Scheduler::reg(Process *p)
150{
151 if (initDone) {
152 // If not marked as dontInitialize, mark as ready.
153 if (!p->dontInitialize())
154 p->ready();
155 } else {
156 // Otherwise, record that this process should be initialized once we
157 // get there.
158 initList.pushLast(p);
159 }
160}
161
162void
163Scheduler::yield()
164{
165 // Pull a process from the active list.
166 _current = getNextReady();
167 if (!_current) {
168 // There are no more processes, so return control to evaluate.
169 Fiber::primaryFiber()->run();
170 } else {
171 _current->popListNode();
172 _current->scheduled(false);
173 // Switch to whatever Fiber is supposed to run this process. All
174 // Fibers which aren't running should be parked at this line.
175 _current->fiber()->run();
176 // If the current process needs to be manually started, start it.
177 if (_current && _current->needsStart()) {
178 _current->needsStart(false);
179 // If a process hasn't started yet, "resetting" it just starts it
180 // and signals its reset event.
181 if (_current->inReset())
182 _current->resetEvent().notify();
183 try {
184 _current->run();
185 } catch (...) {
186 throwUp();
187 }
188 }
189 }
190 if (_current && !_current->needsStart()) {
191 if (_current->excWrapper) {
192 auto ew = _current->excWrapper;
193 _current->excWrapper = nullptr;
194 ew->throw_it();
195 } else if (_current->inReset()) {
196 _current->reset(false);
197 }
198 }
199}
200
201void
202Scheduler::ready(Process *p)
203{
204 if (_stopNow)
205 return;
206
207 p->scheduled(true);
208
209 if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
210 readyListMethods.pushLast(p);
211 else
212 readyListThreads.pushLast(p);
213
214 if (!inEvaluate())
215 scheduleReadyEvent();
216}
217
218void
219Scheduler::resume(Process *p)
220{
221 if (initDone)
222 ready(p);
223 else
224 initList.pushLast(p);
225}
226
227bool
228listContains(ListNode *list, ListNode *target)
229{
230 ListNode *n = list->nextListNode;
231 while (n != list)
232 if (n == target)
233 return true;
234 return false;
235}
236
237bool
238Scheduler::suspend(Process *p)
239{
240 bool was_ready;
241 if (initDone) {
242 // After initialization, check if we're on a ready list.
243 was_ready = (p->nextListNode != nullptr);
244 p->popListNode();
245 } else {
246 // Nothing is ready before init.
247 was_ready = false;
248 }
249 return was_ready;
250}
251
252void
253Scheduler::requestUpdate(Channel *c)
254{
255 updateList.pushLast(c);
256 if (!inEvaluate())
257 scheduleReadyEvent();
258}
259
260void
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 "sim/sim_exit.hh"
36#include "systemc/core/kernel.hh"
37#include "systemc/core/sc_main_fiber.hh"
38#include "systemc/ext/core/messages.hh"
39#include "systemc/ext/core/sc_main.hh"
40#include "systemc/ext/utils/sc_report.hh"
41#include "systemc/ext/utils/sc_report_handler.hh"
42#include "systemc/utils/report.hh"
43#include "systemc/utils/tracefile.hh"
44
45namespace sc_gem5
46{
47
48Scheduler::Scheduler() :
49 eq(nullptr), readyEvent(this, false, ReadyPriority),
50 pauseEvent(this, false, PausePriority),
51 stopEvent(this, false, StopPriority), _throwUp(nullptr),
52 starvationEvent(this, false, StarvationPriority),
53 _elaborationDone(false), _started(false), _stopNow(false),
54 _status(StatusOther), maxTick(::MaxTick),
55 maxTickEvent(this, false, MaxTickPriority),
56 timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0),
57 _changeStamp(0), _current(nullptr), initDone(false), runToTime(true),
58 runOnce(false)
59{}
60
61Scheduler::~Scheduler()
62{
63 // Clear out everything that belongs to us to make sure nobody tries to
64 // clear themselves out after the scheduler goes away.
65 clear();
66}
67
68void
69Scheduler::clear()
70{
71 // Delta notifications.
72 while (!deltas.empty())
73 deltas.front()->deschedule();
74
75 // Timed notifications.
76 for (auto &tsp: timeSlots) {
77 TimeSlot *&ts = tsp.second;
78 while (!ts->events.empty())
79 ts->events.front()->deschedule();
80 deschedule(ts);
81 }
82 timeSlots.clear();
83
84 // gem5 events.
85 if (readyEvent.scheduled())
86 deschedule(&readyEvent);
87 if (pauseEvent.scheduled())
88 deschedule(&pauseEvent);
89 if (stopEvent.scheduled())
90 deschedule(&stopEvent);
91 if (starvationEvent.scheduled())
92 deschedule(&starvationEvent);
93 if (maxTickEvent.scheduled())
94 deschedule(&maxTickEvent);
95 if (timeAdvancesEvent.scheduled())
96 deschedule(&timeAdvancesEvent);
97
98 Process *p;
99 while ((p = initList.getNext()))
100 p->popListNode();
101 while ((p = readyListMethods.getNext()))
102 p->popListNode();
103 while ((p = readyListThreads.getNext()))
104 p->popListNode();
105
106 Channel *c;
107 while ((c = updateList.getNext()))
108 c->popListNode();
109}
110
111void
112Scheduler::initPhase()
113{
114 runUpdate();
115
116 for (Process *p = initList.getNext(); p; p = initList.getNext()) {
117 p->popListNode();
118
119 if (p->dontInitialize()) {
120 if (!p->hasStaticSensitivities() && !p->internal()) {
121 SC_REPORT_WARNING(sc_core::SC_ID_DISABLE_WILL_ORPHAN_PROCESS_,
122 p->name());
123 }
124 } else {
125 p->ready();
126 }
127 }
128
129 runDelta();
130
131 for (auto ets: eventsToSchedule)
132 eq->schedule(ets.first, ets.second);
133 eventsToSchedule.clear();
134
135 if (_started) {
136 if (!runToTime && starved())
137 scheduleStarvationEvent();
138 kernel->status(::sc_core::SC_RUNNING);
139 }
140
141 initDone = true;
142
143 status(StatusOther);
144
145 scheduleTimeAdvancesEvent();
146}
147
148void
149Scheduler::reg(Process *p)
150{
151 if (initDone) {
152 // If not marked as dontInitialize, mark as ready.
153 if (!p->dontInitialize())
154 p->ready();
155 } else {
156 // Otherwise, record that this process should be initialized once we
157 // get there.
158 initList.pushLast(p);
159 }
160}
161
162void
163Scheduler::yield()
164{
165 // Pull a process from the active list.
166 _current = getNextReady();
167 if (!_current) {
168 // There are no more processes, so return control to evaluate.
169 Fiber::primaryFiber()->run();
170 } else {
171 _current->popListNode();
172 _current->scheduled(false);
173 // Switch to whatever Fiber is supposed to run this process. All
174 // Fibers which aren't running should be parked at this line.
175 _current->fiber()->run();
176 // If the current process needs to be manually started, start it.
177 if (_current && _current->needsStart()) {
178 _current->needsStart(false);
179 // If a process hasn't started yet, "resetting" it just starts it
180 // and signals its reset event.
181 if (_current->inReset())
182 _current->resetEvent().notify();
183 try {
184 _current->run();
185 } catch (...) {
186 throwUp();
187 }
188 }
189 }
190 if (_current && !_current->needsStart()) {
191 if (_current->excWrapper) {
192 auto ew = _current->excWrapper;
193 _current->excWrapper = nullptr;
194 ew->throw_it();
195 } else if (_current->inReset()) {
196 _current->reset(false);
197 }
198 }
199}
200
201void
202Scheduler::ready(Process *p)
203{
204 if (_stopNow)
205 return;
206
207 p->scheduled(true);
208
209 if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
210 readyListMethods.pushLast(p);
211 else
212 readyListThreads.pushLast(p);
213
214 if (!inEvaluate())
215 scheduleReadyEvent();
216}
217
218void
219Scheduler::resume(Process *p)
220{
221 if (initDone)
222 ready(p);
223 else
224 initList.pushLast(p);
225}
226
227bool
228listContains(ListNode *list, ListNode *target)
229{
230 ListNode *n = list->nextListNode;
231 while (n != list)
232 if (n == target)
233 return true;
234 return false;
235}
236
237bool
238Scheduler::suspend(Process *p)
239{
240 bool was_ready;
241 if (initDone) {
242 // After initialization, check if we're on a ready list.
243 was_ready = (p->nextListNode != nullptr);
244 p->popListNode();
245 } else {
246 // Nothing is ready before init.
247 was_ready = false;
248 }
249 return was_ready;
250}
251
252void
253Scheduler::requestUpdate(Channel *c)
254{
255 updateList.pushLast(c);
256 if (!inEvaluate())
257 scheduleReadyEvent();
258}
259
260void
261Scheduler::asyncRequestUpdate(Channel *c)
262{
263 std::lock_guard<std::mutex> lock(asyncListMutex);
264 asyncUpdateList.pushLast(c);
265}
266
267void
261Scheduler::scheduleReadyEvent()
262{
263 // Schedule the evaluate and update phases.
264 if (!readyEvent.scheduled()) {
265 schedule(&readyEvent);
266 if (starvationEvent.scheduled())
267 deschedule(&starvationEvent);
268 }
269}
270
271void
272Scheduler::scheduleStarvationEvent()
273{
274 if (!starvationEvent.scheduled()) {
275 schedule(&starvationEvent);
276 if (readyEvent.scheduled())
277 deschedule(&readyEvent);
278 }
279}
280
281void
282Scheduler::runReady()
283{
284 scheduleTimeAdvancesEvent();
285
286 bool empty = readyListMethods.empty() && readyListThreads.empty();
287 lastReadyTick = getCurTick();
288
289 // The evaluation phase.
290 status(StatusEvaluate);
291 do {
292 yield();
293 } while (getNextReady());
294 _current = nullptr;
295
296 if (!empty) {
297 _numCycles++;
298 _changeStamp++;
299 }
300
301 if (_stopNow) {
302 status(StatusOther);
303 return;
304 }
305
306 runUpdate();
307 if (!traceFiles.empty())
308 trace(true);
309 runDelta();
310
311 if (!runToTime && starved())
312 scheduleStarvationEvent();
313
314 if (runOnce)
315 schedulePause();
316
317 status(StatusOther);
318}
319
320void
321Scheduler::runUpdate()
322{
323 status(StatusUpdate);
268Scheduler::scheduleReadyEvent()
269{
270 // Schedule the evaluate and update phases.
271 if (!readyEvent.scheduled()) {
272 schedule(&readyEvent);
273 if (starvationEvent.scheduled())
274 deschedule(&starvationEvent);
275 }
276}
277
278void
279Scheduler::scheduleStarvationEvent()
280{
281 if (!starvationEvent.scheduled()) {
282 schedule(&starvationEvent);
283 if (readyEvent.scheduled())
284 deschedule(&readyEvent);
285 }
286}
287
288void
289Scheduler::runReady()
290{
291 scheduleTimeAdvancesEvent();
292
293 bool empty = readyListMethods.empty() && readyListThreads.empty();
294 lastReadyTick = getCurTick();
295
296 // The evaluation phase.
297 status(StatusEvaluate);
298 do {
299 yield();
300 } while (getNextReady());
301 _current = nullptr;
302
303 if (!empty) {
304 _numCycles++;
305 _changeStamp++;
306 }
307
308 if (_stopNow) {
309 status(StatusOther);
310 return;
311 }
312
313 runUpdate();
314 if (!traceFiles.empty())
315 trace(true);
316 runDelta();
317
318 if (!runToTime && starved())
319 scheduleStarvationEvent();
320
321 if (runOnce)
322 schedulePause();
323
324 status(StatusOther);
325}
326
327void
328Scheduler::runUpdate()
329{
330 status(StatusUpdate);
331 {
332 std::lock_guard<std::mutex> lock(asyncListMutex);
333 Channel *channel;
334 while ((channel = asyncUpdateList.getNext()) != nullptr)
335 updateList.pushLast(channel);
336 }
324
325 try {
326 Channel *channel = updateList.getNext();
327 while (channel) {
328 channel->popListNode();
329 channel->update();
330 channel = updateList.getNext();
331 }
332 } catch (...) {
333 throwUp();
334 }
335}
336
337void
338Scheduler::runDelta()
339{
340 status(StatusDelta);
341
342 try {
343 while (!deltas.empty())
344 deltas.back()->run();
345 } catch (...) {
346 throwUp();
347 }
348}
349
350void
351Scheduler::pause()
352{
353 status(StatusPaused);
354 kernel->status(::sc_core::SC_PAUSED);
355 runOnce = false;
356 if (scMainFiber.called()) {
357 if (!scMainFiber.finished())
358 scMainFiber.run();
359 } else {
360 if (scMainFiber.finished())
361 fatal("Pausing systemc after sc_main completed.");
362 else
363 exitSimLoopNow("systemc pause");
364 }
365}
366
367void
368Scheduler::stop()
369{
370 status(StatusStopped);
371 kernel->stop();
372
373 clear();
374
375 runOnce = false;
376 if (scMainFiber.called()) {
377 if (!scMainFiber.finished())
378 scMainFiber.run();
379 } else {
380 if (scMainFiber.finished())
381 fatal("Stopping systemc after sc_main completed.");
382 else
383 exitSimLoopNow("systemc stop");
384 }
385}
386
387void
388Scheduler::start(Tick max_tick, bool run_to_time)
389{
390 _started = true;
391 status(StatusOther);
392 runToTime = run_to_time;
393
394 maxTick = max_tick;
395 lastReadyTick = getCurTick();
396
397 if (initDone) {
398 if (!runToTime && starved())
399 scheduleStarvationEvent();
400 kernel->status(::sc_core::SC_RUNNING);
401 }
402
403 schedule(&maxTickEvent, maxTick);
404 scheduleTimeAdvancesEvent();
405
406 // Return to gem5 to let it run events, etc.
407 Fiber::primaryFiber()->run();
408
409 if (pauseEvent.scheduled())
410 deschedule(&pauseEvent);
411 if (stopEvent.scheduled())
412 deschedule(&stopEvent);
413 if (maxTickEvent.scheduled())
414 deschedule(&maxTickEvent);
415 if (starvationEvent.scheduled())
416 deschedule(&starvationEvent);
417
418 if (_throwUp) {
419 const ::sc_core::sc_report *to_throw = _throwUp;
420 _throwUp = nullptr;
421 throw *to_throw;
422 }
423}
424
425void
426Scheduler::oneCycle()
427{
428 runOnce = true;
429 scheduleReadyEvent();
430 start(::MaxTick, false);
431}
432
433void
434Scheduler::schedulePause()
435{
436 if (pauseEvent.scheduled())
437 return;
438
439 schedule(&pauseEvent);
440}
441
442void
443Scheduler::throwUp()
444{
445 if (scMainFiber.called() && !scMainFiber.finished()) {
446 ::sc_core::sc_report report = reportifyException();
447 _throwUp = &report;
448 status(StatusOther);
449 scMainFiber.run();
450 } else {
451 reportHandlerProc(reportifyException(),
452 ::sc_core::sc_report_handler::get_catch_actions());
453 }
454}
455
456void
457Scheduler::scheduleStop(bool finish_delta)
458{
459 if (stopEvent.scheduled())
460 return;
461
462 if (!finish_delta) {
463 _stopNow = true;
464 // If we're not supposed to finish the delta cycle, flush all
465 // pending activity.
466 clear();
467 }
468 schedule(&stopEvent);
469}
470
471void
472Scheduler::trace(bool delta)
473{
474 for (auto tf: traceFiles)
475 tf->trace(delta);
476}
477
478Scheduler scheduler;
479Process *getCurrentProcess() { return scheduler.current(); }
480
481namespace {
482
483void
484throwingReportHandler(const ::sc_core::sc_report &r,
485 const ::sc_core::sc_actions &)
486{
487 throw r;
488}
489
490} // anonymous namespace
491
492const ::sc_core::sc_report
493reportifyException()
494{
495 ::sc_core::sc_report_handler_proc old_handler = reportHandlerProc;
496 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
497
498 try {
499 try {
500 // Rethrow the current exception so we can catch it and throw an
501 // sc_report instead if it's not a type we recognize/can handle.
502 throw;
503 } catch (const ::sc_core::sc_report &) {
504 // It's already a sc_report, so nothing to do.
505 throw;
506 } catch (const ::sc_core::sc_unwind_exception &) {
507 panic("Kill/reset exception escaped a Process::run()");
508 } catch (const std::exception &e) {
509 SC_REPORT_ERROR(
510 sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_, e.what());
511 } catch (const char *msg) {
512 SC_REPORT_ERROR(
513 sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_, msg);
514 } catch (...) {
515 SC_REPORT_ERROR(
516 sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_,
517 "UNKNOWN EXCEPTION");
518 }
519 } catch (const ::sc_core::sc_report &r) {
520 ::sc_core::sc_report_handler::set_handler(old_handler);
521 return r;
522 }
523 panic("No exception thrown in reportifyException.");
524}
525
526} // namespace sc_gem5
337
338 try {
339 Channel *channel = updateList.getNext();
340 while (channel) {
341 channel->popListNode();
342 channel->update();
343 channel = updateList.getNext();
344 }
345 } catch (...) {
346 throwUp();
347 }
348}
349
350void
351Scheduler::runDelta()
352{
353 status(StatusDelta);
354
355 try {
356 while (!deltas.empty())
357 deltas.back()->run();
358 } catch (...) {
359 throwUp();
360 }
361}
362
363void
364Scheduler::pause()
365{
366 status(StatusPaused);
367 kernel->status(::sc_core::SC_PAUSED);
368 runOnce = false;
369 if (scMainFiber.called()) {
370 if (!scMainFiber.finished())
371 scMainFiber.run();
372 } else {
373 if (scMainFiber.finished())
374 fatal("Pausing systemc after sc_main completed.");
375 else
376 exitSimLoopNow("systemc pause");
377 }
378}
379
380void
381Scheduler::stop()
382{
383 status(StatusStopped);
384 kernel->stop();
385
386 clear();
387
388 runOnce = false;
389 if (scMainFiber.called()) {
390 if (!scMainFiber.finished())
391 scMainFiber.run();
392 } else {
393 if (scMainFiber.finished())
394 fatal("Stopping systemc after sc_main completed.");
395 else
396 exitSimLoopNow("systemc stop");
397 }
398}
399
400void
401Scheduler::start(Tick max_tick, bool run_to_time)
402{
403 _started = true;
404 status(StatusOther);
405 runToTime = run_to_time;
406
407 maxTick = max_tick;
408 lastReadyTick = getCurTick();
409
410 if (initDone) {
411 if (!runToTime && starved())
412 scheduleStarvationEvent();
413 kernel->status(::sc_core::SC_RUNNING);
414 }
415
416 schedule(&maxTickEvent, maxTick);
417 scheduleTimeAdvancesEvent();
418
419 // Return to gem5 to let it run events, etc.
420 Fiber::primaryFiber()->run();
421
422 if (pauseEvent.scheduled())
423 deschedule(&pauseEvent);
424 if (stopEvent.scheduled())
425 deschedule(&stopEvent);
426 if (maxTickEvent.scheduled())
427 deschedule(&maxTickEvent);
428 if (starvationEvent.scheduled())
429 deschedule(&starvationEvent);
430
431 if (_throwUp) {
432 const ::sc_core::sc_report *to_throw = _throwUp;
433 _throwUp = nullptr;
434 throw *to_throw;
435 }
436}
437
438void
439Scheduler::oneCycle()
440{
441 runOnce = true;
442 scheduleReadyEvent();
443 start(::MaxTick, false);
444}
445
446void
447Scheduler::schedulePause()
448{
449 if (pauseEvent.scheduled())
450 return;
451
452 schedule(&pauseEvent);
453}
454
455void
456Scheduler::throwUp()
457{
458 if (scMainFiber.called() && !scMainFiber.finished()) {
459 ::sc_core::sc_report report = reportifyException();
460 _throwUp = &report;
461 status(StatusOther);
462 scMainFiber.run();
463 } else {
464 reportHandlerProc(reportifyException(),
465 ::sc_core::sc_report_handler::get_catch_actions());
466 }
467}
468
469void
470Scheduler::scheduleStop(bool finish_delta)
471{
472 if (stopEvent.scheduled())
473 return;
474
475 if (!finish_delta) {
476 _stopNow = true;
477 // If we're not supposed to finish the delta cycle, flush all
478 // pending activity.
479 clear();
480 }
481 schedule(&stopEvent);
482}
483
484void
485Scheduler::trace(bool delta)
486{
487 for (auto tf: traceFiles)
488 tf->trace(delta);
489}
490
491Scheduler scheduler;
492Process *getCurrentProcess() { return scheduler.current(); }
493
494namespace {
495
496void
497throwingReportHandler(const ::sc_core::sc_report &r,
498 const ::sc_core::sc_actions &)
499{
500 throw r;
501}
502
503} // anonymous namespace
504
505const ::sc_core::sc_report
506reportifyException()
507{
508 ::sc_core::sc_report_handler_proc old_handler = reportHandlerProc;
509 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
510
511 try {
512 try {
513 // Rethrow the current exception so we can catch it and throw an
514 // sc_report instead if it's not a type we recognize/can handle.
515 throw;
516 } catch (const ::sc_core::sc_report &) {
517 // It's already a sc_report, so nothing to do.
518 throw;
519 } catch (const ::sc_core::sc_unwind_exception &) {
520 panic("Kill/reset exception escaped a Process::run()");
521 } catch (const std::exception &e) {
522 SC_REPORT_ERROR(
523 sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_, e.what());
524 } catch (const char *msg) {
525 SC_REPORT_ERROR(
526 sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_, msg);
527 } catch (...) {
528 SC_REPORT_ERROR(
529 sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_,
530 "UNKNOWN EXCEPTION");
531 }
532 } catch (const ::sc_core::sc_report &r) {
533 ::sc_core::sc_report_handler::set_handler(old_handler);
534 return r;
535 }
536 panic("No exception thrown in reportifyException.");
537}
538
539} // namespace sc_gem5