From f6fda869ead3aae97e73d2222bfc9fdfd837491e Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 30 Aug 2018 00:39:49 -0700 Subject: [PATCH] systemc: Keep track of more cases when we should be ready after resume. If a thread self suspends, it should be marked as ready after resuming. If a process was already ready when suspended, it should also be remarked as ready after resuming. Special care has to be taken in pre-initialization situations so that processes are put on the right lists, and whether a process is tracked is already marked as ready. Change-Id: I15da7d747db591785358d47781297468c5f9fd09 Reviewed-on: https://gem5-review.googlesource.com/c/12445 Reviewed-by: Gabe Black Maintainer: Gabe Black --- src/systemc/core/process.cc | 18 +++++++++++------- src/systemc/core/scheduler.cc | 33 +++++++++++++++++++++++++++++++++ src/systemc/core/scheduler.hh | 8 ++++++++ 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/systemc/core/process.cc b/src/systemc/core/process.cc index 830b8c729..1fd16e0d9 100644 --- a/src/systemc/core/process.cc +++ b/src/systemc/core/process.cc @@ -160,12 +160,16 @@ Process::suspend(bool inc_kids) if (!_suspended) { _suspended = true; - _suspendedReady = false; - } - - if (procKind() != ::sc_core::SC_METHOD_PROC_ && - scheduler.current() == this) { - scheduler.yield(); + _suspendedReady = scheduler.suspend(this); + + if (procKind() != ::sc_core::SC_METHOD_PROC_ && + scheduler.current() == this) { + // This isn't in the spec, but Accellera says that a thread that + // self suspends should be marked ready immediately when it's + // resumed. + _suspendedReady = true; + scheduler.yield(); + } } } @@ -178,7 +182,7 @@ Process::resume(bool inc_kids) if (_suspended) { _suspended = false; if (_suspendedReady) - ready(); + scheduler.resume(this); _suspendedReady = false; } } diff --git a/src/systemc/core/scheduler.cc b/src/systemc/core/scheduler.cc index 46053b40f..9b431acba 100644 --- a/src/systemc/core/scheduler.cc +++ b/src/systemc/core/scheduler.cc @@ -200,6 +200,39 @@ Scheduler::ready(Process *p) scheduleReadyEvent(); } +void +Scheduler::resume(Process *p) +{ + if (initDone) + ready(p); + else + initList.pushLast(p); +} + +bool +Scheduler::suspend(Process *p) +{ + if (initDone) { + // After initialization, the only list we can be on is the ready list. + bool was_ready = (p->nextListNode != nullptr); + p->popListNode(); + return was_ready; + } else { + bool was_ready = false; + // Check the ready list to see if we find this process. + ListNode *n = readyList.nextListNode; + while (n != &readyList) { + if (n == p) { + was_ready = true; + break; + } + } + if (was_ready) + toFinalize.pushLast(p); + return was_ready; + } +} + void Scheduler::requestUpdate(Channel *c) { diff --git a/src/systemc/core/scheduler.hh b/src/systemc/core/scheduler.hh index 2da8da470..f55ff1f83 100644 --- a/src/systemc/core/scheduler.hh +++ b/src/systemc/core/scheduler.hh @@ -182,6 +182,14 @@ class Scheduler // Put a process on the ready list. void ready(Process *p); + // Mark a process as ready if init is finished, or put it on the list of + // processes to be initialized. + void resume(Process *p); + + // Remove a process from the ready/init list if it was on one of them, and + // return if it was. + bool suspend(Process *p); + // Schedule an update for a given channel. void requestUpdate(Channel *c); -- 2.30.2