process.cc revision 13307:e30fee54d354
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/port.hh" 35#include "systemc/core/scheduler.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" 40 41namespace sc_gem5 42{ 43 44class UnwindExceptionReset : public ::sc_core::sc_unwind_exception 45{ 46 public: 47 UnwindExceptionReset() { _isReset = true; } 48}; 49 50class UnwindExceptionKill : public ::sc_core::sc_unwind_exception 51{ 52 public: 53 UnwindExceptionKill() {} 54}; 55 56template <typename T> 57struct BuiltinExceptionWrapper : public ExceptionWrapperBase 58{ 59 public: 60 T t; 61 void throw_it() override { throw t; } 62}; 63 64BuiltinExceptionWrapper<UnwindExceptionReset> resetException; 65BuiltinExceptionWrapper<UnwindExceptionKill> killException; 66 67 68void 69Process::forEachKid(const std::function<void(Process *)> &work) 70{ 71 for (auto &kid: get_child_objects()) { 72 Process *p_kid = dynamic_cast<Process *>(kid); 73 if (p_kid) 74 work(p_kid); 75 } 76} 77 78void 79Process::suspend(bool inc_kids) 80{ 81 if (inc_kids) 82 forEachKid([](Process *p) { p->suspend(true); }); 83 84 if (!_suspended) { 85 _suspended = true; 86 _suspendedReady = scheduler.suspend(this); 87 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 92 // resumed. 93 _suspendedReady = true; 94 scheduler.yield(); 95 } 96 } 97} 98 99void 100Process::resume(bool inc_kids) 101{ 102 if (inc_kids) 103 forEachKid([](Process *p) { p->resume(true); }); 104 105 if (_suspended) { 106 _suspended = false; 107 if (_suspendedReady) 108 scheduler.resume(this); 109 _suspendedReady = false; 110 } 111} 112 113void 114Process::disable(bool inc_kids) 115{ 116 if (inc_kids) 117 forEachKid([](Process *p) { p->disable(true); }); 118 119 if (!::sc_core::sc_allow_process_control_corners && 120 timeoutEvent.scheduled()) { 121 std::string message("attempt to disable a thread with timeout wait: "); 122 message += name(); 123 SC_REPORT_ERROR("Undefined process control interaction", 124 message.c_str()); 125 } 126 127 _disabled = true; 128} 129 130void 131Process::enable(bool inc_kids) 132{ 133 134 if (inc_kids) 135 forEachKid([](Process *p) { p->enable(true); }); 136 137 _disabled = false; 138} 139 140void 141Process::kill(bool inc_kids) 142{ 143 if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) { 144 SC_REPORT_ERROR( 145 "(E572) a process may not be killed before it is initialized", 146 name()); 147 } 148 149 // Propogate the kill to our children no matter what happens to us. 150 if (inc_kids) 151 forEachKid([](Process *p) { p->kill(true); }); 152 153 // If we're in the middle of unwinding, ignore the kill request. 154 if (_isUnwinding) 155 return; 156 157 // Update our state. 158 terminate(); 159 _isUnwinding = true; 160 161 // Make sure this process isn't marked ready 162 popListNode(); 163 164 // Inject the kill exception into this process if it's started. 165 if (!_needsStart) 166 injectException(killException); 167} 168 169void 170Process::reset(bool inc_kids) 171{ 172 if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) { 173 SC_REPORT_ERROR( 174 "(E573) a process may not be asynchronously reset while" 175 "the simulation is not running", name()); 176 } 177 178 // Propogate the reset to our children no matter what happens to us. 179 if (inc_kids) 180 forEachKid([](Process *p) { p->reset(true); }); 181 182 // If we're in the middle of unwinding, ignore the reset request. 183 if (_isUnwinding) 184 return; 185 186 187 _resetEvent.notify(); 188 189 if (_needsStart) { 190 scheduler.runNow(this); 191 } else { 192 _isUnwinding = true; 193 injectException(resetException); 194 } 195} 196 197void 198Process::throw_it(ExceptionWrapperBase &exc, bool inc_kids) 199{ 200 if (::sc_core::sc_get_status() != ::sc_core::SC_RUNNING) { 201 SC_REPORT_ERROR( 202 "(E574) throw_it not allowed unless simulation is running ", 203 name()); 204 } 205 206 if (inc_kids) 207 forEachKid([&exc](Process *p) { p->throw_it(exc, true); }); 208 209 if (_needsStart || _terminated || 210 procKind() == ::sc_core::SC_METHOD_PROC_) { 211 SC_REPORT_WARNING("(W556) throw_it on method/non-running process " 212 "is being ignored ", name()); 213 return; 214 } 215 216 injectException(exc); 217} 218 219void 220Process::injectException(ExceptionWrapperBase &exc) 221{ 222 excWrapper = &exc; 223 scheduler.runNow(this); 224}; 225 226void 227Process::syncResetOn(bool inc_kids) 228{ 229 if (inc_kids) 230 forEachKid([](Process *p) { p->syncResetOn(true); }); 231 232 _syncReset = true; 233} 234 235void 236Process::syncResetOff(bool inc_kids) 237{ 238 if (inc_kids) 239 forEachKid([](Process *p) { p->syncResetOff(true); }); 240 241 _syncReset = false; 242} 243 244void 245Process::signalReset(bool set, bool sync) 246{ 247 if (set) { 248 waitCount(0); 249 if (sync) { 250 syncResetCount++; 251 } else { 252 asyncResetCount++; 253 cancelTimeout(); 254 clearDynamic(); 255 scheduler.runNext(this); 256 } 257 } else { 258 if (sync) 259 syncResetCount--; 260 else 261 asyncResetCount--; 262 } 263} 264 265void 266Process::run() 267{ 268 bool reset; 269 do { 270 reset = false; 271 try { 272 func->call(); 273 } catch(ScHalt) { 274 std::cout << "Terminating process " << name() << std::endl; 275 } catch(const ::sc_core::sc_unwind_exception &exc) { 276 reset = exc.is_reset(); 277 _isUnwinding = false; 278 } catch (...) { 279 throw; 280 } 281 } while (reset); 282 needsStart(true); 283} 284 285void 286Process::addStatic(StaticSensitivity *s) 287{ 288 staticSensitivities.push_back(s); 289} 290 291void 292Process::setDynamic(DynamicSensitivity *s) 293{ 294 if (dynamicSensitivity) { 295 dynamicSensitivity->clear(); 296 delete dynamicSensitivity; 297 } 298 dynamicSensitivity = s; 299} 300 301void 302Process::addReset(Reset *reset) 303{ 304 resets.push_back(reset); 305} 306 307void 308Process::cancelTimeout() 309{ 310 if (timeoutEvent.scheduled()) 311 scheduler.deschedule(&timeoutEvent); 312} 313 314void 315Process::setTimeout(::sc_core::sc_time t) 316{ 317 cancelTimeout(); 318 scheduler.schedule(&timeoutEvent, t); 319} 320 321void 322Process::timeout() 323{ 324 // A process is considered timed_out only if it was also waiting for an 325 // event but got a timeout instead. 326 _timedOut = (dynamicSensitivity != nullptr); 327 328 setDynamic(nullptr); 329 if (disabled()) 330 return; 331 332 ready(); 333} 334 335void 336Process::satisfySensitivity(Sensitivity *s) 337{ 338 if (_waitCount) { 339 _waitCount--; 340 return; 341 } 342 343 // If there's a dynamic sensitivity and this wasn't it, ignore. 344 if ((dynamicSensitivity || timeoutEvent.scheduled()) && 345 dynamicSensitivity != s) { 346 return; 347 } 348 349 _timedOut = false; 350 // This sensitivity should already be cleared by this point, or the event 351 // which triggered it will take care of it. 352 delete dynamicSensitivity; 353 dynamicSensitivity = nullptr; 354 cancelTimeout(); 355 ready(); 356} 357 358void 359Process::ready() 360{ 361 if (disabled()) 362 return; 363 if (suspended()) 364 _suspendedReady = true; 365 else 366 scheduler.ready(this); 367} 368 369void 370Process::lastReport(::sc_core::sc_report *report) 371{ 372 if (report) { 373 _lastReport = std::unique_ptr<::sc_core::sc_report>( 374 new ::sc_core::sc_report(*report)); 375 } else { 376 _lastReport = nullptr; 377 } 378} 379 380::sc_core::sc_report *Process::lastReport() const { return _lastReport.get(); } 381 382Process::Process(const char *name, ProcessFuncWrapper *func, bool internal) : 383 ::sc_core::sc_process_b(name), excWrapper(nullptr), 384 timeoutEvent([this]() { this->timeout(); }), 385 func(func), _internal(internal), _timedOut(false), _dontInitialize(false), 386 _needsStart(true), _isUnwinding(false), _terminated(false), 387 _suspended(false), _disabled(false), _syncReset(false), syncResetCount(0), 388 asyncResetCount(0), _waitCount(0), refCount(0), 389 stackSize(::Fiber::DefaultStackSize), dynamicSensitivity(nullptr) 390{ 391 _dynamic = 392 (::sc_core::sc_get_status() > 393 ::sc_core::SC_BEFORE_END_OF_ELABORATION); 394 _newest = this; 395} 396 397void 398Process::terminate() 399{ 400 _terminated = true; 401 _suspendedReady = false; 402 _suspended = false; 403 _syncReset = false; 404 clearDynamic(); 405 cancelTimeout(); 406 for (auto s: staticSensitivities) { 407 s->clear(); 408 delete s; 409 } 410 staticSensitivities.clear(); 411 412 _terminatedEvent.notify(); 413 414 for (auto jw: joinWaiters) 415 jw->signal(); 416 joinWaiters.clear(); 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 427void 428newReset(const sc_core::sc_port_base *pb, Process *p, bool s, bool v) 429{ 430 Port *port = Port::fromPort(pb); 431 port->addReset(new Reset(p, s, v)); 432} 433 434void 435newReset(const sc_core::sc_signal_in_if<bool> *sig, Process *p, bool s, bool v) 436{ 437 Reset *reset = new Reset(p, s, v); 438 if (!reset->install(sig)) 439 delete reset; 440} 441 442} // namespace sc_gem5 443