process.cc revision 13335:299a16ef8e3c
12155SN/A/* 22155SN/A * Copyright 2018 Google, Inc. 32155SN/A * 42155SN/A * Redistribution and use in source and binary forms, with or without 52155SN/A * modification, are permitted provided that the following conditions are 62155SN/A * met: redistributions of source code must retain the above copyright 72155SN/A * notice, this list of conditions and the following disclaimer; 82155SN/A * redistributions in binary form must reproduce the above copyright 92155SN/A * notice, this list of conditions and the following disclaimer in the 102155SN/A * documentation and/or other materials provided with the distribution; 112155SN/A * neither the name of the copyright holders nor the names of its 122155SN/A * contributors may be used to endorse or promote products derived from 132155SN/A * this software without specific prior written permission. 142155SN/A * 152155SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 162155SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 172155SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 182155SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 192155SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 202155SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 212155SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 222155SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 232155SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 242155SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 252155SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 262155SN/A * 272155SN/A * Authors: Gabe Black 282665Ssaidi@eecs.umich.edu */ 292665Ssaidi@eecs.umich.edu 302155SN/A#include "systemc/core/process.hh" 312155SN/A 322155SN/A#include "systemc/core/event.hh" 332155SN/A#include "systemc/core/port.hh" 342155SN/A#include "systemc/core/scheduler.hh" 352155SN/A#include "systemc/ext/core/messages.hh" 362155SN/A#include "systemc/ext/core/sc_join.hh" 372178SN/A#include "systemc/ext/core/sc_main.hh" 382178SN/A#include "systemc/ext/core/sc_process_handle.hh" 392178SN/A#include "systemc/ext/utils/sc_report_handler.hh" 402178SN/A 412178SN/Anamespace sc_gem5 422178SN/A{ 432178SN/A 442178SN/Aclass UnwindExceptionReset : public ::sc_core::sc_unwind_exception 452178SN/A{ 462178SN/A public: 472178SN/A UnwindExceptionReset() { _isReset = true; } 482178SN/A}; 492155SN/A 502178SN/Aclass UnwindExceptionKill : public ::sc_core::sc_unwind_exception 512155SN/A{ 522155SN/A public: 532178SN/A UnwindExceptionKill() {} 542155SN/A}; 552155SN/A 562623SN/Atemplate <typename T> 572623SN/Astruct BuiltinExceptionWrapper : public ExceptionWrapperBase 582623SN/A{ 592623SN/A public: 602623SN/A T t; 612155SN/A void throw_it() override { throw t; } 622155SN/A}; 632292SN/A 642292SN/ABuiltinExceptionWrapper<UnwindExceptionReset> resetException; 652292SN/ABuiltinExceptionWrapper<UnwindExceptionKill> killException; 662292SN/A 672292SN/A 682292SN/Avoid 692292SN/AProcess::forEachKid(const std::function<void(Process *)> &work) 702292SN/A{ 712766Sktlim@umich.edu for (auto &kid: get_child_objects()) { 722766Sktlim@umich.edu Process *p_kid = dynamic_cast<Process *>(kid); 732766Sktlim@umich.edu if (p_kid) 742921Sktlim@umich.edu work(p_kid); 752921Sktlim@umich.edu } 762766Sktlim@umich.edu} 772766Sktlim@umich.edu 782766Sktlim@umich.eduvoid 792178SN/AProcess::suspend(bool inc_kids) 802155SN/A{ 812155SN/A if (inc_kids) 822155SN/A forEachKid([](Process *p) { p->suspend(true); }); 832155SN/A 842155SN/A if (!_suspended) { 852155SN/A _suspended = true; 862766Sktlim@umich.edu _suspendedReady = scheduler.suspend(this); 872155SN/A 882623SN/A if (procKind() != ::sc_core::SC_METHOD_PROC_ && 892155SN/A scheduler.current() == this) { 902155SN/A // This isn't in the spec, but Accellera says that a thread that 912155SN/A // self suspends should be marked ready immediately when it's 922155SN/A // resumed. 932178SN/A _suspendedReady = true; 942178SN/A scheduler.yield(); 952178SN/A } 962766Sktlim@umich.edu } 972178SN/A} 982178SN/A 992178SN/Avoid 1002178SN/AProcess::resume(bool inc_kids) 1012766Sktlim@umich.edu{ 1022766Sktlim@umich.edu if (inc_kids) 1032766Sktlim@umich.edu forEachKid([](Process *p) { p->resume(true); }); 1042788Sktlim@umich.edu 1052178SN/A if (_suspended) { 1062733Sktlim@umich.edu _suspended = false; 1072733Sktlim@umich.edu if (_suspendedReady) 1082817Sksewell@umich.edu scheduler.resume(this); 1092733Sktlim@umich.edu _suspendedReady = false; 1102178SN/A } 1112178SN/A} 1122178SN/A 1132178SN/Avoid 1142178SN/AProcess::disable(bool inc_kids) 1152178SN/A{ 1162155SN/A if (inc_kids) 1172929Sktlim@umich.edu forEachKid([](Process *p) { p->disable(true); }); 1182929Sktlim@umich.edu 1192929Sktlim@umich.edu if (!::sc_core::sc_allow_process_control_corners && 1202155SN/A timeoutEvent.scheduled()) { 1212155SN/A std::string message("attempt to disable a thread with timeout wait: "); 1222623SN/A message += name(); 1232623SN/A SC_REPORT_ERROR(sc_core::SC_ID_PROCESS_CONTROL_CORNER_CASE_, 1242623SN/A message.c_str()); 1252623SN/A } 1262623SN/A 1272623SN/A _disabled = true; 1282623SN/A} 1292623SN/A 1302623SN/Avoid 1312623SN/AProcess::enable(bool inc_kids) 1322623SN/A{ 1332155SN/A 1342155SN/A if (inc_kids) 1352155SN/A forEachKid([](Process *p) { p->enable(true); }); 1362155SN/A 1372821Sktlim@umich.edu _disabled = false; 1382817Sksewell@umich.edu} 1392821Sktlim@umich.edu 1402817Sksewell@umich.eduvoid 1412155SN/AProcess::kill(bool inc_kids) 1422765Sktlim@umich.edu{ 1432155SN/A if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) { 1442155SN/A SC_REPORT_ERROR(sc_core::SC_ID_KILL_PROCESS_WHILE_UNITIALIZED_, 1452155SN/A name()); 1462155SN/A } 1472155SN/A 1482292SN/A // Propogate the kill to our children no matter what happens to us. 1492155SN/A if (inc_kids) 1502155SN/A forEachKid([](Process *p) { p->kill(true); }); 1512155SN/A 1522292SN/A // If we're in the middle of unwinding, ignore the kill request. 1532292SN/A if (_isUnwinding) 1542155SN/A return; 1552155SN/A 1562155SN/A // Update our state. 1572155SN/A terminate(); 1582292SN/A _isUnwinding = true; 1592155SN/A 1602155SN/A // Make sure this process isn't marked ready 1612766Sktlim@umich.edu popListNode(); 1622765Sktlim@umich.edu 1632929Sktlim@umich.edu // Inject the kill exception into this process if it's started. 1642155SN/A if (!_needsStart) 1652792Sktlim@umich.edu injectException(killException); 1662821Sktlim@umich.edu} 1672292SN/A 1682792Sktlim@umich.eduvoid 1692792Sktlim@umich.eduProcess::reset(bool inc_kids) 1702292SN/A{ 1712292SN/A if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) { 1722292SN/A SC_REPORT_ERROR(sc_core::SC_ID_RESET_PROCESS_WHILE_NOT_RUNNING_, 1732292SN/A name()); 1742297SN/A } 1752297SN/A 1762792Sktlim@umich.edu // Propogate the reset to our children no matter what happens to us. 1772292SN/A if (inc_kids) 1782766Sktlim@umich.edu forEachKid([](Process *p) { p->reset(true); }); 1792765Sktlim@umich.edu 1802292SN/A // If we're in the middle of unwinding, ignore the reset request. 1812821Sktlim@umich.edu if (_isUnwinding) 1822821Sktlim@umich.edu return; 1832821Sktlim@umich.edu 1842821Sktlim@umich.edu // Clear suspended ready since we're about to run regardless. 1852821Sktlim@umich.edu _suspendedReady = false; 1862821Sktlim@umich.edu 1872821Sktlim@umich.edu _resetEvent.notify(); 1882821Sktlim@umich.edu 1892766Sktlim@umich.edu if (_needsStart) { 1902789Sktlim@umich.edu scheduler.runNow(this); 1912733Sktlim@umich.edu } else { 1922733Sktlim@umich.edu _isUnwinding = true; 1932733Sktlim@umich.edu injectException(resetException); 1942733Sktlim@umich.edu } 1952733Sktlim@umich.edu} 1962874Sktlim@umich.edu 1972874Sktlim@umich.eduvoid 1982874Sktlim@umich.eduProcess::throw_it(ExceptionWrapperBase &exc, bool inc_kids) 1992874Sktlim@umich.edu{ 2002733Sktlim@umich.edu if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) 2012733Sktlim@umich.edu SC_REPORT_ERROR(sc_core::SC_ID_THROW_IT_WHILE_NOT_RUNNING_, name()); 2022315SN/A 2032761Sstever@eecs.umich.edu if (inc_kids) 2042155SN/A forEachKid([&exc](Process *p) { p->throw_it(exc, true); }); 2052155SN/A 2062155SN/A if (_needsStart || _terminated || 2072155SN/A procKind() == ::sc_core::SC_METHOD_PROC_) { 2082155SN/A SC_REPORT_WARNING(sc_core::SC_ID_THROW_IT_IGNORED_, name()); 2092155SN/A return; 2102155SN/A } 2112155SN/A 212 injectException(exc); 213} 214 215void 216Process::injectException(ExceptionWrapperBase &exc) 217{ 218 excWrapper = &exc; 219 scheduler.runNow(this); 220}; 221 222void 223Process::syncResetOn(bool inc_kids) 224{ 225 if (inc_kids) 226 forEachKid([](Process *p) { p->syncResetOn(true); }); 227 228 _syncReset = true; 229} 230 231void 232Process::syncResetOff(bool inc_kids) 233{ 234 if (inc_kids) 235 forEachKid([](Process *p) { p->syncResetOff(true); }); 236 237 _syncReset = false; 238} 239 240void 241Process::signalReset(bool set, bool sync) 242{ 243 if (set) { 244 waitCount(0); 245 if (sync) { 246 syncResetCount++; 247 } else { 248 asyncResetCount++; 249 cancelTimeout(); 250 clearDynamic(); 251 scheduler.runNext(this); 252 } 253 } else { 254 if (sync) 255 syncResetCount--; 256 else 257 asyncResetCount--; 258 } 259} 260 261void 262Process::run() 263{ 264 bool reset; 265 do { 266 reset = false; 267 try { 268 func->call(); 269 } catch(ScHalt) { 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; 274 } catch (...) { 275 throw; 276 } 277 } while (reset); 278 needsStart(true); 279} 280 281void 282Process::addStatic(StaticSensitivity *s) 283{ 284 staticSensitivities.push_back(s); 285} 286 287void 288Process::setDynamic(DynamicSensitivity *s) 289{ 290 if (dynamicSensitivity) { 291 dynamicSensitivity->clear(); 292 delete dynamicSensitivity; 293 } 294 dynamicSensitivity = s; 295} 296 297void 298Process::addReset(Reset *reset) 299{ 300 resets.push_back(reset); 301} 302 303void 304Process::cancelTimeout() 305{ 306 if (timeoutEvent.scheduled()) 307 scheduler.deschedule(&timeoutEvent); 308} 309 310void 311Process::setTimeout(::sc_core::sc_time t) 312{ 313 cancelTimeout(); 314 scheduler.schedule(&timeoutEvent, t); 315} 316 317void 318Process::timeout() 319{ 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); 323 324 setDynamic(nullptr); 325 if (disabled()) 326 return; 327 328 ready(); 329} 330 331void 332Process::satisfySensitivity(Sensitivity *s) 333{ 334 if (_waitCount) { 335 _waitCount--; 336 return; 337 } 338 339 // If there's a dynamic sensitivity and this wasn't it, ignore. 340 if ((dynamicSensitivity || timeoutEvent.scheduled()) && 341 dynamicSensitivity != s) { 342 return; 343 } 344 345 _timedOut = false; 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; 350 cancelTimeout(); 351 ready(); 352} 353 354void 355Process::ready() 356{ 357 if (disabled()) 358 return; 359 if (suspended()) 360 _suspendedReady = true; 361 else if (!scheduled()) 362 scheduler.ready(this); 363} 364 365void 366Process::lastReport(::sc_core::sc_report *report) 367{ 368 if (report) { 369 _lastReport = std::unique_ptr<::sc_core::sc_report>( 370 new ::sc_core::sc_report(*report)); 371 } else { 372 _lastReport = nullptr; 373 } 374} 375 376::sc_core::sc_report *Process::lastReport() const { return _lastReport.get(); } 377 378Process::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) 387{ 388 _dynamic = 389 (::sc_core::sc_get_status() > 390 ::sc_core::SC_BEFORE_END_OF_ELABORATION); 391 _newest = this; 392} 393 394void 395Process::terminate() 396{ 397 _terminated = true; 398 _suspendedReady = false; 399 _suspended = false; 400 _syncReset = false; 401 clearDynamic(); 402 cancelTimeout(); 403 for (auto s: staticSensitivities) { 404 s->clear(); 405 delete s; 406 } 407 staticSensitivities.clear(); 408 409 _terminatedEvent.notify(); 410 411 for (auto jw: joinWaiters) 412 jw->signal(); 413 joinWaiters.clear(); 414} 415 416Process *Process::_newest; 417 418void 419throw_it_wrapper(Process *p, ExceptionWrapperBase &exc, bool inc_kids) 420{ 421 p->throw_it(exc, inc_kids); 422} 423 424void 425newReset(const sc_core::sc_port_base *pb, Process *p, bool s, bool v) 426{ 427 Port *port = Port::fromPort(pb); 428 port->addReset(new Reset(p, s, v)); 429} 430 431void 432newReset(const sc_core::sc_signal_in_if<bool> *sig, Process *p, bool s, bool v) 433{ 434 Reset *reset = new Reset(p, s, v); 435 if (!reset->install(sig)) 436 delete reset; 437} 438 439} // namespace sc_gem5 440