[#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()) {
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
}
}