scheduler.cc (13203:76ee4971fd9e) scheduler.cc (13207:034ca389a810)
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
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),
51 _numCycles(0), _changeStamp(0), _current(nullptr), initDone(false),
52 runOnce(false), readyList(nullptr)
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);
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()) {
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
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),
51 _numCycles(0), _changeStamp(0), _current(nullptr), initDone(false),
52 runOnce(false), readyList(nullptr)
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);
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->finalize();
108 p->popListNode();
109
110 if (p->dontInitialize()) {
111 if (!p->hasStaticSensitivities() && !p->internal()) {
112 SC_REPORT_WARNING(
113 "(W558) disable() or dont_initialize() called on "
114 "process with no static sensitivity, it will be "
115 "orphaned", p->name());
116 }
117 } else {
118 p->ready();
119 }
120 }
121
122 runUpdate();
123 runDelta();
124
125 for (auto ets: eventsToSchedule)
126 eq->schedule(ets.first, ets.second);
127 eventsToSchedule.clear();
128
129 if (_started) {
130 if (!runToTime && starved())
131 scheduleStarvationEvent();
132 kernel->status(::sc_core::SC_RUNNING);
133 }
134
135 initDone = true;
136
137 status(StatusOther);
138}
139
140void
141Scheduler::reg(Process *p)
142{
143 if (initDone) {
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);
137}
138
139void
140Scheduler::reg(Process *p)
141{
142 if (initDone) {
144 // If we're past initialization, finalize static sensitivity.
145 p->finalize();
146 // If not marked as dontInitialize, mark as ready.
147 if (!p->dontInitialize())
148 p->ready();
149 } else {
150 // Otherwise, record that this process should be initialized once we
151 // get there.
152 initList.pushLast(p);
153 }
154}
155
156void
157Scheduler::yield()
158{
159 // Pull a process from the active list.
160 _current = readyList->getNext();
161 if (!_current) {
162 // There are no more processes, so return control to evaluate.
163 Fiber::primaryFiber()->run();
164 } else {
165 _current->popListNode();
166 // Switch to whatever Fiber is supposed to run this process. All
167 // Fibers which aren't running should be parked at this line.
168 _current->fiber()->run();
169 // If the current process needs to be manually started, start it.
170 if (_current && _current->needsStart()) {
171 _current->needsStart(false);
172 try {
173 _current->run();
174 } catch (...) {
175 throwToScMain();
176 }
177 }
178 }
179 if (_current && _current->excWrapper) {
180 // Make sure this isn't a method process.
181 assert(!_current->needsStart());
182 auto ew = _current->excWrapper;
183 _current->excWrapper = nullptr;
184 ew->throw_it();
185 }
186}
187
188void
189Scheduler::ready(Process *p)
190{
191 if (_stopNow)
192 return;
193
194 if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
195 readyListMethods.pushLast(p);
196 else
197 readyListThreads.pushLast(p);
198
199 scheduleReadyEvent();
200}
201
202void
203Scheduler::resume(Process *p)
204{
205 if (initDone)
206 ready(p);
207 else
208 initList.pushLast(p);
209}
210
211bool
212listContains(ListNode *list, ListNode *target)
213{
214 ListNode *n = list->nextListNode;
215 while (n != list)
216 if (n == target)
217 return true;
218 return false;
219}
220
221bool
222Scheduler::suspend(Process *p)
223{
224 bool was_ready;
225 if (initDone) {
226 // After initialization, check if we're on a ready list.
227 was_ready = (p->nextListNode != nullptr);
228 p->popListNode();
229 } else {
230 // Nothing is ready before init.
231 was_ready = false;
232 }
233 return was_ready;
234}
235
236void
237Scheduler::requestUpdate(Channel *c)
238{
239 updateList.pushLast(c);
240 scheduleReadyEvent();
241}
242
243void
244Scheduler::scheduleReadyEvent()
245{
246 // Schedule the evaluate and update phases.
247 if (!readyEvent.scheduled()) {
248 schedule(&readyEvent);
249 if (starvationEvent.scheduled())
250 deschedule(&starvationEvent);
251 }
252}
253
254void
255Scheduler::scheduleStarvationEvent()
256{
257 if (!starvationEvent.scheduled()) {
258 schedule(&starvationEvent);
259 if (readyEvent.scheduled())
260 deschedule(&readyEvent);
261 }
262}
263
264void
265Scheduler::runReady()
266{
267 bool empty = readyListMethods.empty() && readyListThreads.empty();
268 lastReadyTick = getCurTick();
269
270 // The evaluation phase.
271 do {
272 // We run methods and threads in two seperate passes to emulate how
273 // Accellera orders things, but without having to scan through a
274 // unified list to find the next process of the correct type.
275 readyList = &readyListMethods;
276 while (!readyListMethods.empty())
277 yield();
278
279 readyList = &readyListThreads;
280 while (!readyListThreads.empty())
281 yield();
282
283 // We already know that readyListThreads is empty at this point.
284 } while (!readyListMethods.empty());
285
286 if (!empty) {
287 _numCycles++;
288 _changeStamp++;
289 }
290
291 if (_stopNow)
292 return;
293
294 runUpdate();
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
381 // Return to gem5 to let it run events, etc.
382 Fiber::primaryFiber()->run();
383
384 if (pauseEvent.scheduled())
385 deschedule(&pauseEvent);
386 if (stopEvent.scheduled())
387 deschedule(&stopEvent);
388 if (maxTickEvent.scheduled())
389 deschedule(&maxTickEvent);
390 if (starvationEvent.scheduled())
391 deschedule(&starvationEvent);
392
393 if (_throwToScMain) {
394 const ::sc_core::sc_report *to_throw = _throwToScMain;
395 _throwToScMain = nullptr;
396 throw *to_throw;
397 }
398}
399
400void
401Scheduler::oneCycle()
402{
403 runOnce = true;
404 scheduleReadyEvent();
405 start(::MaxTick, false);
406}
407
408void
409Scheduler::schedulePause()
410{
411 if (pauseEvent.scheduled())
412 return;
413
414 schedule(&pauseEvent);
415}
416
417void
418Scheduler::throwToScMain(const ::sc_core::sc_report *r)
419{
420 if (!r)
421 r = reportifyException();
422 _throwToScMain = r;
423 status(StatusOther);
424 scMain->run();
425}
426
427void
428Scheduler::scheduleStop(bool finish_delta)
429{
430 if (stopEvent.scheduled())
431 return;
432
433 if (!finish_delta) {
434 _stopNow = true;
435 // If we're not supposed to finish the delta cycle, flush all
436 // pending activity.
437 clear();
438 }
439 schedule(&stopEvent);
440}
441
442Scheduler scheduler;
443
444namespace {
445
446void
447throwingReportHandler(const ::sc_core::sc_report &r,
448 const ::sc_core::sc_actions &)
449{
450 throw r;
451}
452
453} // anonymous namespace
454
455const ::sc_core::sc_report *
456reportifyException()
457{
458 ::sc_core::sc_report_handler_proc old_handler =
459 ::sc_core::sc_report_handler::get_handler();
460 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
461
462 try {
463 try {
464 // Rethrow the current exception so we can catch it and throw an
465 // sc_report instead if it's not a type we recognize/can handle.
466 throw;
467 } catch (const ::sc_core::sc_report &) {
468 // It's already a sc_report, so nothing to do.
469 throw;
470 } catch (const ::sc_core::sc_unwind_exception &) {
471 panic("Kill/reset exception escaped a Process::run()");
472 } catch (const std::exception &e) {
473 SC_REPORT_ERROR("uncaught exception", e.what());
474 } catch (const char *msg) {
475 SC_REPORT_ERROR("uncaught exception", msg);
476 } catch (...) {
477 SC_REPORT_ERROR("uncaught exception", "UNKNOWN EXCEPTION");
478 }
479 } catch (const ::sc_core::sc_report &r) {
480 ::sc_core::sc_report_handler::set_handler(old_handler);
481 return &r;
482 }
483 panic("No exception thrown in reportifyException.");
484}
485
486} // namespace sc_gem5
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 = readyList->getNext();
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 scheduleReadyEvent();
197}
198
199void
200Scheduler::resume(Process *p)
201{
202 if (initDone)
203 ready(p);
204 else
205 initList.pushLast(p);
206}
207
208bool
209listContains(ListNode *list, ListNode *target)
210{
211 ListNode *n = list->nextListNode;
212 while (n != list)
213 if (n == target)
214 return true;
215 return false;
216}
217
218bool
219Scheduler::suspend(Process *p)
220{
221 bool was_ready;
222 if (initDone) {
223 // After initialization, check if we're on a ready list.
224 was_ready = (p->nextListNode != nullptr);
225 p->popListNode();
226 } else {
227 // Nothing is ready before init.
228 was_ready = false;
229 }
230 return was_ready;
231}
232
233void
234Scheduler::requestUpdate(Channel *c)
235{
236 updateList.pushLast(c);
237 scheduleReadyEvent();
238}
239
240void
241Scheduler::scheduleReadyEvent()
242{
243 // Schedule the evaluate and update phases.
244 if (!readyEvent.scheduled()) {
245 schedule(&readyEvent);
246 if (starvationEvent.scheduled())
247 deschedule(&starvationEvent);
248 }
249}
250
251void
252Scheduler::scheduleStarvationEvent()
253{
254 if (!starvationEvent.scheduled()) {
255 schedule(&starvationEvent);
256 if (readyEvent.scheduled())
257 deschedule(&readyEvent);
258 }
259}
260
261void
262Scheduler::runReady()
263{
264 bool empty = readyListMethods.empty() && readyListThreads.empty();
265 lastReadyTick = getCurTick();
266
267 // The evaluation phase.
268 do {
269 // We run methods and threads in two seperate passes to emulate how
270 // Accellera orders things, but without having to scan through a
271 // unified list to find the next process of the correct type.
272 readyList = &readyListMethods;
273 while (!readyListMethods.empty())
274 yield();
275
276 readyList = &readyListThreads;
277 while (!readyListThreads.empty())
278 yield();
279
280 // We already know that readyListThreads is empty at this point.
281 } while (!readyListMethods.empty());
282
283 if (!empty) {
284 _numCycles++;
285 _changeStamp++;
286 }
287
288 if (_stopNow)
289 return;
290
291 runUpdate();
292 runDelta();
293
294 if (!runToTime && starved())
295 scheduleStarvationEvent();
296
297 if (runOnce)
298 schedulePause();
299
300 status(StatusOther);
301}
302
303void
304Scheduler::runUpdate()
305{
306 status(StatusUpdate);
307
308 try {
309 Channel *channel = updateList.getNext();
310 while (channel) {
311 channel->popListNode();
312 channel->update();
313 channel = updateList.getNext();
314 }
315 } catch (...) {
316 throwToScMain();
317 }
318}
319
320void
321Scheduler::runDelta()
322{
323 status(StatusDelta);
324
325 try {
326 while (!deltas.empty())
327 deltas.front()->run();
328 } catch (...) {
329 throwToScMain();
330 }
331}
332
333void
334Scheduler::pause()
335{
336 status(StatusPaused);
337 kernel->status(::sc_core::SC_PAUSED);
338 runOnce = false;
339 if (scMain && !scMain->finished())
340 scMain->run();
341}
342
343void
344Scheduler::stop()
345{
346 status(StatusStopped);
347 kernel->stop();
348
349 clear();
350
351 runOnce = false;
352 if (scMain && !scMain->finished())
353 scMain->run();
354}
355
356void
357Scheduler::start(Tick max_tick, bool run_to_time)
358{
359 // We should be running from sc_main. Keep track of that Fiber to return
360 // to later.
361 scMain = Fiber::currentFiber();
362
363 _started = true;
364 status(StatusOther);
365 runToTime = run_to_time;
366
367 maxTick = max_tick;
368 lastReadyTick = getCurTick();
369
370 if (initDone) {
371 if (!runToTime && starved())
372 scheduleStarvationEvent();
373 kernel->status(::sc_core::SC_RUNNING);
374 }
375
376 schedule(&maxTickEvent, maxTick);
377
378 // Return to gem5 to let it run events, etc.
379 Fiber::primaryFiber()->run();
380
381 if (pauseEvent.scheduled())
382 deschedule(&pauseEvent);
383 if (stopEvent.scheduled())
384 deschedule(&stopEvent);
385 if (maxTickEvent.scheduled())
386 deschedule(&maxTickEvent);
387 if (starvationEvent.scheduled())
388 deschedule(&starvationEvent);
389
390 if (_throwToScMain) {
391 const ::sc_core::sc_report *to_throw = _throwToScMain;
392 _throwToScMain = nullptr;
393 throw *to_throw;
394 }
395}
396
397void
398Scheduler::oneCycle()
399{
400 runOnce = true;
401 scheduleReadyEvent();
402 start(::MaxTick, false);
403}
404
405void
406Scheduler::schedulePause()
407{
408 if (pauseEvent.scheduled())
409 return;
410
411 schedule(&pauseEvent);
412}
413
414void
415Scheduler::throwToScMain(const ::sc_core::sc_report *r)
416{
417 if (!r)
418 r = reportifyException();
419 _throwToScMain = r;
420 status(StatusOther);
421 scMain->run();
422}
423
424void
425Scheduler::scheduleStop(bool finish_delta)
426{
427 if (stopEvent.scheduled())
428 return;
429
430 if (!finish_delta) {
431 _stopNow = true;
432 // If we're not supposed to finish the delta cycle, flush all
433 // pending activity.
434 clear();
435 }
436 schedule(&stopEvent);
437}
438
439Scheduler scheduler;
440
441namespace {
442
443void
444throwingReportHandler(const ::sc_core::sc_report &r,
445 const ::sc_core::sc_actions &)
446{
447 throw r;
448}
449
450} // anonymous namespace
451
452const ::sc_core::sc_report *
453reportifyException()
454{
455 ::sc_core::sc_report_handler_proc old_handler =
456 ::sc_core::sc_report_handler::get_handler();
457 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
458
459 try {
460 try {
461 // Rethrow the current exception so we can catch it and throw an
462 // sc_report instead if it's not a type we recognize/can handle.
463 throw;
464 } catch (const ::sc_core::sc_report &) {
465 // It's already a sc_report, so nothing to do.
466 throw;
467 } catch (const ::sc_core::sc_unwind_exception &) {
468 panic("Kill/reset exception escaped a Process::run()");
469 } catch (const std::exception &e) {
470 SC_REPORT_ERROR("uncaught exception", e.what());
471 } catch (const char *msg) {
472 SC_REPORT_ERROR("uncaught exception", msg);
473 } catch (...) {
474 SC_REPORT_ERROR("uncaught exception", "UNKNOWN EXCEPTION");
475 }
476 } catch (const ::sc_core::sc_report &r) {
477 ::sc_core::sc_report_handler::set_handler(old_handler);
478 return &r;
479 }
480 panic("No exception thrown in reportifyException.");
481}
482
483} // namespace sc_gem5