From f66271e62ee5f65b20d6814fbe84e76a68c66b27 Mon Sep 17 00:00:00 2001 From: yihong Date: Sun, 7 Apr 2024 17:17:00 +0800 Subject: [PATCH] fix: use goroutine progress instead of state to determine deadlock (#24) * feat: track if a goroutine has made progress This is done by keeping track of what is the last instruction that is executed by the goroutine. `progress = prev_instruction !== curr_instruction` * fix: check goroutine progress during deadlock detection --- src/go-slang/goroutine.ts | 7 +++++++ src/go-slang/scheduler.ts | 11 +++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/go-slang/goroutine.ts b/src/go-slang/goroutine.ts index 04831d635..f39f6739c 100644 --- a/src/go-slang/goroutine.ts +++ b/src/go-slang/goroutine.ts @@ -89,6 +89,10 @@ export class GoRoutine { private context: Context private scheduler: Scheduler + // used to determine if the goroutine made progress in the last tick + public progress: boolean = false + private prevInst: Instruction | null = null + public state: GoRoutineState public isMain: boolean @@ -114,6 +118,9 @@ export class GoRoutine { Result.ok(C.isEmpty() ? GoRoutineState.Exited : GoRoutineState.Running) this.state = nextState.isSuccess ? nextState.unwrap() : GoRoutineState.Exited + this.progress = this.prevInst !== inst + this.prevInst = inst + return nextState } } diff --git a/src/go-slang/scheduler.ts b/src/go-slang/scheduler.ts index 1b6199ede..ce093b0ea 100644 --- a/src/go-slang/scheduler.ts +++ b/src/go-slang/scheduler.ts @@ -28,9 +28,10 @@ export class Scheduler { @benchmark('Scheduler::run') public run(): void { - let numConsecAllBlocks = 0 + // the number of consecutive time quanta where all routines made no progress + let numConsecNoProgress = 0 - while (this.routines.length && numConsecAllBlocks < this.routines.length) { + while (this.routines.length && numConsecNoProgress < this.routines.length) { const [routine, timeQuanta] = this.routines.shift() as [GoRoutine, TimeQuanta] let remainingTime = timeQuanta @@ -52,10 +53,8 @@ export class Scheduler { this.schedule(routine) - const hasRunningRoutines = this.routines.some( - ([{ state }]) => state === GoRoutineState.Running - ) - numConsecAllBlocks = hasRunningRoutines ? 0 : numConsecAllBlocks + 1 + const hasProgress = this.routines.some(([{ progress }]) => progress) + numConsecNoProgress = hasProgress ? 0 : numConsecNoProgress + 1 } // if we reach here, all routines are blocked