[#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 <d.stepanov@yadro.com>
This commit is contained in:
Dmitrii Stepanov 2025-01-28 10:43:41 +03:00
parent f1cb5b40d5
commit d8663f1a74
Signed by: dstepanov-yadro
GPG key ID: 237AF1A763293BC0

View file

@ -36,7 +36,10 @@ func (c *systemClock) now() float64 {
} }
func (c *systemClock) runAt(ts float64, f func()) { 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() { func (c *systemClock) close() {
@ -48,7 +51,8 @@ func (c *systemClock) start() {
c.wg.Add(1) c.wg.Add(1)
go func() { go func() {
defer c.wg.Done() defer c.wg.Done()
t := time.NewTimer(time.Hour) t := time.NewTimer(0)
<-t.C
var f func() var f func()
for { for {
select { select {
@ -61,11 +65,10 @@ func (c *systemClock) start() {
if !ok { if !ok {
return return
} }
var d time.Duration
now := c.now() now := c.now()
if now >= s.ts { if now < s.ts {
s.f() d = time.Duration((s.ts - now) * 1e9)
f = nil
continue
} }
if !t.Stop() { if !t.Stop() {
select { select {
@ -73,7 +76,7 @@ func (c *systemClock) start() {
default: default:
} }
} }
t.Reset(time.Duration((s.ts - now) * 1e9)) t.Reset(d)
f = s.f f = s.f
} }
} }