process.cc revision 13087:1df34ed84a4b
112854Sgabeblack@google.com/*
212854Sgabeblack@google.com * Copyright 2018 Google, Inc.
312854Sgabeblack@google.com *
412854Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
512854Sgabeblack@google.com * modification, are permitted provided that the following conditions are
612854Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
712854Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
812854Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
912854Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
1012854Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
1112854Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
1212854Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
1312854Sgabeblack@google.com * this software without specific prior written permission.
1412854Sgabeblack@google.com *
1512854Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1612854Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1712854Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1812854Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1912854Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2012854Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2112854Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2212854Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2312854Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2412854Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2512854Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2612854Sgabeblack@google.com *
2712854Sgabeblack@google.com * Authors: Gabe Black
2812854Sgabeblack@google.com */
2912854Sgabeblack@google.com
3012854Sgabeblack@google.com#include "systemc/core/process.hh"
3112854Sgabeblack@google.com
3212854Sgabeblack@google.com#include "base/logging.hh"
3312854Sgabeblack@google.com#include "systemc/core/event.hh"
3412854Sgabeblack@google.com#include "systemc/core/scheduler.hh"
3512854Sgabeblack@google.com#include "systemc/ext/core/sc_process_handle.hh"
3612854Sgabeblack@google.com#include "systemc/ext/utils/sc_report_handler.hh"
3712854Sgabeblack@google.com
3812854Sgabeblack@google.comnamespace sc_gem5
3912854Sgabeblack@google.com{
4012854Sgabeblack@google.com
4112854Sgabeblack@google.comSensitivityTimeout::SensitivityTimeout(Process *p, ::sc_core::sc_time t) :
4212854Sgabeblack@google.com    Sensitivity(p), timeoutEvent([this]() { this->timeout(); })
4312854Sgabeblack@google.com{
4412854Sgabeblack@google.com    scheduler.schedule(&timeoutEvent, t);
4512854Sgabeblack@google.com}
4612854Sgabeblack@google.com
4712854Sgabeblack@google.comSensitivityTimeout::~SensitivityTimeout()
4812854Sgabeblack@google.com{
4912854Sgabeblack@google.com    if (timeoutEvent.scheduled())
5012854Sgabeblack@google.com        scheduler.deschedule(&timeoutEvent);
5112854Sgabeblack@google.com}
5212854Sgabeblack@google.com
5312854Sgabeblack@google.comvoid
5412854Sgabeblack@google.comSensitivityTimeout::timeout()
5512854Sgabeblack@google.com{
5612854Sgabeblack@google.com    notify();
5712854Sgabeblack@google.com}
5812854Sgabeblack@google.com
5912854Sgabeblack@google.comSensitivityEvent::SensitivityEvent(
6012854Sgabeblack@google.com        Process *p, const ::sc_core::sc_event *e) : Sensitivity(p), event(e)
6112854Sgabeblack@google.com{
6212854Sgabeblack@google.com    Event::getFromScEvent(event)->addSensitivity(this);
6312854Sgabeblack@google.com}
6412854Sgabeblack@google.com
6512854Sgabeblack@google.comSensitivityEvent::~SensitivityEvent()
6612854Sgabeblack@google.com{
6712854Sgabeblack@google.com    Event::getFromScEvent(event)->delSensitivity(this);
6812854Sgabeblack@google.com}
6912854Sgabeblack@google.com
7012854Sgabeblack@google.comSensitivityEventAndList::SensitivityEventAndList(
7112854Sgabeblack@google.com        Process *p, const ::sc_core::sc_event_and_list *list) :
7212854Sgabeblack@google.com    Sensitivity(p), list(list), count(0)
7312854Sgabeblack@google.com{
7412854Sgabeblack@google.com    for (auto e: list->events)
7512854Sgabeblack@google.com        Event::getFromScEvent(e)->addSensitivity(this);
7612854Sgabeblack@google.com}
7712854Sgabeblack@google.com
7812854Sgabeblack@google.comSensitivityEventAndList::~SensitivityEventAndList()
7912854Sgabeblack@google.com{
8012854Sgabeblack@google.com    for (auto e: list->events)
8112854Sgabeblack@google.com        Event::getFromScEvent(e)->delSensitivity(this);
8212854Sgabeblack@google.com}
8312854Sgabeblack@google.com
8412854Sgabeblack@google.comvoid
8512854Sgabeblack@google.comSensitivityEventAndList::notifyWork(Event *e)
8612854Sgabeblack@google.com{
8712854Sgabeblack@google.com    e->delSensitivity(this);
8812854Sgabeblack@google.com    count++;
8912854Sgabeblack@google.com    if (count == list->events.size())
9012854Sgabeblack@google.com        process->satisfySensitivity(this);
9112854Sgabeblack@google.com}
9213322Sgabeblack@google.com
9312854Sgabeblack@google.comSensitivityEventOrList::SensitivityEventOrList(
9412854Sgabeblack@google.com        Process *p, const ::sc_core::sc_event_or_list *list) :
9512854Sgabeblack@google.com    Sensitivity(p), list(list)
9612854Sgabeblack@google.com{
9712854Sgabeblack@google.com    for (auto e: list->events)
9812854Sgabeblack@google.com        Event::getFromScEvent(e)->addSensitivity(this);
9912854Sgabeblack@google.com}
10012854Sgabeblack@google.com
10112854Sgabeblack@google.comSensitivityEventOrList::~SensitivityEventOrList()
10212854Sgabeblack@google.com{
10312854Sgabeblack@google.com    for (auto e: list->events)
10412854Sgabeblack@google.com        Event::getFromScEvent(e)->delSensitivity(this);
10512854Sgabeblack@google.com}
10612854Sgabeblack@google.com
10712854Sgabeblack@google.comvoid
10812854Sgabeblack@google.comSensitivityTimeoutAndEventAndList::notifyWork(Event *e)
10912854Sgabeblack@google.com{
11012854Sgabeblack@google.com    if (e) {
11112854Sgabeblack@google.com        // An event went off which must be part of the sc_event_and_list.
11212854Sgabeblack@google.com        SensitivityEventAndList::notifyWork(e);
11312854Sgabeblack@google.com    } else {
11412854Sgabeblack@google.com        // There's no inciting event, so this must be a timeout.
11512854Sgabeblack@google.com        SensitivityTimeout::notifyWork(e);
11612854Sgabeblack@google.com    }
11712854Sgabeblack@google.com}
11812854Sgabeblack@google.com
11912854Sgabeblack@google.com
12012854Sgabeblack@google.comclass UnwindExceptionReset : public ::sc_core::sc_unwind_exception
12112854Sgabeblack@google.com{
12212854Sgabeblack@google.com  public:
12312854Sgabeblack@google.com    UnwindExceptionReset() { _isReset = true; }
12412854Sgabeblack@google.com};
12512854Sgabeblack@google.com
12612854Sgabeblack@google.comclass UnwindExceptionKill : public ::sc_core::sc_unwind_exception
12712854Sgabeblack@google.com{
12812854Sgabeblack@google.com  public:
12912854Sgabeblack@google.com    UnwindExceptionKill() {}
13012854Sgabeblack@google.com};
13112854Sgabeblack@google.com
13212854Sgabeblack@google.comtemplate <typename T>
13312854Sgabeblack@google.comstruct BuiltinExceptionWrapper : public ExceptionWrapperBase
13412854Sgabeblack@google.com{
13513322Sgabeblack@google.com  public:
13612854Sgabeblack@google.com    T t;
13712854Sgabeblack@google.com    void throw_it() override { throw t; }
13812854Sgabeblack@google.com};
13912854Sgabeblack@google.com
14012854Sgabeblack@google.comBuiltinExceptionWrapper<UnwindExceptionReset> resetException;
14112854Sgabeblack@google.comBuiltinExceptionWrapper<UnwindExceptionKill> killException;
14212854Sgabeblack@google.com
14312854Sgabeblack@google.com
14413160Sgabeblack@google.comvoid
14512854Sgabeblack@google.comProcess::forEachKid(const std::function<void(Process *)> &work)
14612854Sgabeblack@google.com{
14713322Sgabeblack@google.com    for (auto &kid: get_child_objects()) {
14812854Sgabeblack@google.com        Process *p_kid = dynamic_cast<Process *>(kid);
14912854Sgabeblack@google.com        if (p_kid)
15012854Sgabeblack@google.com            work(p_kid);
15112854Sgabeblack@google.com    }
15212854Sgabeblack@google.com}
15312854Sgabeblack@google.com
15412854Sgabeblack@google.comvoid
15512854Sgabeblack@google.comProcess::suspend(bool inc_kids)
15612854Sgabeblack@google.com{
15712854Sgabeblack@google.com    if (inc_kids)
15812854Sgabeblack@google.com        forEachKid([](Process *p) { p->suspend(true); });
15912854Sgabeblack@google.com
16012854Sgabeblack@google.com    if (!_suspended) {
16112854Sgabeblack@google.com        _suspended = true;
16212854Sgabeblack@google.com        _suspendedReady = false;
16312854Sgabeblack@google.com    }
16412854Sgabeblack@google.com
16512854Sgabeblack@google.com    if (procKind() != ::sc_core::SC_METHOD_PROC_ &&
16612854Sgabeblack@google.com            scheduler.current() == this) {
16712854Sgabeblack@google.com        scheduler.yield();
16812854Sgabeblack@google.com    }
16912854Sgabeblack@google.com}
17012854Sgabeblack@google.com
17112854Sgabeblack@google.comvoid
17212854Sgabeblack@google.comProcess::resume(bool inc_kids)
17312854Sgabeblack@google.com{
17412854Sgabeblack@google.com    if (inc_kids)
17512854Sgabeblack@google.com        forEachKid([](Process *p) { p->resume(true); });
17612854Sgabeblack@google.com
17712854Sgabeblack@google.com    if (_suspended) {
17812854Sgabeblack@google.com        _suspended = false;
17912854Sgabeblack@google.com        if (_suspendedReady)
18012854Sgabeblack@google.com            ready();
18112854Sgabeblack@google.com        _suspendedReady = false;
18212854Sgabeblack@google.com    }
18312854Sgabeblack@google.com}
18412854Sgabeblack@google.com
18512854Sgabeblack@google.comvoid
18612854Sgabeblack@google.comProcess::disable(bool inc_kids)
18712854Sgabeblack@google.com{
18812854Sgabeblack@google.com    if (inc_kids)
18912854Sgabeblack@google.com        forEachKid([](Process *p) { p->disable(true); });
19012854Sgabeblack@google.com
19112854Sgabeblack@google.com    if (!::sc_core::sc_allow_process_control_corners &&
19212854Sgabeblack@google.com            dynamic_cast<SensitivityTimeout *>(dynamicSensitivity)) {
19312854Sgabeblack@google.com        std::string message("attempt to disable a thread with timeout wait: ");
19412854Sgabeblack@google.com        message += name();
19512854Sgabeblack@google.com        SC_REPORT_ERROR("Undefined process control interaction",
19612854Sgabeblack@google.com                message.c_str());
19712854Sgabeblack@google.com    }
19812854Sgabeblack@google.com
19912854Sgabeblack@google.com    _disabled = true;
20012854Sgabeblack@google.com}
20112854Sgabeblack@google.com
20212854Sgabeblack@google.comvoid
20312854Sgabeblack@google.comProcess::enable(bool inc_kids)
20412854Sgabeblack@google.com{
20512854Sgabeblack@google.com
20612854Sgabeblack@google.com    if (inc_kids)
20712854Sgabeblack@google.com        forEachKid([](Process *p) { p->enable(true); });
20812854Sgabeblack@google.com
20912854Sgabeblack@google.com    _disabled = false;
21012854Sgabeblack@google.com}
21112854Sgabeblack@google.com
21212854Sgabeblack@google.comvoid
21312854Sgabeblack@google.comProcess::kill(bool inc_kids)
21412854Sgabeblack@google.com{
21512854Sgabeblack@google.com    // Propogate the kill to our children no matter what happens to us.
21612854Sgabeblack@google.com    if (inc_kids)
21712854Sgabeblack@google.com        forEachKid([](Process *p) { p->kill(true); });
21812854Sgabeblack@google.com
21912854Sgabeblack@google.com    // If we're in the middle of unwinding, ignore the kill request.
22012854Sgabeblack@google.com    if (_isUnwinding)
22112854Sgabeblack@google.com        return;
22212854Sgabeblack@google.com
22312854Sgabeblack@google.com    // Update our state.
22412854Sgabeblack@google.com    terminate();
22512854Sgabeblack@google.com    _isUnwinding = true;
22612854Sgabeblack@google.com
22712854Sgabeblack@google.com    // Make sure this process isn't marked ready
22812854Sgabeblack@google.com    popListNode();
22912854Sgabeblack@google.com
23012854Sgabeblack@google.com    // Inject the kill exception into this process if it's started.
23112854Sgabeblack@google.com    if (!_needsStart)
23212854Sgabeblack@google.com        injectException(killException);
23312854Sgabeblack@google.com}
23412854Sgabeblack@google.com
23512854Sgabeblack@google.comvoid
23612854Sgabeblack@google.comProcess::reset(bool inc_kids)
23712854Sgabeblack@google.com{
23812854Sgabeblack@google.com    // Propogate the reset to our children no matter what happens to us.
23912854Sgabeblack@google.com    if (inc_kids)
24012854Sgabeblack@google.com        forEachKid([](Process *p) { p->reset(true); });
24112854Sgabeblack@google.com
24212854Sgabeblack@google.com    // If we're in the middle of unwinding, ignore the reset request.
24312854Sgabeblack@google.com    if (_isUnwinding)
24412854Sgabeblack@google.com        return;
24512854Sgabeblack@google.com
24612854Sgabeblack@google.com
24712854Sgabeblack@google.com    if (_needsStart) {
24812854Sgabeblack@google.com        scheduler.runNow(this);
24912854Sgabeblack@google.com    } else {
25012854Sgabeblack@google.com        _isUnwinding = true;
25112854Sgabeblack@google.com        injectException(resetException);
25212854Sgabeblack@google.com    }
25312854Sgabeblack@google.com
25412854Sgabeblack@google.com    _resetEvent.notify();
25512854Sgabeblack@google.com}
25612854Sgabeblack@google.com
25712854Sgabeblack@google.comvoid
25812854Sgabeblack@google.comProcess::throw_it(ExceptionWrapperBase &exc, bool inc_kids)
25912854Sgabeblack@google.com{
26012854Sgabeblack@google.com    if (inc_kids)
26112854Sgabeblack@google.com        forEachKid([&exc](Process *p) { p->throw_it(exc, true); });
26212854Sgabeblack@google.com
26312854Sgabeblack@google.com    // Only inject an exception into threads that have started.
26412854Sgabeblack@google.com    if (!_needsStart)
26512854Sgabeblack@google.com        injectException(exc);
26612854Sgabeblack@google.com}
26712854Sgabeblack@google.com
26812854Sgabeblack@google.comvoid
26912854Sgabeblack@google.comProcess::injectException(ExceptionWrapperBase &exc)
27012854Sgabeblack@google.com{
27112854Sgabeblack@google.com    excWrapper = &exc;
27212854Sgabeblack@google.com    scheduler.runNow(this);
27312854Sgabeblack@google.com};
27412854Sgabeblack@google.com
27512854Sgabeblack@google.comvoid
27612854Sgabeblack@google.comProcess::syncResetOn(bool inc_kids)
27712854Sgabeblack@google.com{
27812854Sgabeblack@google.com    if (inc_kids)
27912854Sgabeblack@google.com        forEachKid([](Process *p) { p->syncResetOn(true); });
28012854Sgabeblack@google.com
28112854Sgabeblack@google.com    _syncReset = true;
28212854Sgabeblack@google.com}
28312854Sgabeblack@google.com
28412854Sgabeblack@google.comvoid
28512854Sgabeblack@google.comProcess::syncResetOff(bool inc_kids)
28612854Sgabeblack@google.com{
28712854Sgabeblack@google.com    if (inc_kids)
28812854Sgabeblack@google.com        forEachKid([](Process *p) { p->syncResetOff(true); });
28912854Sgabeblack@google.com
29012854Sgabeblack@google.com    _syncReset = false;
29112854Sgabeblack@google.com}
29212854Sgabeblack@google.com
29312854Sgabeblack@google.comvoid
29412854Sgabeblack@google.comProcess::dontInitialize()
29512854Sgabeblack@google.com{
29612854Sgabeblack@google.com    scheduler.dontInitialize(this);
29712854Sgabeblack@google.com}
29812854Sgabeblack@google.com
29912854Sgabeblack@google.comvoid
30012854Sgabeblack@google.comProcess::finalize()
30112854Sgabeblack@google.com{
30212854Sgabeblack@google.com    for (auto &s: pendingStaticSensitivities) {
30312854Sgabeblack@google.com        s->finalize(staticSensitivities);
30412854Sgabeblack@google.com        delete s;
30512854Sgabeblack@google.com        s = nullptr;
30612854Sgabeblack@google.com    }
30712854Sgabeblack@google.com    pendingStaticSensitivities.clear();
30812854Sgabeblack@google.com};
30912854Sgabeblack@google.com
31012854Sgabeblack@google.comvoid
31112854Sgabeblack@google.comProcess::run()
31212854Sgabeblack@google.com{
31312854Sgabeblack@google.com    bool reset;
31412854Sgabeblack@google.com    do {
31512854Sgabeblack@google.com        reset = false;
31612854Sgabeblack@google.com        try {
31712854Sgabeblack@google.com            func->call();
31812854Sgabeblack@google.com        } catch(const ::sc_core::sc_unwind_exception &exc) {
31912854Sgabeblack@google.com            reset = exc.is_reset();
32012854Sgabeblack@google.com            _isUnwinding = false;
32112854Sgabeblack@google.com        }
32212854Sgabeblack@google.com    } while (reset);
32312854Sgabeblack@google.com}
32412854Sgabeblack@google.com
32512854Sgabeblack@google.comvoid
32612854Sgabeblack@google.comProcess::addStatic(PendingSensitivity *s)
32712854Sgabeblack@google.com{
32812854Sgabeblack@google.com    pendingStaticSensitivities.push_back(s);
32912854Sgabeblack@google.com}
33012854Sgabeblack@google.com
33112854Sgabeblack@google.comvoid
33212854Sgabeblack@google.comProcess::setDynamic(Sensitivity *s)
33312854Sgabeblack@google.com{
33412854Sgabeblack@google.com    delete dynamicSensitivity;
33512854Sgabeblack@google.com    dynamicSensitivity = s;
33612854Sgabeblack@google.com}
33712854Sgabeblack@google.com
33812854Sgabeblack@google.comvoid
33912854Sgabeblack@google.comProcess::satisfySensitivity(Sensitivity *s)
34012854Sgabeblack@google.com{
34112854Sgabeblack@google.com    // If there's a dynamic sensitivity and this wasn't it, ignore.
34212854Sgabeblack@google.com    if (dynamicSensitivity && dynamicSensitivity != s)
34312854Sgabeblack@google.com        return;
34412854Sgabeblack@google.com
34512854Sgabeblack@google.com    setDynamic(nullptr);
34612854Sgabeblack@google.com    ready();
34712854Sgabeblack@google.com}
34812854Sgabeblack@google.com
34912854Sgabeblack@google.comvoid
35012854Sgabeblack@google.comProcess::ready()
35112854Sgabeblack@google.com{
35212854Sgabeblack@google.com    if (disabled())
35312854Sgabeblack@google.com        return;
35412854Sgabeblack@google.com    if (suspended())
35512854Sgabeblack@google.com        _suspendedReady = true;
35612854Sgabeblack@google.com    else
35712854Sgabeblack@google.com        scheduler.ready(this);
35812854Sgabeblack@google.com}
35912854Sgabeblack@google.com
36012854Sgabeblack@google.comvoid
36112854Sgabeblack@google.comProcess::lastReport(::sc_core::sc_report *report)
36212854Sgabeblack@google.com{
36312854Sgabeblack@google.com    if (report) {
36412854Sgabeblack@google.com        _lastReport = std::unique_ptr<::sc_core::sc_report>(
36512854Sgabeblack@google.com                new ::sc_core::sc_report(*report));
36612854Sgabeblack@google.com    } else {
36712854Sgabeblack@google.com        _lastReport = nullptr;
36812854Sgabeblack@google.com    }
36912854Sgabeblack@google.com}
37012854Sgabeblack@google.com
37112854Sgabeblack@google.com::sc_core::sc_report *Process::lastReport() const { return _lastReport.get(); }
37212854Sgabeblack@google.com
37312854Sgabeblack@google.comProcess::Process(const char *name, ProcessFuncWrapper *func, bool _dynamic) :
37412854Sgabeblack@google.com    ::sc_core::sc_process_b(name), excWrapper(nullptr), func(func),
37512854Sgabeblack@google.com    _needsStart(true), _dynamic(_dynamic), _isUnwinding(false),
37612854Sgabeblack@google.com    _terminated(false), _suspended(false), _disabled(false),
37712854Sgabeblack@google.com    _syncReset(false), refCount(0), stackSize(::Fiber::DefaultStackSize),
37812854Sgabeblack@google.com    dynamicSensitivity(nullptr)
37912854Sgabeblack@google.com{
38012854Sgabeblack@google.com    _newest = this;
38112854Sgabeblack@google.com}
38212854Sgabeblack@google.com
38312854Sgabeblack@google.comvoid
38412854Sgabeblack@google.comProcess::terminate()
38512854Sgabeblack@google.com{
38612854Sgabeblack@google.com    _terminated = true;
38712854Sgabeblack@google.com    _suspendedReady = false;
38812854Sgabeblack@google.com    _suspended = false;
38912854Sgabeblack@google.com    _syncReset = false;
39012854Sgabeblack@google.com    delete dynamicSensitivity;
39112854Sgabeblack@google.com    dynamicSensitivity = nullptr;
39212854Sgabeblack@google.com    for (auto s: staticSensitivities)
39312854Sgabeblack@google.com        delete s;
39412854Sgabeblack@google.com    staticSensitivities.clear();
39512854Sgabeblack@google.com
39612854Sgabeblack@google.com    _terminatedEvent.notify();
39712854Sgabeblack@google.com}
39812854Sgabeblack@google.com
39912854Sgabeblack@google.comProcess *Process::_newest;
40012854Sgabeblack@google.com
40112854Sgabeblack@google.comvoid
40212854Sgabeblack@google.comthrow_it_wrapper(Process *p, ExceptionWrapperBase &exc, bool inc_kids)
40312854Sgabeblack@google.com{
40412854Sgabeblack@google.com    p->throw_it(exc, inc_kids);
40512854Sgabeblack@google.com}
40612854Sgabeblack@google.com
40712854Sgabeblack@google.com} // namespace sc_gem5
40812854Sgabeblack@google.com