process.cc revision 13306:2196f4a8201f
18257SBrad.Beckmann@amd.com/* 28257SBrad.Beckmann@amd.com * Copyright 2018 Google, Inc. 38257SBrad.Beckmann@amd.com * 48257SBrad.Beckmann@amd.com * Redistribution and use in source and binary forms, with or without 58257SBrad.Beckmann@amd.com * modification, are permitted provided that the following conditions are 68257SBrad.Beckmann@amd.com * met: redistributions of source code must retain the above copyright 78257SBrad.Beckmann@amd.com * notice, this list of conditions and the following disclaimer; 88257SBrad.Beckmann@amd.com * redistributions in binary form must reproduce the above copyright 98257SBrad.Beckmann@amd.com * notice, this list of conditions and the following disclaimer in the 108257SBrad.Beckmann@amd.com * documentation and/or other materials provided with the distribution; 118257SBrad.Beckmann@amd.com * neither the name of the copyright holders nor the names of its 128257SBrad.Beckmann@amd.com * contributors may be used to endorse or promote products derived from 138257SBrad.Beckmann@amd.com * this software without specific prior written permission. 148257SBrad.Beckmann@amd.com * 158257SBrad.Beckmann@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 168257SBrad.Beckmann@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 178257SBrad.Beckmann@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 188257SBrad.Beckmann@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 198257SBrad.Beckmann@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 208257SBrad.Beckmann@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 218257SBrad.Beckmann@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 228257SBrad.Beckmann@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 238257SBrad.Beckmann@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 248257SBrad.Beckmann@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 258257SBrad.Beckmann@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 268257SBrad.Beckmann@amd.com * 278257SBrad.Beckmann@amd.com * Authors: Gabe Black 288257SBrad.Beckmann@amd.com */ 2912492Sodanrc@yahoo.com.br 3012492Sodanrc@yahoo.com.br#include "systemc/core/process.hh" 318257SBrad.Beckmann@amd.com 328257SBrad.Beckmann@amd.com#include "base/logging.hh" 338257SBrad.Beckmann@amd.com#include "systemc/core/event.hh" 348257SBrad.Beckmann@amd.com#include "systemc/core/port.hh" 358257SBrad.Beckmann@amd.com#include "systemc/core/scheduler.hh" 368257SBrad.Beckmann@amd.com#include "systemc/ext/core/sc_join.hh" 379465Snilay@cs.wisc.edu#include "systemc/ext/core/sc_main.hh" 388257SBrad.Beckmann@amd.com#include "systemc/ext/core/sc_process_handle.hh" 399465Snilay@cs.wisc.edu#include "systemc/ext/utils/sc_report_handler.hh" 408257SBrad.Beckmann@amd.com 418257SBrad.Beckmann@amd.comnamespace sc_gem5 428257SBrad.Beckmann@amd.com{ 438257SBrad.Beckmann@amd.com 448257SBrad.Beckmann@amd.comclass UnwindExceptionReset : public ::sc_core::sc_unwind_exception 458257SBrad.Beckmann@amd.com{ 468257SBrad.Beckmann@amd.com public: 478257SBrad.Beckmann@amd.com UnwindExceptionReset() { _isReset = true; } 488257SBrad.Beckmann@amd.com}; 498257SBrad.Beckmann@amd.com 508257SBrad.Beckmann@amd.comclass UnwindExceptionKill : public ::sc_core::sc_unwind_exception 518257SBrad.Beckmann@amd.com{ 528257SBrad.Beckmann@amd.com public: 539274Snilay@cs.wisc.edu UnwindExceptionKill() {} 5411664Stushar@ece.gatech.edu}; 558257SBrad.Beckmann@amd.com 568257SBrad.Beckmann@amd.comtemplate <typename T> 578257SBrad.Beckmann@amd.comstruct BuiltinExceptionWrapper : public ExceptionWrapperBase 588257SBrad.Beckmann@amd.com{ 598257SBrad.Beckmann@amd.com public: 608257SBrad.Beckmann@amd.com T t; 618257SBrad.Beckmann@amd.com void throw_it() override { throw t; } 628257SBrad.Beckmann@amd.com}; 638257SBrad.Beckmann@amd.com 648257SBrad.Beckmann@amd.comBuiltinExceptionWrapper<UnwindExceptionReset> resetException; 6512492Sodanrc@yahoo.com.brBuiltinExceptionWrapper<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 return; 211 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 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 _suspended(false), _disabled(false), _syncReset(false), syncResetCount(0), 384 asyncResetCount(0), _waitCount(0), refCount(0), 385 stackSize(::Fiber::DefaultStackSize), dynamicSensitivity(nullptr) 386{ 387 _dynamic = 388 (::sc_core::sc_get_status() > 389 ::sc_core::SC_BEFORE_END_OF_ELABORATION); 390 _newest = this; 391} 392 393void 394Process::terminate() 395{ 396 _terminated = true; 397 _suspendedReady = false; 398 _suspended = false; 399 _syncReset = false; 400 clearDynamic(); 401 cancelTimeout(); 402 for (auto s: staticSensitivities) { 403 s->clear(); 404 delete s; 405 } 406 staticSensitivities.clear(); 407 408 _terminatedEvent.notify(); 409 410 for (auto jw: joinWaiters) 411 jw->signal(); 412 joinWaiters.clear(); 413} 414 415Process *Process::_newest; 416 417void 418throw_it_wrapper(Process *p, ExceptionWrapperBase &exc, bool inc_kids) 419{ 420 p->throw_it(exc, inc_kids); 421} 422 423void 424newReset(const sc_core::sc_port_base *pb, Process *p, bool s, bool v) 425{ 426 Port *port = Port::fromPort(pb); 427 port->addReset(new Reset(p, s, v)); 428} 429 430void 431newReset(const sc_core::sc_signal_in_if<bool> *sig, Process *p, bool s, bool v) 432{ 433 Reset *reset = new Reset(p, s, v); 434 if (!reset->install(sig)) 435 delete reset; 436} 437 438} // namespace sc_gem5 439