process.cc revision 13335:299a16ef8e3c
12155SN/A/*
22155SN/A * Copyright 2018 Google, Inc.
32155SN/A *
42155SN/A * Redistribution and use in source and binary forms, with or without
52155SN/A * modification, are permitted provided that the following conditions are
62155SN/A * met: redistributions of source code must retain the above copyright
72155SN/A * notice, this list of conditions and the following disclaimer;
82155SN/A * redistributions in binary form must reproduce the above copyright
92155SN/A * notice, this list of conditions and the following disclaimer in the
102155SN/A * documentation and/or other materials provided with the distribution;
112155SN/A * neither the name of the copyright holders nor the names of its
122155SN/A * contributors may be used to endorse or promote products derived from
132155SN/A * this software without specific prior written permission.
142155SN/A *
152155SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
162155SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
172155SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
182155SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
192155SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
202155SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
212155SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
222155SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
232155SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
242155SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
252155SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262155SN/A *
272155SN/A * Authors: Gabe Black
282665Ssaidi@eecs.umich.edu */
292665Ssaidi@eecs.umich.edu
302155SN/A#include "systemc/core/process.hh"
312155SN/A
322155SN/A#include "systemc/core/event.hh"
332155SN/A#include "systemc/core/port.hh"
342155SN/A#include "systemc/core/scheduler.hh"
352155SN/A#include "systemc/ext/core/messages.hh"
362155SN/A#include "systemc/ext/core/sc_join.hh"
372178SN/A#include "systemc/ext/core/sc_main.hh"
382178SN/A#include "systemc/ext/core/sc_process_handle.hh"
392178SN/A#include "systemc/ext/utils/sc_report_handler.hh"
402178SN/A
412178SN/Anamespace sc_gem5
422178SN/A{
432178SN/A
442178SN/Aclass UnwindExceptionReset : public ::sc_core::sc_unwind_exception
452178SN/A{
462178SN/A  public:
472178SN/A    UnwindExceptionReset() { _isReset = true; }
482178SN/A};
492155SN/A
502178SN/Aclass UnwindExceptionKill : public ::sc_core::sc_unwind_exception
512155SN/A{
522155SN/A  public:
532178SN/A    UnwindExceptionKill() {}
542155SN/A};
552155SN/A
562623SN/Atemplate <typename T>
572623SN/Astruct BuiltinExceptionWrapper : public ExceptionWrapperBase
582623SN/A{
592623SN/A  public:
602623SN/A    T t;
612155SN/A    void throw_it() override { throw t; }
622155SN/A};
632292SN/A
642292SN/ABuiltinExceptionWrapper<UnwindExceptionReset> resetException;
652292SN/ABuiltinExceptionWrapper<UnwindExceptionKill> killException;
662292SN/A
672292SN/A
682292SN/Avoid
692292SN/AProcess::forEachKid(const std::function<void(Process *)> &work)
702292SN/A{
712766Sktlim@umich.edu    for (auto &kid: get_child_objects()) {
722766Sktlim@umich.edu        Process *p_kid = dynamic_cast<Process *>(kid);
732766Sktlim@umich.edu        if (p_kid)
742921Sktlim@umich.edu            work(p_kid);
752921Sktlim@umich.edu    }
762766Sktlim@umich.edu}
772766Sktlim@umich.edu
782766Sktlim@umich.eduvoid
792178SN/AProcess::suspend(bool inc_kids)
802155SN/A{
812155SN/A    if (inc_kids)
822155SN/A        forEachKid([](Process *p) { p->suspend(true); });
832155SN/A
842155SN/A    if (!_suspended) {
852155SN/A        _suspended = true;
862766Sktlim@umich.edu        _suspendedReady = scheduler.suspend(this);
872155SN/A
882623SN/A        if (procKind() != ::sc_core::SC_METHOD_PROC_ &&
892155SN/A                scheduler.current() == this) {
902155SN/A            // This isn't in the spec, but Accellera says that a thread that
912155SN/A            // self suspends should be marked ready immediately when it's
922155SN/A            // resumed.
932178SN/A            _suspendedReady = true;
942178SN/A            scheduler.yield();
952178SN/A        }
962766Sktlim@umich.edu    }
972178SN/A}
982178SN/A
992178SN/Avoid
1002178SN/AProcess::resume(bool inc_kids)
1012766Sktlim@umich.edu{
1022766Sktlim@umich.edu    if (inc_kids)
1032766Sktlim@umich.edu        forEachKid([](Process *p) { p->resume(true); });
1042788Sktlim@umich.edu
1052178SN/A    if (_suspended) {
1062733Sktlim@umich.edu        _suspended = false;
1072733Sktlim@umich.edu        if (_suspendedReady)
1082817Sksewell@umich.edu            scheduler.resume(this);
1092733Sktlim@umich.edu        _suspendedReady = false;
1102178SN/A    }
1112178SN/A}
1122178SN/A
1132178SN/Avoid
1142178SN/AProcess::disable(bool inc_kids)
1152178SN/A{
1162155SN/A    if (inc_kids)
1172929Sktlim@umich.edu        forEachKid([](Process *p) { p->disable(true); });
1182929Sktlim@umich.edu
1192929Sktlim@umich.edu    if (!::sc_core::sc_allow_process_control_corners &&
1202155SN/A            timeoutEvent.scheduled()) {
1212155SN/A        std::string message("attempt to disable a thread with timeout wait: ");
1222623SN/A        message += name();
1232623SN/A        SC_REPORT_ERROR(sc_core::SC_ID_PROCESS_CONTROL_CORNER_CASE_,
1242623SN/A                message.c_str());
1252623SN/A    }
1262623SN/A
1272623SN/A    _disabled = true;
1282623SN/A}
1292623SN/A
1302623SN/Avoid
1312623SN/AProcess::enable(bool inc_kids)
1322623SN/A{
1332155SN/A
1342155SN/A    if (inc_kids)
1352155SN/A        forEachKid([](Process *p) { p->enable(true); });
1362155SN/A
1372821Sktlim@umich.edu    _disabled = false;
1382817Sksewell@umich.edu}
1392821Sktlim@umich.edu
1402817Sksewell@umich.eduvoid
1412155SN/AProcess::kill(bool inc_kids)
1422765Sktlim@umich.edu{
1432155SN/A    if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) {
1442155SN/A        SC_REPORT_ERROR(sc_core::SC_ID_KILL_PROCESS_WHILE_UNITIALIZED_,
1452155SN/A                name());
1462155SN/A    }
1472155SN/A
1482292SN/A    // Propogate the kill to our children no matter what happens to us.
1492155SN/A    if (inc_kids)
1502155SN/A        forEachKid([](Process *p) { p->kill(true); });
1512155SN/A
1522292SN/A    // If we're in the middle of unwinding, ignore the kill request.
1532292SN/A    if (_isUnwinding)
1542155SN/A        return;
1552155SN/A
1562155SN/A    // Update our state.
1572155SN/A    terminate();
1582292SN/A    _isUnwinding = true;
1592155SN/A
1602155SN/A    // Make sure this process isn't marked ready
1612766Sktlim@umich.edu    popListNode();
1622765Sktlim@umich.edu
1632929Sktlim@umich.edu    // Inject the kill exception into this process if it's started.
1642155SN/A    if (!_needsStart)
1652792Sktlim@umich.edu        injectException(killException);
1662821Sktlim@umich.edu}
1672292SN/A
1682792Sktlim@umich.eduvoid
1692792Sktlim@umich.eduProcess::reset(bool inc_kids)
1702292SN/A{
1712292SN/A    if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) {
1722292SN/A        SC_REPORT_ERROR(sc_core::SC_ID_RESET_PROCESS_WHILE_NOT_RUNNING_,
1732292SN/A                name());
1742297SN/A    }
1752297SN/A
1762792Sktlim@umich.edu    // Propogate the reset to our children no matter what happens to us.
1772292SN/A    if (inc_kids)
1782766Sktlim@umich.edu        forEachKid([](Process *p) { p->reset(true); });
1792765Sktlim@umich.edu
1802292SN/A    // If we're in the middle of unwinding, ignore the reset request.
1812821Sktlim@umich.edu    if (_isUnwinding)
1822821Sktlim@umich.edu        return;
1832821Sktlim@umich.edu
1842821Sktlim@umich.edu    // Clear suspended ready since we're about to run regardless.
1852821Sktlim@umich.edu    _suspendedReady = false;
1862821Sktlim@umich.edu
1872821Sktlim@umich.edu    _resetEvent.notify();
1882821Sktlim@umich.edu
1892766Sktlim@umich.edu    if (_needsStart) {
1902789Sktlim@umich.edu        scheduler.runNow(this);
1912733Sktlim@umich.edu    } else {
1922733Sktlim@umich.edu        _isUnwinding = true;
1932733Sktlim@umich.edu        injectException(resetException);
1942733Sktlim@umich.edu    }
1952733Sktlim@umich.edu}
1962874Sktlim@umich.edu
1972874Sktlim@umich.eduvoid
1982874Sktlim@umich.eduProcess::throw_it(ExceptionWrapperBase &exc, bool inc_kids)
1992874Sktlim@umich.edu{
2002733Sktlim@umich.edu    if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING)
2012733Sktlim@umich.edu        SC_REPORT_ERROR(sc_core::SC_ID_THROW_IT_WHILE_NOT_RUNNING_, name());
2022315SN/A
2032761Sstever@eecs.umich.edu    if (inc_kids)
2042155SN/A        forEachKid([&exc](Process *p) { p->throw_it(exc, true); });
2052155SN/A
2062155SN/A    if (_needsStart || _terminated ||
2072155SN/A            procKind() == ::sc_core::SC_METHOD_PROC_) {
2082155SN/A        SC_REPORT_WARNING(sc_core::SC_ID_THROW_IT_IGNORED_, name());
2092155SN/A        return;
2102155SN/A    }
2112155SN/A
212    injectException(exc);
213}
214
215void
216Process::injectException(ExceptionWrapperBase &exc)
217{
218    excWrapper = &exc;
219    scheduler.runNow(this);
220};
221
222void
223Process::syncResetOn(bool inc_kids)
224{
225    if (inc_kids)
226        forEachKid([](Process *p) { p->syncResetOn(true); });
227
228    _syncReset = true;
229}
230
231void
232Process::syncResetOff(bool inc_kids)
233{
234    if (inc_kids)
235        forEachKid([](Process *p) { p->syncResetOff(true); });
236
237    _syncReset = false;
238}
239
240void
241Process::signalReset(bool set, bool sync)
242{
243    if (set) {
244        waitCount(0);
245        if (sync) {
246            syncResetCount++;
247        } else {
248            asyncResetCount++;
249            cancelTimeout();
250            clearDynamic();
251            scheduler.runNext(this);
252        }
253    } else {
254        if (sync)
255            syncResetCount--;
256        else
257            asyncResetCount--;
258    }
259}
260
261void
262Process::run()
263{
264    bool reset;
265    do {
266        reset = false;
267        try {
268            func->call();
269        } catch(ScHalt) {
270            std::cout << "Terminating process " << name() << std::endl;
271        } catch(const ::sc_core::sc_unwind_exception &exc) {
272            reset = exc.is_reset();
273            _isUnwinding = false;
274        } catch (...) {
275            throw;
276        }
277    } while (reset);
278    needsStart(true);
279}
280
281void
282Process::addStatic(StaticSensitivity *s)
283{
284    staticSensitivities.push_back(s);
285}
286
287void
288Process::setDynamic(DynamicSensitivity *s)
289{
290    if (dynamicSensitivity) {
291        dynamicSensitivity->clear();
292        delete dynamicSensitivity;
293    }
294    dynamicSensitivity = s;
295}
296
297void
298Process::addReset(Reset *reset)
299{
300    resets.push_back(reset);
301}
302
303void
304Process::cancelTimeout()
305{
306    if (timeoutEvent.scheduled())
307        scheduler.deschedule(&timeoutEvent);
308}
309
310void
311Process::setTimeout(::sc_core::sc_time t)
312{
313    cancelTimeout();
314    scheduler.schedule(&timeoutEvent, t);
315}
316
317void
318Process::timeout()
319{
320    // A process is considered timed_out only if it was also waiting for an
321    // event but got a timeout instead.
322    _timedOut = (dynamicSensitivity != nullptr);
323
324    setDynamic(nullptr);
325    if (disabled())
326        return;
327
328    ready();
329}
330
331void
332Process::satisfySensitivity(Sensitivity *s)
333{
334    if (_waitCount) {
335        _waitCount--;
336        return;
337    }
338
339    // If there's a dynamic sensitivity and this wasn't it, ignore.
340    if ((dynamicSensitivity || timeoutEvent.scheduled()) &&
341            dynamicSensitivity != s) {
342        return;
343    }
344
345    _timedOut = false;
346    // This sensitivity should already be cleared by this point, or the event
347    // which triggered it will take care of it.
348    delete dynamicSensitivity;
349    dynamicSensitivity = nullptr;
350    cancelTimeout();
351    ready();
352}
353
354void
355Process::ready()
356{
357    if (disabled())
358        return;
359    if (suspended())
360        _suspendedReady = true;
361    else if (!scheduled())
362        scheduler.ready(this);
363}
364
365void
366Process::lastReport(::sc_core::sc_report *report)
367{
368    if (report) {
369        _lastReport = std::unique_ptr<::sc_core::sc_report>(
370                new ::sc_core::sc_report(*report));
371    } else {
372        _lastReport = nullptr;
373    }
374}
375
376::sc_core::sc_report *Process::lastReport() const { return _lastReport.get(); }
377
378Process::Process(const char *name, ProcessFuncWrapper *func, bool internal) :
379    ::sc_core::sc_process_b(name), excWrapper(nullptr),
380    timeoutEvent([this]() { this->timeout(); }),
381    func(func), _internal(internal), _timedOut(false), _dontInitialize(false),
382    _needsStart(true), _isUnwinding(false), _terminated(false),
383    _scheduled(false), _suspended(false), _disabled(false),
384    _syncReset(false), syncResetCount(0), asyncResetCount(0), _waitCount(0),
385    refCount(0), stackSize(::Fiber::DefaultStackSize),
386    dynamicSensitivity(nullptr)
387{
388    _dynamic =
389            (::sc_core::sc_get_status() >
390             ::sc_core::SC_BEFORE_END_OF_ELABORATION);
391    _newest = this;
392}
393
394void
395Process::terminate()
396{
397    _terminated = true;
398    _suspendedReady = false;
399    _suspended = false;
400    _syncReset = false;
401    clearDynamic();
402    cancelTimeout();
403    for (auto s: staticSensitivities) {
404        s->clear();
405        delete s;
406    }
407    staticSensitivities.clear();
408
409    _terminatedEvent.notify();
410
411    for (auto jw: joinWaiters)
412        jw->signal();
413    joinWaiters.clear();
414}
415
416Process *Process::_newest;
417
418void
419throw_it_wrapper(Process *p, ExceptionWrapperBase &exc, bool inc_kids)
420{
421    p->throw_it(exc, inc_kids);
422}
423
424void
425newReset(const sc_core::sc_port_base *pb, Process *p, bool s, bool v)
426{
427    Port *port = Port::fromPort(pb);
428    port->addReset(new Reset(p, s, v));
429}
430
431void
432newReset(const sc_core::sc_signal_in_if<bool> *sig, Process *p, bool s, bool v)
433{
434    Reset *reset = new Reset(p, s, v);
435    if (!reset->install(sig))
436        delete reset;
437}
438
439} // namespace sc_gem5
440