2 * Copyright 2018 Google, Inc.
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.
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.
30 #include "systemc/core/process.hh"
32 #include "systemc/core/event.hh"
33 #include "systemc/core/port.hh"
34 #include "systemc/core/scheduler.hh"
35 #include "systemc/ext/core/messages.hh"
36 #include "systemc/ext/core/sc_join.hh"
37 #include "systemc/ext/core/sc_main.hh"
38 #include "systemc/ext/core/sc_process_handle.hh"
39 #include "systemc/ext/utils/sc_report_handler.hh"
44 class UnwindExceptionReset
: public ::sc_core::sc_unwind_exception
47 UnwindExceptionReset() { _isReset
= true; }
50 class UnwindExceptionKill
: public ::sc_core::sc_unwind_exception
53 UnwindExceptionKill() {}
57 struct BuiltinExceptionWrapper
: public ExceptionWrapperBase
61 void throw_it() override
{ throw t
; }
64 BuiltinExceptionWrapper
<UnwindExceptionReset
> resetException
;
65 BuiltinExceptionWrapper
<UnwindExceptionKill
> killException
;
69 Process::forEachKid(const std::function
<void(Process
*)> &work
)
71 for (auto &kid
: get_child_objects()) {
72 Process
*p_kid
= dynamic_cast<Process
*>(kid
);
79 Process::suspend(bool inc_kids
)
82 forEachKid([](Process
*p
) { p
->suspend(true); });
86 _suspendedReady
= scheduler
.suspend(this);
88 if (procKind() != ::sc_core::SC_METHOD_PROC_
&&
89 scheduler
.current() == this) {
90 // This isn't in the spec, but Accellera says that a thread that
91 // self suspends should be marked ready immediately when it's
93 _suspendedReady
= true;
100 Process::resume(bool inc_kids
)
103 forEachKid([](Process
*p
) { p
->resume(true); });
108 scheduler
.resume(this);
109 _suspendedReady
= false;
114 Process::disable(bool inc_kids
)
117 forEachKid([](Process
*p
) { p
->disable(true); });
119 if (!::sc_core::sc_allow_process_control_corners
&&
120 timeoutEvent
.scheduled()) {
121 std::string
message("attempt to disable a thread with timeout wait: ");
123 SC_REPORT_ERROR(sc_core::SC_ID_PROCESS_CONTROL_CORNER_CASE_
,
131 Process::enable(bool inc_kids
)
135 forEachKid([](Process
*p
) { p
->enable(true); });
141 Process::kill(bool inc_kids
)
143 if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING
) {
144 SC_REPORT_ERROR(sc_core::SC_ID_KILL_PROCESS_WHILE_UNITIALIZED_
,
148 // Propogate the kill to our children no matter what happens to us.
150 forEachKid([](Process
*p
) { p
->kill(true); });
152 // If we're in the middle of unwinding, ignore the kill request.
160 // Make sure this process isn't marked ready
163 // Inject the kill exception into this process if it's started.
165 injectException(killException
);
169 Process::reset(bool inc_kids
)
171 if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING
) {
172 SC_REPORT_ERROR(sc_core::SC_ID_RESET_PROCESS_WHILE_NOT_RUNNING_
,
176 // Propogate the reset to our children no matter what happens to us.
178 forEachKid([](Process
*p
) { p
->reset(true); });
180 // If we're in the middle of unwinding, ignore the reset request.
184 // Clear suspended ready since we're about to run regardless.
185 _suspendedReady
= false;
187 _resetEvent
.notify();
190 scheduler
.runNow(this);
193 injectException(resetException
);
198 Process::throw_it(ExceptionWrapperBase
&exc
, bool inc_kids
)
200 if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING
)
201 SC_REPORT_ERROR(sc_core::SC_ID_THROW_IT_WHILE_NOT_RUNNING_
, name());
204 forEachKid([&exc
](Process
*p
) { p
->throw_it(exc
, true); });
206 if (_needsStart
|| _terminated
||
207 procKind() == ::sc_core::SC_METHOD_PROC_
) {
208 SC_REPORT_WARNING(sc_core::SC_ID_THROW_IT_IGNORED_
, name());
212 injectException(exc
);
216 Process::injectException(ExceptionWrapperBase
&exc
)
219 scheduler
.runNow(this);
223 Process::syncResetOn(bool inc_kids
)
226 forEachKid([](Process
*p
) { p
->syncResetOn(true); });
232 Process::syncResetOff(bool inc_kids
)
235 forEachKid([](Process
*p
) { p
->syncResetOff(true); });
241 Process::signalReset(bool set
, bool sync
)
251 scheduler
.runNext(this);
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;
282 Process::addStatic(StaticSensitivity
*s
)
284 staticSensitivities
.push_back(s
);
288 Process::setDynamic(DynamicSensitivity
*s
)
290 if (dynamicSensitivity
) {
291 dynamicSensitivity
->clear();
292 delete dynamicSensitivity
;
294 dynamicSensitivity
= s
;
298 Process::addReset(Reset
*reset
)
300 resets
.push_back(reset
);
304 Process::cancelTimeout()
306 if (timeoutEvent
.scheduled())
307 scheduler
.deschedule(&timeoutEvent
);
311 Process::setTimeout(::sc_core::sc_time t
)
314 scheduler
.schedule(&timeoutEvent
, t
);
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);
332 Process::satisfySensitivity(Sensitivity
*s
)
339 // If there's a dynamic sensitivity and this wasn't it, ignore.
340 if ((dynamicSensitivity
|| timeoutEvent
.scheduled()) &&
341 dynamicSensitivity
!= s
) {
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;
360 _suspendedReady
= true;
361 else if (!scheduled())
362 scheduler
.ready(this);
366 Process::lastReport(::sc_core::sc_report
*report
)
369 _lastReport
= std::unique_ptr
<::sc_core::sc_report
>(
370 new ::sc_core::sc_report(*report
));
372 _lastReport
= nullptr;
376 ::sc_core::sc_report
*Process::lastReport() const { return _lastReport
.get(); }
378 Process::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)
389 (::sc_core::sc_get_status() >
390 ::sc_core::SC_BEFORE_END_OF_ELABORATION
);
398 _suspendedReady
= false;
403 for (auto s
: staticSensitivities
) {
407 staticSensitivities
.clear();
409 _terminatedEvent
.notify();
411 for (auto jw
: joinWaiters
)
416 Process
*Process::_newest
;
419 throw_it_wrapper(Process
*p
, ExceptionWrapperBase
&exc
, bool inc_kids
)
421 p
->throw_it(exc
, inc_kids
);
425 newReset(const sc_core::sc_port_base
*pb
, Process
*p
, bool s
, bool v
)
427 Port
*port
= Port::fromPort(pb
);
428 port
->addReset(new Reset(p
, s
, v
));
432 newReset(const sc_core::sc_signal_in_if
<bool> *sig
, Process
*p
, bool s
, bool v
)
434 Reset
*reset
= new Reset(p
, s
, v
);
435 if (!reset
->install(sig
))
439 } // namespace sc_gem5