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 <gabeblack@google.com> Maintainer: Gabe Black <gabeblack@google.com>
This commit is contained in:
@@ -160,12 +160,16 @@ Process::suspend(bool inc_kids)
|
||||
|
||||
if (!_suspended) {
|
||||
_suspended = true;
|
||||
_suspendedReady = false;
|
||||
}
|
||||
_suspendedReady = scheduler.suspend(this);
|
||||
|
||||
if (procKind() != ::sc_core::SC_METHOD_PROC_ &&
|
||||
scheduler.current() == this) {
|
||||
scheduler.yield();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user