process.cc revision 13102:f9a4fa519bb3
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/process.hh"
31
32#include "base/logging.hh"
33#include "systemc/core/event.hh"
34#include "systemc/core/scheduler.hh"
35#include "systemc/ext/core/sc_main.hh"
36#include "systemc/ext/core/sc_process_handle.hh"
37#include "systemc/ext/utils/sc_report_handler.hh"
38
39namespace sc_gem5
40{
41
42SensitivityTimeout::SensitivityTimeout(Process *p, ::sc_core::sc_time t) :
43    Sensitivity(p), timeoutEvent([this]() { this->timeout(); })
44{
45    scheduler.schedule(&timeoutEvent, t);
46}
47
48SensitivityTimeout::~SensitivityTimeout()
49{
50    if (timeoutEvent.scheduled())
51        scheduler.deschedule(&timeoutEvent);
52}
53
54void
55SensitivityTimeout::timeout()
56{
57    notify();
58}
59
60SensitivityEvent::SensitivityEvent(
61        Process *p, const ::sc_core::sc_event *e) : Sensitivity(p), event(e)
62{
63    Event::getFromScEvent(event)->addSensitivity(this);
64}
65
66SensitivityEvent::~SensitivityEvent()
67{
68    Event::getFromScEvent(event)->delSensitivity(this);
69}
70
71SensitivityEventAndList::SensitivityEventAndList(
72        Process *p, const ::sc_core::sc_event_and_list *list) :
73    Sensitivity(p), list(list), count(0)
74{
75    for (auto e: list->events)
76        Event::getFromScEvent(e)->addSensitivity(this);
77}
78
79SensitivityEventAndList::~SensitivityEventAndList()
80{
81    for (auto e: list->events)
82        Event::getFromScEvent(e)->delSensitivity(this);
83}
84
85void
86SensitivityEventAndList::notifyWork(Event *e)
87{
88    e->delSensitivity(this);
89    count++;
90    if (count == list->events.size())
91        process->satisfySensitivity(this);
92}
93
94SensitivityEventOrList::SensitivityEventOrList(
95        Process *p, const ::sc_core::sc_event_or_list *list) :
96    Sensitivity(p), list(list)
97{
98    for (auto e: list->events)
99        Event::getFromScEvent(e)->addSensitivity(this);
100}
101
102SensitivityEventOrList::~SensitivityEventOrList()
103{
104    for (auto e: list->events)
105        Event::getFromScEvent(e)->delSensitivity(this);
106}
107
108void
109SensitivityTimeoutAndEventAndList::notifyWork(Event *e)
110{
111    if (e) {
112        // An event went off which must be part of the sc_event_and_list.
113        SensitivityEventAndList::notifyWork(e);
114    } else {
115        // There's no inciting event, so this must be a timeout.
116        SensitivityTimeout::notifyWork(e);
117    }
118}
119
120
121class UnwindExceptionReset : public ::sc_core::sc_unwind_exception
122{
123  public:
124    UnwindExceptionReset() { _isReset = true; }
125};
126
127class UnwindExceptionKill : public ::sc_core::sc_unwind_exception
128{
129  public:
130    UnwindExceptionKill() {}
131};
132
133template <typename T>
134struct BuiltinExceptionWrapper : public ExceptionWrapperBase
135{
136  public:
137    T t;
138    void throw_it() override { throw t; }
139};
140
141BuiltinExceptionWrapper<UnwindExceptionReset> resetException;
142BuiltinExceptionWrapper<UnwindExceptionKill> killException;
143
144
145void
146Process::forEachKid(const std::function<void(Process *)> &work)
147{
148    for (auto &kid: get_child_objects()) {
149        Process *p_kid = dynamic_cast<Process *>(kid);
150        if (p_kid)
151            work(p_kid);
152    }
153}
154
155void
156Process::suspend(bool inc_kids)
157{
158    if (inc_kids)
159        forEachKid([](Process *p) { p->suspend(true); });
160
161    if (!_suspended) {
162        _suspended = true;
163        _suspendedReady = false;
164    }
165
166    if (procKind() != ::sc_core::SC_METHOD_PROC_ &&
167            scheduler.current() == this) {
168        scheduler.yield();
169    }
170}
171
172void
173Process::resume(bool inc_kids)
174{
175    if (inc_kids)
176        forEachKid([](Process *p) { p->resume(true); });
177
178    if (_suspended) {
179        _suspended = false;
180        if (_suspendedReady)
181            ready();
182        _suspendedReady = false;
183    }
184}
185
186void
187Process::disable(bool inc_kids)
188{
189    if (inc_kids)
190        forEachKid([](Process *p) { p->disable(true); });
191
192    if (!::sc_core::sc_allow_process_control_corners &&
193            dynamic_cast<SensitivityTimeout *>(dynamicSensitivity)) {
194        std::string message("attempt to disable a thread with timeout wait: ");
195        message += name();
196        SC_REPORT_ERROR("Undefined process control interaction",
197                message.c_str());
198    }
199
200    _disabled = true;
201}
202
203void
204Process::enable(bool inc_kids)
205{
206
207    if (inc_kids)
208        forEachKid([](Process *p) { p->enable(true); });
209
210    _disabled = false;
211}
212
213void
214Process::kill(bool inc_kids)
215{
216    if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) {
217        SC_REPORT_ERROR(
218                "(E572) a process may not be killed before it is initialized",
219                name());
220    }
221
222    // Propogate the kill to our children no matter what happens to us.
223    if (inc_kids)
224        forEachKid([](Process *p) { p->kill(true); });
225
226    // If we're in the middle of unwinding, ignore the kill request.
227    if (_isUnwinding)
228        return;
229
230    // Update our state.
231    terminate();
232    _isUnwinding = true;
233
234    // Make sure this process isn't marked ready
235    popListNode();
236
237    // Inject the kill exception into this process if it's started.
238    if (!_needsStart)
239        injectException(killException);
240}
241
242void
243Process::reset(bool inc_kids)
244{
245    if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) {
246        SC_REPORT_ERROR(
247                "(E573) a process may not be asynchronously reset while"
248                "the simulation is not running", name());
249    }
250
251    // Propogate the reset to our children no matter what happens to us.
252    if (inc_kids)
253        forEachKid([](Process *p) { p->reset(true); });
254
255    // If we're in the middle of unwinding, ignore the reset request.
256    if (_isUnwinding)
257        return;
258
259
260    if (_needsStart) {
261        scheduler.runNow(this);
262    } else {
263        _isUnwinding = true;
264        injectException(resetException);
265    }
266
267    _resetEvent.notify();
268}
269
270void
271Process::throw_it(ExceptionWrapperBase &exc, bool inc_kids)
272{
273    if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) {
274        SC_REPORT_ERROR(
275                "(E574) throw_it not allowed unless simulation is running ",
276                name());
277    }
278
279    if (inc_kids)
280        forEachKid([&exc](Process *p) { p->throw_it(exc, true); });
281
282    // Only inject an exception into threads that have started.
283    if (!_needsStart)
284        injectException(exc);
285}
286
287void
288Process::injectException(ExceptionWrapperBase &exc)
289{
290    excWrapper = &exc;
291    scheduler.runNow(this);
292};
293
294void
295Process::syncResetOn(bool inc_kids)
296{
297    if (inc_kids)
298        forEachKid([](Process *p) { p->syncResetOn(true); });
299
300    _syncReset = true;
301}
302
303void
304Process::syncResetOff(bool inc_kids)
305{
306    if (inc_kids)
307        forEachKid([](Process *p) { p->syncResetOff(true); });
308
309    _syncReset = false;
310}
311
312void
313Process::dontInitialize()
314{
315    scheduler.dontInitialize(this);
316}
317
318void
319Process::finalize()
320{
321    for (auto &s: pendingStaticSensitivities) {
322        s->finalize(staticSensitivities);
323        delete s;
324        s = nullptr;
325    }
326    pendingStaticSensitivities.clear();
327};
328
329void
330Process::run()
331{
332    bool reset;
333    do {
334        reset = false;
335        try {
336            func->call();
337        } catch(const ::sc_core::sc_unwind_exception &exc) {
338            reset = exc.is_reset();
339            _isUnwinding = false;
340        }
341    } while (reset);
342    needsStart(true);
343}
344
345void
346Process::addStatic(PendingSensitivity *s)
347{
348    pendingStaticSensitivities.push_back(s);
349}
350
351void
352Process::setDynamic(Sensitivity *s)
353{
354    delete dynamicSensitivity;
355    dynamicSensitivity = s;
356}
357
358void
359Process::satisfySensitivity(Sensitivity *s)
360{
361    // If there's a dynamic sensitivity and this wasn't it, ignore.
362    if (dynamicSensitivity && dynamicSensitivity != s)
363        return;
364
365    setDynamic(nullptr);
366    ready();
367}
368
369void
370Process::ready()
371{
372    if (disabled())
373        return;
374    if (suspended())
375        _suspendedReady = true;
376    else
377        scheduler.ready(this);
378}
379
380void
381Process::lastReport(::sc_core::sc_report *report)
382{
383    if (report) {
384        _lastReport = std::unique_ptr<::sc_core::sc_report>(
385                new ::sc_core::sc_report(*report));
386    } else {
387        _lastReport = nullptr;
388    }
389}
390
391::sc_core::sc_report *Process::lastReport() const { return _lastReport.get(); }
392
393Process::Process(const char *name, ProcessFuncWrapper *func, bool _dynamic) :
394    ::sc_core::sc_process_b(name), excWrapper(nullptr), func(func),
395    _needsStart(true), _dynamic(_dynamic), _isUnwinding(false),
396    _terminated(false), _suspended(false), _disabled(false),
397    _syncReset(false), refCount(0), stackSize(::Fiber::DefaultStackSize),
398    dynamicSensitivity(nullptr)
399{
400    _newest = this;
401}
402
403void
404Process::terminate()
405{
406    _terminated = true;
407    _suspendedReady = false;
408    _suspended = false;
409    _syncReset = false;
410    delete dynamicSensitivity;
411    dynamicSensitivity = nullptr;
412    for (auto s: staticSensitivities)
413        delete s;
414    staticSensitivities.clear();
415
416    _terminatedEvent.notify();
417}
418
419Process *Process::_newest;
420
421void
422throw_it_wrapper(Process *p, ExceptionWrapperBase &exc, bool inc_kids)
423{
424    p->throw_it(exc, inc_kids);
425}
426
427} // namespace sc_gem5
428