process.cc revision 13328:d5f4e801436a
112839Sgabeblack@google.com/* 212839Sgabeblack@google.com * Copyright 2018 Google, Inc. 312839Sgabeblack@google.com * 412839Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 512839Sgabeblack@google.com * modification, are permitted provided that the following conditions are 612839Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 712839Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 812839Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 912839Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 1012839Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 1112839Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 1212839Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 1312839Sgabeblack@google.com * this software without specific prior written permission. 1412839Sgabeblack@google.com * 1512839Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1612839Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1712839Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1812839Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1912839Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2012839Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2112839Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2212839Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2312839Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2412839Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2512839Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2612839Sgabeblack@google.com * 2712839Sgabeblack@google.com * Authors: Gabe Black 2812839Sgabeblack@google.com */ 2912839Sgabeblack@google.com 3012839Sgabeblack@google.com#include "systemc/core/process.hh" 3112993Sgabeblack@google.com 3212993Sgabeblack@google.com#include "base/logging.hh" 3312993Sgabeblack@google.com#include "systemc/core/event.hh" 3413129Sgabeblack@google.com#include "systemc/core/port.hh" 3512993Sgabeblack@google.com#include "systemc/core/scheduler.hh" 3612839Sgabeblack@google.com#include "systemc/ext/core/messages.hh" 3712839Sgabeblack@google.com#include "systemc/ext/core/sc_join.hh" 3812993Sgabeblack@google.com#include "systemc/ext/core/sc_main.hh" 3912993Sgabeblack@google.com#include "systemc/ext/core/sc_process_handle.hh" 4012993Sgabeblack@google.com#include "systemc/ext/utils/sc_report_handler.hh" 4112993Sgabeblack@google.com 4212993Sgabeblack@google.comnamespace sc_gem5 4312993Sgabeblack@google.com{ 4412993Sgabeblack@google.com 4512993Sgabeblack@google.comclass UnwindExceptionReset : public ::sc_core::sc_unwind_exception 4612993Sgabeblack@google.com{ 4712993Sgabeblack@google.com public: 4812993Sgabeblack@google.com UnwindExceptionReset() { _isReset = true; } 4912993Sgabeblack@google.com}; 5012993Sgabeblack@google.com 5112993Sgabeblack@google.comclass UnwindExceptionKill : public ::sc_core::sc_unwind_exception 5212993Sgabeblack@google.com{ 5312993Sgabeblack@google.com public: 5412993Sgabeblack@google.com UnwindExceptionKill() {} 5512993Sgabeblack@google.com}; 5612993Sgabeblack@google.com 5712993Sgabeblack@google.comtemplate <typename T> 5812993Sgabeblack@google.comstruct BuiltinExceptionWrapper : public ExceptionWrapperBase 5912993Sgabeblack@google.com{ 6012993Sgabeblack@google.com public: 6112993Sgabeblack@google.com T t; 6212993Sgabeblack@google.com void throw_it() override { throw t; } 6312993Sgabeblack@google.com}; 6412993Sgabeblack@google.com 6513131Sgabeblack@google.comBuiltinExceptionWrapper<UnwindExceptionReset> resetException; 6612993Sgabeblack@google.comBuiltinExceptionWrapper<UnwindExceptionKill> killException; 6713131Sgabeblack@google.com 6812993Sgabeblack@google.com 6912993Sgabeblack@google.comvoid 7012993Sgabeblack@google.comProcess::forEachKid(const std::function<void(Process *)> &work) 7112993Sgabeblack@google.com{ 7212993Sgabeblack@google.com for (auto &kid: get_child_objects()) { 7312993Sgabeblack@google.com Process *p_kid = dynamic_cast<Process *>(kid); 7412993Sgabeblack@google.com if (p_kid) 7512993Sgabeblack@google.com work(p_kid); 7612993Sgabeblack@google.com } 7712993Sgabeblack@google.com} 7812993Sgabeblack@google.com 7912993Sgabeblack@google.comvoid 8012993Sgabeblack@google.comProcess::suspend(bool inc_kids) 8112993Sgabeblack@google.com{ 8212993Sgabeblack@google.com if (inc_kids) 8312993Sgabeblack@google.com forEachKid([](Process *p) { p->suspend(true); }); 8412993Sgabeblack@google.com 8512993Sgabeblack@google.com if (!_suspended) { 8613180Sgabeblack@google.com _suspended = true; 8713180Sgabeblack@google.com _suspendedReady = scheduler.suspend(this); 8813180Sgabeblack@google.com 8913180Sgabeblack@google.com if (procKind() != ::sc_core::SC_METHOD_PROC_ && 9013180Sgabeblack@google.com scheduler.current() == this) { 9113180Sgabeblack@google.com // This isn't in the spec, but Accellera says that a thread that 9213180Sgabeblack@google.com // self suspends should be marked ready immediately when it's 9313180Sgabeblack@google.com // resumed. 9413180Sgabeblack@google.com _suspendedReady = true; 9513180Sgabeblack@google.com scheduler.yield(); 9612993Sgabeblack@google.com } 9712993Sgabeblack@google.com } 9812993Sgabeblack@google.com} 9912993Sgabeblack@google.com 10012993Sgabeblack@google.comvoid 10112993Sgabeblack@google.comProcess::resume(bool inc_kids) 10212993Sgabeblack@google.com{ 10312993Sgabeblack@google.com if (inc_kids) 10412993Sgabeblack@google.com forEachKid([](Process *p) { p->resume(true); }); 10512993Sgabeblack@google.com 10612839Sgabeblack@google.com if (_suspended) { 10712839Sgabeblack@google.com _suspended = false; 10812839Sgabeblack@google.com if (_suspendedReady) 10912993Sgabeblack@google.com scheduler.resume(this); 11012993Sgabeblack@google.com _suspendedReady = false; 11112993Sgabeblack@google.com } 11212839Sgabeblack@google.com} 11312839Sgabeblack@google.com 11412839Sgabeblack@google.comvoid 11512839Sgabeblack@google.comProcess::disable(bool inc_kids) 11612839Sgabeblack@google.com{ 11712993Sgabeblack@google.com if (inc_kids) 11812839Sgabeblack@google.com forEachKid([](Process *p) { p->disable(true); }); 11912839Sgabeblack@google.com 12012839Sgabeblack@google.com if (!::sc_core::sc_allow_process_control_corners && 12112839Sgabeblack@google.com timeoutEvent.scheduled()) { 12212839Sgabeblack@google.com std::string message("attempt to disable a thread with timeout wait: "); 12312993Sgabeblack@google.com message += name(); 12412839Sgabeblack@google.com SC_REPORT_ERROR(sc_core::SC_ID_PROCESS_CONTROL_CORNER_CASE_, 12512839Sgabeblack@google.com message.c_str()); 12612839Sgabeblack@google.com } 12712993Sgabeblack@google.com 12812839Sgabeblack@google.com _disabled = true; 12912993Sgabeblack@google.com} 13012839Sgabeblack@google.com 13112839Sgabeblack@google.comvoid 13212839Sgabeblack@google.comProcess::enable(bool inc_kids) 13312839Sgabeblack@google.com{ 13412993Sgabeblack@google.com 13512839Sgabeblack@google.com if (inc_kids) 13612993Sgabeblack@google.com forEachKid([](Process *p) { p->enable(true); }); 13712839Sgabeblack@google.com 13812839Sgabeblack@google.com _disabled = false; 13912839Sgabeblack@google.com} 14012993Sgabeblack@google.com 14112839Sgabeblack@google.comvoid 14212993Sgabeblack@google.comProcess::kill(bool inc_kids) 14312839Sgabeblack@google.com{ 14412839Sgabeblack@google.com if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) { 14512839Sgabeblack@google.com SC_REPORT_ERROR(sc_core::SC_ID_KILL_PROCESS_WHILE_UNITIALIZED_, 14612993Sgabeblack@google.com name()); 14712839Sgabeblack@google.com } 14812993Sgabeblack@google.com 14912839Sgabeblack@google.com // Propogate the kill to our children no matter what happens to us. 15012839Sgabeblack@google.com if (inc_kids) 15112839Sgabeblack@google.com forEachKid([](Process *p) { p->kill(true); }); 15212993Sgabeblack@google.com 15312839Sgabeblack@google.com // If we're in the middle of unwinding, ignore the kill request. 15412993Sgabeblack@google.com if (_isUnwinding) 15512839Sgabeblack@google.com return; 15612839Sgabeblack@google.com 15712839Sgabeblack@google.com // Update our state. 15812993Sgabeblack@google.com terminate(); 15912839Sgabeblack@google.com _isUnwinding = true; 16012993Sgabeblack@google.com 16112839Sgabeblack@google.com // Make sure this process isn't marked ready 16212839Sgabeblack@google.com popListNode(); 16312839Sgabeblack@google.com 16412839Sgabeblack@google.com // Inject the kill exception into this process if it's started. 16512839Sgabeblack@google.com if (!_needsStart) 16612839Sgabeblack@google.com injectException(killException); 16712839Sgabeblack@google.com} 16812839Sgabeblack@google.com 16912839Sgabeblack@google.comvoid 17012839Sgabeblack@google.comProcess::reset(bool inc_kids) 17112839Sgabeblack@google.com{ 17212839Sgabeblack@google.com if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) { 17312839Sgabeblack@google.com SC_REPORT_ERROR(sc_core::SC_ID_RESET_PROCESS_WHILE_NOT_RUNNING_, 17412839Sgabeblack@google.com name()); 17512839Sgabeblack@google.com } 17612839Sgabeblack@google.com 17712839Sgabeblack@google.com // Propogate the reset to our children no matter what happens to us. 17812839Sgabeblack@google.com if (inc_kids) 17912839Sgabeblack@google.com forEachKid([](Process *p) { p->reset(true); }); 18012839Sgabeblack@google.com 18112839Sgabeblack@google.com // If we're in the middle of unwinding, ignore the reset request. 18212839Sgabeblack@google.com if (_isUnwinding) 18312839Sgabeblack@google.com return; 18412839Sgabeblack@google.com 18512839Sgabeblack@google.com // Clear suspended ready since we're about to run regardless. 18612839Sgabeblack@google.com _suspendedReady = false; 18712839Sgabeblack@google.com 18812839Sgabeblack@google.com _resetEvent.notify(); 18912839Sgabeblack@google.com 19012839Sgabeblack@google.com if (_needsStart) { 19112839Sgabeblack@google.com scheduler.runNow(this); 19212839Sgabeblack@google.com } else { 19312839Sgabeblack@google.com _isUnwinding = true; 19412839Sgabeblack@google.com injectException(resetException); 19512839Sgabeblack@google.com } 19612839Sgabeblack@google.com} 19712839Sgabeblack@google.com 19812839Sgabeblack@google.comvoid 19912839Sgabeblack@google.comProcess::throw_it(ExceptionWrapperBase &exc, bool inc_kids) 20012839Sgabeblack@google.com{ 20112839Sgabeblack@google.com if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) 20212839Sgabeblack@google.com SC_REPORT_ERROR(sc_core::SC_ID_THROW_IT_WHILE_NOT_RUNNING_, name()); 20312839Sgabeblack@google.com 20412839Sgabeblack@google.com if (inc_kids) 20512839Sgabeblack@google.com forEachKid([&exc](Process *p) { p->throw_it(exc, true); }); 20612839Sgabeblack@google.com 20712839Sgabeblack@google.com if (_needsStart || _terminated || 20812839Sgabeblack@google.com procKind() == ::sc_core::SC_METHOD_PROC_) { 20912839Sgabeblack@google.com SC_REPORT_WARNING(sc_core::SC_ID_THROW_IT_IGNORED_, name()); 21012839Sgabeblack@google.com return; 21112839Sgabeblack@google.com } 21212839Sgabeblack@google.com 21312839Sgabeblack@google.com injectException(exc); 21412839Sgabeblack@google.com} 21512839Sgabeblack@google.com 21612839Sgabeblack@google.comvoid 21712839Sgabeblack@google.comProcess::injectException(ExceptionWrapperBase &exc) 21812839Sgabeblack@google.com{ 21912839Sgabeblack@google.com excWrapper = &exc; 22012839Sgabeblack@google.com scheduler.runNow(this); 22112839Sgabeblack@google.com}; 22212839Sgabeblack@google.com 22312839Sgabeblack@google.comvoid 22412839Sgabeblack@google.comProcess::syncResetOn(bool inc_kids) 22512839Sgabeblack@google.com{ 22612839Sgabeblack@google.com if (inc_kids) 22712839Sgabeblack@google.com forEachKid([](Process *p) { p->syncResetOn(true); }); 22812839Sgabeblack@google.com 22912839Sgabeblack@google.com _syncReset = true; 23012839Sgabeblack@google.com} 23112839Sgabeblack@google.com 23212839Sgabeblack@google.comvoid 23312839Sgabeblack@google.comProcess::syncResetOff(bool inc_kids) 23412839Sgabeblack@google.com{ 23512839Sgabeblack@google.com if (inc_kids) 236 forEachKid([](Process *p) { p->syncResetOff(true); }); 237 238 _syncReset = false; 239} 240 241void 242Process::signalReset(bool set, bool sync) 243{ 244 if (set) { 245 waitCount(0); 246 if (sync) { 247 syncResetCount++; 248 } else { 249 asyncResetCount++; 250 cancelTimeout(); 251 clearDynamic(); 252 scheduler.runNext(this); 253 } 254 } else { 255 if (sync) 256 syncResetCount--; 257 else 258 asyncResetCount--; 259 } 260} 261 262void 263Process::run() 264{ 265 bool reset; 266 do { 267 reset = false; 268 try { 269 func->call(); 270 } catch(ScHalt) { 271 std::cout << "Terminating process " << name() << std::endl; 272 } catch(const ::sc_core::sc_unwind_exception &exc) { 273 reset = exc.is_reset(); 274 _isUnwinding = false; 275 } catch (...) { 276 throw; 277 } 278 } while (reset); 279 needsStart(true); 280} 281 282void 283Process::addStatic(StaticSensitivity *s) 284{ 285 staticSensitivities.push_back(s); 286} 287 288void 289Process::setDynamic(DynamicSensitivity *s) 290{ 291 if (dynamicSensitivity) { 292 dynamicSensitivity->clear(); 293 delete dynamicSensitivity; 294 } 295 dynamicSensitivity = s; 296} 297 298void 299Process::addReset(Reset *reset) 300{ 301 resets.push_back(reset); 302} 303 304void 305Process::cancelTimeout() 306{ 307 if (timeoutEvent.scheduled()) 308 scheduler.deschedule(&timeoutEvent); 309} 310 311void 312Process::setTimeout(::sc_core::sc_time t) 313{ 314 cancelTimeout(); 315 scheduler.schedule(&timeoutEvent, t); 316} 317 318void 319Process::timeout() 320{ 321 // A process is considered timed_out only if it was also waiting for an 322 // event but got a timeout instead. 323 _timedOut = (dynamicSensitivity != nullptr); 324 325 setDynamic(nullptr); 326 if (disabled()) 327 return; 328 329 ready(); 330} 331 332void 333Process::satisfySensitivity(Sensitivity *s) 334{ 335 if (_waitCount) { 336 _waitCount--; 337 return; 338 } 339 340 // If there's a dynamic sensitivity and this wasn't it, ignore. 341 if ((dynamicSensitivity || timeoutEvent.scheduled()) && 342 dynamicSensitivity != s) { 343 return; 344 } 345 346 _timedOut = false; 347 // This sensitivity should already be cleared by this point, or the event 348 // which triggered it will take care of it. 349 delete dynamicSensitivity; 350 dynamicSensitivity = nullptr; 351 cancelTimeout(); 352 ready(); 353} 354 355void 356Process::ready() 357{ 358 if (disabled()) 359 return; 360 if (suspended()) 361 _suspendedReady = true; 362 else if (!scheduled()) 363 scheduler.ready(this); 364} 365 366void 367Process::lastReport(::sc_core::sc_report *report) 368{ 369 if (report) { 370 _lastReport = std::unique_ptr<::sc_core::sc_report>( 371 new ::sc_core::sc_report(*report)); 372 } else { 373 _lastReport = nullptr; 374 } 375} 376 377::sc_core::sc_report *Process::lastReport() const { return _lastReport.get(); } 378 379Process::Process(const char *name, ProcessFuncWrapper *func, bool internal) : 380 ::sc_core::sc_process_b(name), excWrapper(nullptr), 381 timeoutEvent([this]() { this->timeout(); }), 382 func(func), _internal(internal), _timedOut(false), _dontInitialize(false), 383 _needsStart(true), _isUnwinding(false), _terminated(false), 384 _scheduled(false), _suspended(false), _disabled(false), 385 _syncReset(false), syncResetCount(0), asyncResetCount(0), _waitCount(0), 386 refCount(0), stackSize(::Fiber::DefaultStackSize), 387 dynamicSensitivity(nullptr) 388{ 389 _dynamic = 390 (::sc_core::sc_get_status() > 391 ::sc_core::SC_BEFORE_END_OF_ELABORATION); 392 _newest = this; 393} 394 395void 396Process::terminate() 397{ 398 _terminated = true; 399 _suspendedReady = false; 400 _suspended = false; 401 _syncReset = false; 402 clearDynamic(); 403 cancelTimeout(); 404 for (auto s: staticSensitivities) { 405 s->clear(); 406 delete s; 407 } 408 staticSensitivities.clear(); 409 410 _terminatedEvent.notify(); 411 412 for (auto jw: joinWaiters) 413 jw->signal(); 414 joinWaiters.clear(); 415} 416 417Process *Process::_newest; 418 419void 420throw_it_wrapper(Process *p, ExceptionWrapperBase &exc, bool inc_kids) 421{ 422 p->throw_it(exc, inc_kids); 423} 424 425void 426newReset(const sc_core::sc_port_base *pb, Process *p, bool s, bool v) 427{ 428 Port *port = Port::fromPort(pb); 429 port->addReset(new Reset(p, s, v)); 430} 431 432void 433newReset(const sc_core::sc_signal_in_if<bool> *sig, Process *p, bool s, bool v) 434{ 435 Reset *reset = new Reset(p, s, v); 436 if (!reset->install(sig)) 437 delete reset; 438} 439 440} // namespace sc_gem5 441