scheduler.cc (13259:3730df183b84) scheduler.cc (13260:4d18f1d20093)
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"
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),
52 timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0),
53 _changeStamp(0), _current(nullptr), initDone(false), runOnce(false)
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);
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();
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->needsStart()) {
182 if (_current->excWrapper) {
183 auto ew = _current->excWrapper;
184 _current->excWrapper = nullptr;
185 ew->throw_it();
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"
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),
52 timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0),
53 _changeStamp(0), _current(nullptr), initDone(false), runOnce(false)
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);
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();
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->needsStart()) {
182 if (_current->excWrapper) {
183 auto ew = _current->excWrapper;
184 _current->excWrapper = nullptr;
185 ew->throw_it();
186 } else if (_current->syncReset()) {
186 } else if (_current->inReset()) {
187 _current->reset(false);
188 }
189 }
190}
191
192void
193Scheduler::ready(Process *p)
194{
195 if (_stopNow)
196 return;
197
198 if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
199 readyListMethods.pushLast(p);
200 else
201 readyListThreads.pushLast(p);
202
203 if (!inEvaluate())
204 scheduleReadyEvent();
205}
206
207void
208Scheduler::resume(Process *p)
209{
210 if (initDone)
211 ready(p);
212 else
213 initList.pushLast(p);
214}
215
216bool
217listContains(ListNode *list, ListNode *target)
218{
219 ListNode *n = list->nextListNode;
220 while (n != list)
221 if (n == target)
222 return true;
223 return false;
224}
225
226bool
227Scheduler::suspend(Process *p)
228{
229 bool was_ready;
230 if (initDone) {
231 // After initialization, check if we're on a ready list.
232 was_ready = (p->nextListNode != nullptr);
233 p->popListNode();
234 } else {
235 // Nothing is ready before init.
236 was_ready = false;
237 }
238 return was_ready;
239}
240
241void
242Scheduler::requestUpdate(Channel *c)
243{
244 updateList.pushLast(c);
245 if (!inEvaluate())
246 scheduleReadyEvent();
247}
248
249void
250Scheduler::scheduleReadyEvent()
251{
252 // Schedule the evaluate and update phases.
253 if (!readyEvent.scheduled()) {
254 schedule(&readyEvent);
255 if (starvationEvent.scheduled())
256 deschedule(&starvationEvent);
257 }
258}
259
260void
261Scheduler::scheduleStarvationEvent()
262{
263 if (!starvationEvent.scheduled()) {
264 schedule(&starvationEvent);
265 if (readyEvent.scheduled())
266 deschedule(&readyEvent);
267 }
268}
269
270void
271Scheduler::runReady()
272{
273 scheduleTimeAdvancesEvent();
274
275 bool empty = readyListMethods.empty() && readyListThreads.empty();
276 lastReadyTick = getCurTick();
277
278 // The evaluation phase.
279 status(StatusEvaluate);
280 do {
281 yield();
282 } while (getNextReady());
283
284 if (!empty) {
285 _numCycles++;
286 _changeStamp++;
287 }
288
289 if (_stopNow) {
290 status(StatusOther);
291 return;
292 }
293
294 runUpdate();
295 if (!traceFiles.empty())
296 trace(true);
297 runDelta();
298
299 if (!runToTime && starved())
300 scheduleStarvationEvent();
301
302 if (runOnce)
303 schedulePause();
304
305 status(StatusOther);
306}
307
308void
309Scheduler::runUpdate()
310{
311 status(StatusUpdate);
312
313 try {
314 Channel *channel = updateList.getNext();
315 while (channel) {
316 channel->popListNode();
317 channel->update();
318 channel = updateList.getNext();
319 }
320 } catch (...) {
321 throwToScMain();
322 }
323}
324
325void
326Scheduler::runDelta()
327{
328 status(StatusDelta);
329
330 try {
331 while (!deltas.empty())
332 deltas.front()->run();
333 } catch (...) {
334 throwToScMain();
335 }
336}
337
338void
339Scheduler::pause()
340{
341 status(StatusPaused);
342 kernel->status(::sc_core::SC_PAUSED);
343 runOnce = false;
344 if (scMain && !scMain->finished())
345 scMain->run();
346}
347
348void
349Scheduler::stop()
350{
351 status(StatusStopped);
352 kernel->stop();
353
354 clear();
355
356 runOnce = false;
357 if (scMain && !scMain->finished())
358 scMain->run();
359}
360
361void
362Scheduler::start(Tick max_tick, bool run_to_time)
363{
364 // We should be running from sc_main. Keep track of that Fiber to return
365 // to later.
366 scMain = Fiber::currentFiber();
367
368 _started = true;
369 status(StatusOther);
370 runToTime = run_to_time;
371
372 maxTick = max_tick;
373 lastReadyTick = getCurTick();
374
375 if (initDone) {
376 if (!runToTime && starved())
377 scheduleStarvationEvent();
378 kernel->status(::sc_core::SC_RUNNING);
379 }
380
381 schedule(&maxTickEvent, maxTick);
382 scheduleTimeAdvancesEvent();
383
384 // Return to gem5 to let it run events, etc.
385 Fiber::primaryFiber()->run();
386
387 if (pauseEvent.scheduled())
388 deschedule(&pauseEvent);
389 if (stopEvent.scheduled())
390 deschedule(&stopEvent);
391 if (maxTickEvent.scheduled())
392 deschedule(&maxTickEvent);
393 if (starvationEvent.scheduled())
394 deschedule(&starvationEvent);
395
396 if (_throwToScMain) {
397 const ::sc_core::sc_report *to_throw = _throwToScMain;
398 _throwToScMain = nullptr;
399 throw *to_throw;
400 }
401}
402
403void
404Scheduler::oneCycle()
405{
406 runOnce = true;
407 scheduleReadyEvent();
408 start(::MaxTick, false);
409}
410
411void
412Scheduler::schedulePause()
413{
414 if (pauseEvent.scheduled())
415 return;
416
417 schedule(&pauseEvent);
418}
419
420void
421Scheduler::throwToScMain(const ::sc_core::sc_report *r)
422{
423 if (!r)
424 r = reportifyException();
425 _throwToScMain = r;
426 status(StatusOther);
427 scMain->run();
428}
429
430void
431Scheduler::scheduleStop(bool finish_delta)
432{
433 if (stopEvent.scheduled())
434 return;
435
436 if (!finish_delta) {
437 _stopNow = true;
438 // If we're not supposed to finish the delta cycle, flush all
439 // pending activity.
440 clear();
441 }
442 schedule(&stopEvent);
443}
444
445void
446Scheduler::trace(bool delta)
447{
448 for (auto tf: traceFiles)
449 tf->trace(delta);
450}
451
452Scheduler scheduler;
453
454namespace {
455
456void
457throwingReportHandler(const ::sc_core::sc_report &r,
458 const ::sc_core::sc_actions &)
459{
460 throw r;
461}
462
463} // anonymous namespace
464
465const ::sc_core::sc_report *
466reportifyException()
467{
468 ::sc_core::sc_report_handler_proc old_handler =
469 ::sc_core::sc_report_handler::get_handler();
470 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
471
472 try {
473 try {
474 // Rethrow the current exception so we can catch it and throw an
475 // sc_report instead if it's not a type we recognize/can handle.
476 throw;
477 } catch (const ::sc_core::sc_report &) {
478 // It's already a sc_report, so nothing to do.
479 throw;
480 } catch (const ::sc_core::sc_unwind_exception &) {
481 panic("Kill/reset exception escaped a Process::run()");
482 } catch (const std::exception &e) {
483 SC_REPORT_ERROR("uncaught exception", e.what());
484 } catch (const char *msg) {
485 SC_REPORT_ERROR("uncaught exception", msg);
486 } catch (...) {
487 SC_REPORT_ERROR("uncaught exception", "UNKNOWN EXCEPTION");
488 }
489 } catch (const ::sc_core::sc_report &r) {
490 ::sc_core::sc_report_handler::set_handler(old_handler);
491 return &r;
492 }
493 panic("No exception thrown in reportifyException.");
494}
495
496} // namespace sc_gem5
187 _current->reset(false);
188 }
189 }
190}
191
192void
193Scheduler::ready(Process *p)
194{
195 if (_stopNow)
196 return;
197
198 if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
199 readyListMethods.pushLast(p);
200 else
201 readyListThreads.pushLast(p);
202
203 if (!inEvaluate())
204 scheduleReadyEvent();
205}
206
207void
208Scheduler::resume(Process *p)
209{
210 if (initDone)
211 ready(p);
212 else
213 initList.pushLast(p);
214}
215
216bool
217listContains(ListNode *list, ListNode *target)
218{
219 ListNode *n = list->nextListNode;
220 while (n != list)
221 if (n == target)
222 return true;
223 return false;
224}
225
226bool
227Scheduler::suspend(Process *p)
228{
229 bool was_ready;
230 if (initDone) {
231 // After initialization, check if we're on a ready list.
232 was_ready = (p->nextListNode != nullptr);
233 p->popListNode();
234 } else {
235 // Nothing is ready before init.
236 was_ready = false;
237 }
238 return was_ready;
239}
240
241void
242Scheduler::requestUpdate(Channel *c)
243{
244 updateList.pushLast(c);
245 if (!inEvaluate())
246 scheduleReadyEvent();
247}
248
249void
250Scheduler::scheduleReadyEvent()
251{
252 // Schedule the evaluate and update phases.
253 if (!readyEvent.scheduled()) {
254 schedule(&readyEvent);
255 if (starvationEvent.scheduled())
256 deschedule(&starvationEvent);
257 }
258}
259
260void
261Scheduler::scheduleStarvationEvent()
262{
263 if (!starvationEvent.scheduled()) {
264 schedule(&starvationEvent);
265 if (readyEvent.scheduled())
266 deschedule(&readyEvent);
267 }
268}
269
270void
271Scheduler::runReady()
272{
273 scheduleTimeAdvancesEvent();
274
275 bool empty = readyListMethods.empty() && readyListThreads.empty();
276 lastReadyTick = getCurTick();
277
278 // The evaluation phase.
279 status(StatusEvaluate);
280 do {
281 yield();
282 } while (getNextReady());
283
284 if (!empty) {
285 _numCycles++;
286 _changeStamp++;
287 }
288
289 if (_stopNow) {
290 status(StatusOther);
291 return;
292 }
293
294 runUpdate();
295 if (!traceFiles.empty())
296 trace(true);
297 runDelta();
298
299 if (!runToTime && starved())
300 scheduleStarvationEvent();
301
302 if (runOnce)
303 schedulePause();
304
305 status(StatusOther);
306}
307
308void
309Scheduler::runUpdate()
310{
311 status(StatusUpdate);
312
313 try {
314 Channel *channel = updateList.getNext();
315 while (channel) {
316 channel->popListNode();
317 channel->update();
318 channel = updateList.getNext();
319 }
320 } catch (...) {
321 throwToScMain();
322 }
323}
324
325void
326Scheduler::runDelta()
327{
328 status(StatusDelta);
329
330 try {
331 while (!deltas.empty())
332 deltas.front()->run();
333 } catch (...) {
334 throwToScMain();
335 }
336}
337
338void
339Scheduler::pause()
340{
341 status(StatusPaused);
342 kernel->status(::sc_core::SC_PAUSED);
343 runOnce = false;
344 if (scMain && !scMain->finished())
345 scMain->run();
346}
347
348void
349Scheduler::stop()
350{
351 status(StatusStopped);
352 kernel->stop();
353
354 clear();
355
356 runOnce = false;
357 if (scMain && !scMain->finished())
358 scMain->run();
359}
360
361void
362Scheduler::start(Tick max_tick, bool run_to_time)
363{
364 // We should be running from sc_main. Keep track of that Fiber to return
365 // to later.
366 scMain = Fiber::currentFiber();
367
368 _started = true;
369 status(StatusOther);
370 runToTime = run_to_time;
371
372 maxTick = max_tick;
373 lastReadyTick = getCurTick();
374
375 if (initDone) {
376 if (!runToTime && starved())
377 scheduleStarvationEvent();
378 kernel->status(::sc_core::SC_RUNNING);
379 }
380
381 schedule(&maxTickEvent, maxTick);
382 scheduleTimeAdvancesEvent();
383
384 // Return to gem5 to let it run events, etc.
385 Fiber::primaryFiber()->run();
386
387 if (pauseEvent.scheduled())
388 deschedule(&pauseEvent);
389 if (stopEvent.scheduled())
390 deschedule(&stopEvent);
391 if (maxTickEvent.scheduled())
392 deschedule(&maxTickEvent);
393 if (starvationEvent.scheduled())
394 deschedule(&starvationEvent);
395
396 if (_throwToScMain) {
397 const ::sc_core::sc_report *to_throw = _throwToScMain;
398 _throwToScMain = nullptr;
399 throw *to_throw;
400 }
401}
402
403void
404Scheduler::oneCycle()
405{
406 runOnce = true;
407 scheduleReadyEvent();
408 start(::MaxTick, false);
409}
410
411void
412Scheduler::schedulePause()
413{
414 if (pauseEvent.scheduled())
415 return;
416
417 schedule(&pauseEvent);
418}
419
420void
421Scheduler::throwToScMain(const ::sc_core::sc_report *r)
422{
423 if (!r)
424 r = reportifyException();
425 _throwToScMain = r;
426 status(StatusOther);
427 scMain->run();
428}
429
430void
431Scheduler::scheduleStop(bool finish_delta)
432{
433 if (stopEvent.scheduled())
434 return;
435
436 if (!finish_delta) {
437 _stopNow = true;
438 // If we're not supposed to finish the delta cycle, flush all
439 // pending activity.
440 clear();
441 }
442 schedule(&stopEvent);
443}
444
445void
446Scheduler::trace(bool delta)
447{
448 for (auto tf: traceFiles)
449 tf->trace(delta);
450}
451
452Scheduler scheduler;
453
454namespace {
455
456void
457throwingReportHandler(const ::sc_core::sc_report &r,
458 const ::sc_core::sc_actions &)
459{
460 throw r;
461}
462
463} // anonymous namespace
464
465const ::sc_core::sc_report *
466reportifyException()
467{
468 ::sc_core::sc_report_handler_proc old_handler =
469 ::sc_core::sc_report_handler::get_handler();
470 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
471
472 try {
473 try {
474 // Rethrow the current exception so we can catch it and throw an
475 // sc_report instead if it's not a type we recognize/can handle.
476 throw;
477 } catch (const ::sc_core::sc_report &) {
478 // It's already a sc_report, so nothing to do.
479 throw;
480 } catch (const ::sc_core::sc_unwind_exception &) {
481 panic("Kill/reset exception escaped a Process::run()");
482 } catch (const std::exception &e) {
483 SC_REPORT_ERROR("uncaught exception", e.what());
484 } catch (const char *msg) {
485 SC_REPORT_ERROR("uncaught exception", msg);
486 } catch (...) {
487 SC_REPORT_ERROR("uncaught exception", "UNKNOWN EXCEPTION");
488 }
489 } catch (const ::sc_core::sc_report &r) {
490 ::sc_core::sc_report_handler::set_handler(old_handler);
491 return &r;
492 }
493 panic("No exception thrown in reportifyException.");
494}
495
496} // namespace sc_gem5