Fix to commit coroutines immediately on wait statements (#4229)

Event-triggered coroutines live in two stages: 'uncommitted' and 'ready'. First
they land in 'uncommitted', meaning they can't be resumed yet. Only after
coroutines from the 'ready' queue are resumed, the 'uncommitted' ones are moved
to the 'ready' queue, and can be resumed. This is to avoid self-triggering in
situations like waiting for an event immediately after triggering it.

However, there is an issue with `wait` statements. If you have a `wait(b)`, it's
being translated into a loop that awaits a change in `b` as long as `b` is
false. If `b` is false at first, the coroutine is put into the `uncommitted`
queue. If `b` is set to true before it's committed, the coroutine won't get
resumed.

This patch fixes that by immediately committing event controls created from
`wait` statements. That means the coroutine from the example above will get
resumed from now on.
This commit is contained in:
Krzysztof Bieganski
2023-05-25 20:20:44 -04:00
committed by GitHub
parent bfa1f2d7ce
commit 519792d02b
11 changed files with 100 additions and 14 deletions
+10 -3
View File
@@ -237,6 +237,9 @@ private:
// to this sentree
// Ast{NodeProcedure,CFunc,Begin}::user2() -> bool. Set true if process/task
// is suspendable
// Ast{EventControl}::user2() -> bool. Set true if event control
// should immediately be
// committed
// AstSenTree::user2() -> AstCExpr*. Debug info passed to the
// timing schedulers
// const VNUser1InUse m_user1InUse; (Allocated for use in SuspendableVisitor)
@@ -709,6 +712,9 @@ private:
flp, new AstVarRef{flp, getCreateTriggerSchedulerp(sensesp), VAccess::WRITE},
"trigger"};
triggerMethodp->dtypeSetVoid();
// If it should be committed immediately, pass true, otherwise false
triggerMethodp->addPinsp(nodep->user2() ? new AstConst{flp, AstConst::BitTrue{}}
: new AstConst{flp, AstConst::BitFalse{}});
addEventDebugInfo(triggerMethodp, sensesp);
// Create the co_await
AstCAwait* const awaitp = new AstCAwait{flp, triggerMethodp, sensesp};
@@ -835,9 +841,10 @@ private:
AstSenItem* const senItemsp = varRefpsToSenItemsp(condp);
UASSERT_OBJ(senItemsp, nodep, "No varrefs in wait statement condition");
// Put the event control in a while loop with the wait expression as condition
auto* const loopp
= new AstWhile{flp, new AstLogNot{flp, condp},
new AstEventControl{flp, new AstSenTree{flp, senItemsp}, nullptr}};
AstEventControl* const controlp
= new AstEventControl{flp, new AstSenTree{flp, senItemsp}, nullptr};
controlp->user2(true); // Commit immediately
AstWhile* const loopp = new AstWhile{flp, new AstLogNot{flp, condp}, controlp};
if (stmtsp) AstNode::addNext<AstNode, AstNode>(loopp, stmtsp);
nodep->replaceWith(loopp);
}