process.cc revision 13261:c8e97d29976d
112855Sgabeblack@google.com/* 212855Sgabeblack@google.com * Copyright 2018 Google, Inc. 312855Sgabeblack@google.com * 412855Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 512855Sgabeblack@google.com * modification, are permitted provided that the following conditions are 612855Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 712855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 812855Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 912855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 1012855Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 1112855Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 1212855Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 1312855Sgabeblack@google.com * this software without specific prior written permission. 1412855Sgabeblack@google.com * 1512855Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1612855Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1712855Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1812855Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1912855Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2012855Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2112855Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2212855Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2312855Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2412855Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2512855Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2612855Sgabeblack@google.com * 2712855Sgabeblack@google.com * Authors: Gabe Black 2812855Sgabeblack@google.com */ 2912855Sgabeblack@google.com 3012855Sgabeblack@google.com#include "systemc/core/process.hh" 3112855Sgabeblack@google.com 3212855Sgabeblack@google.com#include "base/logging.hh" 3312855Sgabeblack@google.com#include "systemc/core/event.hh" 3412855Sgabeblack@google.com#include "systemc/core/scheduler.hh" 3512855Sgabeblack@google.com#include "systemc/ext/core/sc_join.hh" 3612855Sgabeblack@google.com#include "systemc/ext/core/sc_main.hh" 3712855Sgabeblack@google.com#include "systemc/ext/core/sc_process_handle.hh" 3812855Sgabeblack@google.com#include "systemc/ext/utils/sc_report_handler.hh" 3912855Sgabeblack@google.com 4012855Sgabeblack@google.comnamespace sc_gem5 4112855Sgabeblack@google.com{ 4212855Sgabeblack@google.com 4312855Sgabeblack@google.comclass UnwindExceptionReset : public ::sc_core::sc_unwind_exception 4412855Sgabeblack@google.com{ 4512855Sgabeblack@google.com public: 4612855Sgabeblack@google.com UnwindExceptionReset() { _isReset = true; } 4712855Sgabeblack@google.com}; 4812855Sgabeblack@google.com 4912855Sgabeblack@google.comclass UnwindExceptionKill : public ::sc_core::sc_unwind_exception 5012855Sgabeblack@google.com{ 5112855Sgabeblack@google.com public: 5212855Sgabeblack@google.com UnwindExceptionKill() {} 5312855Sgabeblack@google.com}; 5412855Sgabeblack@google.com 5512855Sgabeblack@google.comtemplate <typename T> 5612855Sgabeblack@google.comstruct BuiltinExceptionWrapper : public ExceptionWrapperBase 5712855Sgabeblack@google.com{ 5812855Sgabeblack@google.com public: 5912855Sgabeblack@google.com T t; 6012855Sgabeblack@google.com void throw_it() override { throw t; } 6112855Sgabeblack@google.com}; 6212855Sgabeblack@google.com 6312855Sgabeblack@google.comBuiltinExceptionWrapper<UnwindExceptionReset> resetException; 6412855Sgabeblack@google.comBuiltinExceptionWrapper<UnwindExceptionKill> killException; 6512855Sgabeblack@google.com 6612855Sgabeblack@google.com 6712855Sgabeblack@google.comvoid 6812855Sgabeblack@google.comProcess::forEachKid(const std::function<void(Process *)> &work) 6912855Sgabeblack@google.com{ 7012855Sgabeblack@google.com for (auto &kid: get_child_objects()) { 7112855Sgabeblack@google.com Process *p_kid = dynamic_cast<Process *>(kid); 7212855Sgabeblack@google.com if (p_kid) 7312855Sgabeblack@google.com work(p_kid); 7412855Sgabeblack@google.com } 7512855Sgabeblack@google.com} 7612855Sgabeblack@google.com 7712855Sgabeblack@google.comvoid 7812855Sgabeblack@google.comProcess::suspend(bool inc_kids) 7912855Sgabeblack@google.com{ 8012855Sgabeblack@google.com if (inc_kids) 8112855Sgabeblack@google.com forEachKid([](Process *p) { p->suspend(true); }); 8212855Sgabeblack@google.com 8312855Sgabeblack@google.com if (!_suspended) { 8412855Sgabeblack@google.com _suspended = true; 8512855Sgabeblack@google.com _suspendedReady = scheduler.suspend(this); 8612855Sgabeblack@google.com 8712855Sgabeblack@google.com if (procKind() != ::sc_core::SC_METHOD_PROC_ && 8812855Sgabeblack@google.com scheduler.current() == this) { 8912855Sgabeblack@google.com // This isn't in the spec, but Accellera says that a thread that 9012855Sgabeblack@google.com // self suspends should be marked ready immediately when it's 9112855Sgabeblack@google.com // resumed. 9212855Sgabeblack@google.com _suspendedReady = true; 9312855Sgabeblack@google.com scheduler.yield(); 9412855Sgabeblack@google.com } 9512855Sgabeblack@google.com } 9612855Sgabeblack@google.com} 9712855Sgabeblack@google.com 9812855Sgabeblack@google.comvoid 9912855Sgabeblack@google.comProcess::resume(bool inc_kids) 10012855Sgabeblack@google.com{ 10112855Sgabeblack@google.com if (inc_kids) 10212855Sgabeblack@google.com forEachKid([](Process *p) { p->resume(true); }); 10312855Sgabeblack@google.com 10412855Sgabeblack@google.com if (_suspended) { 10512855Sgabeblack@google.com _suspended = false; 10612855Sgabeblack@google.com if (_suspendedReady) 10712855Sgabeblack@google.com scheduler.resume(this); 10812855Sgabeblack@google.com _suspendedReady = false; 10912855Sgabeblack@google.com } 11012855Sgabeblack@google.com} 11112855Sgabeblack@google.com 11212855Sgabeblack@google.comvoid 11312855Sgabeblack@google.comProcess::disable(bool inc_kids) 11412855Sgabeblack@google.com{ 11512855Sgabeblack@google.com if (inc_kids) 11612855Sgabeblack@google.com forEachKid([](Process *p) { p->disable(true); }); 11712855Sgabeblack@google.com 11812855Sgabeblack@google.com if (!::sc_core::sc_allow_process_control_corners && 11912855Sgabeblack@google.com timeoutEvent.scheduled()) { 12012855Sgabeblack@google.com std::string message("attempt to disable a thread with timeout wait: "); 12112855Sgabeblack@google.com message += name(); 12212855Sgabeblack@google.com SC_REPORT_ERROR("Undefined process control interaction", 12312855Sgabeblack@google.com message.c_str()); 12412855Sgabeblack@google.com } 12512855Sgabeblack@google.com 12612855Sgabeblack@google.com _disabled = true; 12712855Sgabeblack@google.com} 12812855Sgabeblack@google.com 12912855Sgabeblack@google.comvoid 13012855Sgabeblack@google.comProcess::enable(bool inc_kids) 13112855Sgabeblack@google.com{ 13212855Sgabeblack@google.com 13312855Sgabeblack@google.com if (inc_kids) 13412855Sgabeblack@google.com forEachKid([](Process *p) { p->enable(true); }); 13512855Sgabeblack@google.com 13612855Sgabeblack@google.com _disabled = false; 13712855Sgabeblack@google.com} 13812855Sgabeblack@google.com 13912855Sgabeblack@google.comvoid 14012855Sgabeblack@google.comProcess::kill(bool inc_kids) 14112855Sgabeblack@google.com{ 14212855Sgabeblack@google.com if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) { 14312855Sgabeblack@google.com SC_REPORT_ERROR( 14412855Sgabeblack@google.com "(E572) a process may not be killed before it is initialized", 14512855Sgabeblack@google.com name()); 14612855Sgabeblack@google.com } 14712855Sgabeblack@google.com 14812855Sgabeblack@google.com // Propogate the kill to our children no matter what happens to us. 14912855Sgabeblack@google.com if (inc_kids) 15012855Sgabeblack@google.com forEachKid([](Process *p) { p->kill(true); }); 15112855Sgabeblack@google.com 15212855Sgabeblack@google.com // If we're in the middle of unwinding, ignore the kill request. 15312855Sgabeblack@google.com if (_isUnwinding) 15412855Sgabeblack@google.com return; 15512855Sgabeblack@google.com 15612855Sgabeblack@google.com // Update our state. 15712855Sgabeblack@google.com terminate(); 15812855Sgabeblack@google.com _isUnwinding = true; 15912855Sgabeblack@google.com 16012855Sgabeblack@google.com // Make sure this process isn't marked ready 16112855Sgabeblack@google.com popListNode(); 16212855Sgabeblack@google.com 16312855Sgabeblack@google.com // Inject the kill exception into this process if it's started. 16412855Sgabeblack@google.com if (!_needsStart) 16512855Sgabeblack@google.com injectException(killException); 16612855Sgabeblack@google.com} 16712855Sgabeblack@google.com 16812855Sgabeblack@google.comvoid 16912855Sgabeblack@google.comProcess::reset(bool inc_kids) 17012855Sgabeblack@google.com{ 17112855Sgabeblack@google.com if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) { 17212855Sgabeblack@google.com SC_REPORT_ERROR( 17312855Sgabeblack@google.com "(E573) a process may not be asynchronously reset while" 17412855Sgabeblack@google.com "the simulation is not running", name()); 17512855Sgabeblack@google.com } 17612855Sgabeblack@google.com 17712855Sgabeblack@google.com // Propogate the reset to our children no matter what happens to us. 17812855Sgabeblack@google.com if (inc_kids) 17912855Sgabeblack@google.com forEachKid([](Process *p) { p->reset(true); }); 18012855Sgabeblack@google.com 18112855Sgabeblack@google.com // If we're in the middle of unwinding, ignore the reset request. 18212855Sgabeblack@google.com if (_isUnwinding) 18312855Sgabeblack@google.com return; 18412855Sgabeblack@google.com 18512855Sgabeblack@google.com 18612855Sgabeblack@google.com _resetEvent.notify(); 18712855Sgabeblack@google.com 18812855Sgabeblack@google.com if (_needsStart) { 18912855Sgabeblack@google.com scheduler.runNow(this); 19012855Sgabeblack@google.com } else { 19112855Sgabeblack@google.com _isUnwinding = true; 19212855Sgabeblack@google.com injectException(resetException); 19312855Sgabeblack@google.com } 19412855Sgabeblack@google.com} 19512855Sgabeblack@google.com 19612855Sgabeblack@google.comvoid 19712855Sgabeblack@google.comProcess::throw_it(ExceptionWrapperBase &exc, bool inc_kids) 19812855Sgabeblack@google.com{ 19912855Sgabeblack@google.com if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) { 20012855Sgabeblack@google.com SC_REPORT_ERROR( 20112855Sgabeblack@google.com "(E574) throw_it not allowed unless simulation is running ", 20212855Sgabeblack@google.com name()); 20312855Sgabeblack@google.com } 20412855Sgabeblack@google.com 20512855Sgabeblack@google.com if (inc_kids) 20612855Sgabeblack@google.com forEachKid([&exc](Process *p) { p->throw_it(exc, true); }); 20712855Sgabeblack@google.com 20812855Sgabeblack@google.com // Only inject an exception into threads that have started. 20912855Sgabeblack@google.com if (!_needsStart) 21012855Sgabeblack@google.com injectException(exc); 21112855Sgabeblack@google.com} 21212855Sgabeblack@google.com 21312855Sgabeblack@google.comvoid 21412855Sgabeblack@google.comProcess::injectException(ExceptionWrapperBase &exc) 21512855Sgabeblack@google.com{ 21612855Sgabeblack@google.com excWrapper = &exc; 21712855Sgabeblack@google.com scheduler.runNow(this); 21812855Sgabeblack@google.com}; 21912855Sgabeblack@google.com 22012855Sgabeblack@google.comvoid 22112855Sgabeblack@google.comProcess::syncResetOn(bool inc_kids) 22212855Sgabeblack@google.com{ 22312855Sgabeblack@google.com if (inc_kids) 22412855Sgabeblack@google.com forEachKid([](Process *p) { p->syncResetOn(true); }); 22512855Sgabeblack@google.com 22612855Sgabeblack@google.com _syncReset = true; 22712855Sgabeblack@google.com} 22812855Sgabeblack@google.com 22912855Sgabeblack@google.comvoid 23012855Sgabeblack@google.comProcess::syncResetOff(bool inc_kids) 23112855Sgabeblack@google.com{ 23212855Sgabeblack@google.com if (inc_kids) 23312855Sgabeblack@google.com forEachKid([](Process *p) { p->syncResetOff(true); }); 23412855Sgabeblack@google.com 23512855Sgabeblack@google.com _syncReset = false; 23612855Sgabeblack@google.com} 23712855Sgabeblack@google.com 23812855Sgabeblack@google.comvoid 23912855Sgabeblack@google.comProcess::signalReset(bool set, bool sync) 240{ 241 if (set) { 242 waitCount(0); 243 if (sync) { 244 syncResetCount++; 245 } else { 246 asyncResetCount++; 247 cancelTimeout(); 248 clearDynamic(); 249 scheduler.runNext(this); 250 } 251 } else { 252 if (sync) 253 syncResetCount--; 254 else 255 asyncResetCount--; 256 } 257} 258 259void 260Process::run() 261{ 262 bool reset; 263 do { 264 reset = false; 265 try { 266 func->call(); 267 } catch(ScHalt) { 268 std::cout << "Terminating process " << name() << std::endl; 269 } catch(const ::sc_core::sc_unwind_exception &exc) { 270 reset = exc.is_reset(); 271 _isUnwinding = false; 272 } catch (...) { 273 throw; 274 } 275 } while (reset); 276 needsStart(true); 277} 278 279void 280Process::addStatic(StaticSensitivity *s) 281{ 282 staticSensitivities.push_back(s); 283} 284 285void 286Process::setDynamic(DynamicSensitivity *s) 287{ 288 if (dynamicSensitivity) { 289 dynamicSensitivity->clear(); 290 delete dynamicSensitivity; 291 } 292 dynamicSensitivity = s; 293} 294 295void 296Process::addReset(ResetSensitivity *s) 297{ 298 resetSensitivities.push_back(s); 299} 300 301void 302Process::cancelTimeout() 303{ 304 if (timeoutEvent.scheduled()) 305 scheduler.deschedule(&timeoutEvent); 306} 307 308void 309Process::setTimeout(::sc_core::sc_time t) 310{ 311 cancelTimeout(); 312 scheduler.schedule(&timeoutEvent, t); 313} 314 315void 316Process::timeout() 317{ 318 // A process is considered timed_out only if it was also waiting for an 319 // event but got a timeout instead. 320 _timedOut = (dynamicSensitivity != nullptr); 321 322 setDynamic(nullptr); 323 if (disabled()) 324 return; 325 326 ready(); 327} 328 329void 330Process::satisfySensitivity(Sensitivity *s) 331{ 332 if (_waitCount) { 333 _waitCount--; 334 return; 335 } 336 337 // If there's a dynamic sensitivity and this wasn't it, ignore. 338 if ((dynamicSensitivity || timeoutEvent.scheduled()) && 339 dynamicSensitivity != s) { 340 return; 341 } 342 343 _timedOut = false; 344 // This sensitivity should already be cleared by this point, or the event 345 // which triggered it will take care of it. 346 delete dynamicSensitivity; 347 dynamicSensitivity = nullptr; 348 cancelTimeout(); 349 ready(); 350} 351 352void 353Process::ready() 354{ 355 if (disabled()) 356 return; 357 if (suspended()) 358 _suspendedReady = true; 359 else 360 scheduler.ready(this); 361} 362 363void 364Process::lastReport(::sc_core::sc_report *report) 365{ 366 if (report) { 367 _lastReport = std::unique_ptr<::sc_core::sc_report>( 368 new ::sc_core::sc_report(*report)); 369 } else { 370 _lastReport = nullptr; 371 } 372} 373 374::sc_core::sc_report *Process::lastReport() const { return _lastReport.get(); } 375 376Process::Process(const char *name, ProcessFuncWrapper *func, bool internal) : 377 ::sc_core::sc_process_b(name), excWrapper(nullptr), 378 timeoutEvent([this]() { this->timeout(); }), 379 func(func), _internal(internal), _timedOut(false), _dontInitialize(false), 380 _needsStart(true), _isUnwinding(false), _terminated(false), 381 _suspended(false), _disabled(false), _syncReset(false), syncResetCount(0), 382 asyncResetCount(0), _waitCount(0), refCount(0), 383 stackSize(::Fiber::DefaultStackSize), dynamicSensitivity(nullptr) 384{ 385 _dynamic = 386 (::sc_core::sc_get_status() > 387 ::sc_core::SC_BEFORE_END_OF_ELABORATION); 388 _newest = this; 389} 390 391void 392Process::terminate() 393{ 394 _terminated = true; 395 _suspendedReady = false; 396 _suspended = false; 397 _syncReset = false; 398 clearDynamic(); 399 cancelTimeout(); 400 for (auto s: staticSensitivities) { 401 s->clear(); 402 delete s; 403 } 404 staticSensitivities.clear(); 405 406 _terminatedEvent.notify(); 407 408 for (auto jw: joinWaiters) 409 jw->signal(); 410 joinWaiters.clear(); 411} 412 413Process *Process::_newest; 414 415void 416throw_it_wrapper(Process *p, ExceptionWrapperBase &exc, bool inc_kids) 417{ 418 p->throw_it(exc, inc_kids); 419} 420 421} // namespace sc_gem5 422