From 78914382c39e941a2e22187f1f7c3ba1324f24f9 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Tue, 15 Jul 2025 15:35:47 +0200 Subject: [PATCH] runtime: ensure time.Sleep(d) sleeps at least d Account for the sleep queue base time in the computation of the wakeup time. Tested with the following program on pico2. func main() { go func() { for i := range 60 { const delay = 20 * time.Millisecond before := time.Now() time.Sleep(delay) if d := time.Since(before); true || d < delay { log.Println(i, "actual", d, "delay", delay) } } }() time.Sleep(500 * time.Millisecond) log.Println("******** done sleeping ********") select {} } Without this change, the program would print lines such as: 17 actual 15.494ms delay 20ms 18 actual 15.49ms delay 20ms 19 actual 15.585ms delay 20ms 20 actual 15.493ms delay 20ms 21 actual 15.494ms delay 20ms 22 actual 15.487ms delay 20ms 23 actual 15.498ms delay 20ms ******** done sleeping ******** 24 actual 15.548ms delay 20ms 25 actual 20.011ms delay 20ms 26 actual 20.01ms delay 20ms 27 actual 20.011ms delay 20ms 28 actual 20.015ms delay 20ms Note that while more than one sleeping goroutine is in the timer queue, the sleep duration is 5ms short. --- builder/sizes_test.go | 6 +++--- src/runtime/scheduler_cooperative.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/builder/sizes_test.go b/builder/sizes_test.go index 818404064..f4274708d 100644 --- a/builder/sizes_test.go +++ b/builder/sizes_test.go @@ -42,9 +42,9 @@ func TestBinarySize(t *testing.T) { // This is a small number of very diverse targets that we want to test. tests := []sizeTest{ // microcontrollers - {"hifive1b", "examples/echo", 4556, 280, 0, 2264}, - {"microbit", "examples/serial", 2920, 388, 8, 2272}, - {"wioterminal", "examples/pininterrupt", 7379, 1489, 116, 6912}, + {"hifive1b", "examples/echo", 4580, 280, 0, 2264}, + {"microbit", "examples/serial", 2928, 388, 8, 2272}, + {"wioterminal", "examples/pininterrupt", 7387, 1489, 116, 6912}, // TODO: also check wasm. Right now this is difficult, because // wasm binaries are run through wasm-opt and therefore the diff --git a/src/runtime/scheduler_cooperative.go b/src/runtime/scheduler_cooperative.go index bf6f5aec4..274daa84d 100644 --- a/src/runtime/scheduler_cooperative.go +++ b/src/runtime/scheduler_cooperative.go @@ -77,7 +77,6 @@ func addSleepTask(t *task.Task, duration timeUnit) { panic("runtime: addSleepTask: expected next task to be nil") } } - t.Data = uint64(duration) now := ticks() if sleepQueue == nil { scheduleLog(" -> sleep new queue") @@ -85,6 +84,7 @@ func addSleepTask(t *task.Task, duration timeUnit) { // set new base time sleepQueueBaseTime = now } + t.Data = uint64(duration + (now - sleepQueueBaseTime)) // Add to sleep queue. q := &sleepQueue