From d8663f1a74d810e03090813a9d92fcc7adf4f36f Mon Sep 17 00:00:00 2001 From: Dmitrii Stepanov Date: Tue, 28 Jan 2025 10:43:41 +0300 Subject: [PATCH] [#1] mclock: Fix possible deadlock There is a possible call-chain `scheduleRequest()` -> `runAt()` -> `scheduleRequest()`, so second `scheduleRequest()` may be locked on mutext held by first `scheduleRequest()`. Signed-off-by: Dmitrii Stepanov --- scheduling/clock.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/scheduling/clock.go b/scheduling/clock.go index 99e6075..9fe66bd 100644 --- a/scheduling/clock.go +++ b/scheduling/clock.go @@ -36,7 +36,10 @@ func (c *systemClock) now() float64 { } func (c *systemClock) runAt(ts float64, f func()) { - c.schedule <- scheduleInfo{ts: ts, f: f} + select { + case c.schedule <- scheduleInfo{ts: ts, f: f}: + default: // timer fired, scheduleRequest will call runAt again + } } func (c *systemClock) close() { @@ -48,7 +51,8 @@ func (c *systemClock) start() { c.wg.Add(1) go func() { defer c.wg.Done() - t := time.NewTimer(time.Hour) + t := time.NewTimer(0) + <-t.C var f func() for { select { @@ -61,11 +65,10 @@ func (c *systemClock) start() { if !ok { return } + var d time.Duration now := c.now() - if now >= s.ts { - s.f() - f = nil - continue + if now < s.ts { + d = time.Duration((s.ts - now) * 1e9) } if !t.Stop() { select { @@ -73,7 +76,7 @@ func (c *systemClock) start() { default: } } - t.Reset(time.Duration((s.ts - now) * 1e9)) + t.Reset(d) f = s.f } }