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.
This commit is contained in:
Elias Naur
2025-07-15 15:35:47 +02:00
committed by Ron Evans
parent 15e37ff927
commit 78914382c3
2 changed files with 4 additions and 4 deletions
+3 -3
View File
@@ -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
+1 -1
View File
@@ -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