Skip to content

Commit 4c06868

Browse files
authored
Fix: time calculations in IOCP and Monitor thread (#16583)
* Fix: invalid absolute to relative time conversions in IOCP event loop * Fix: invalid remaining time calculation in monitor thread
1 parent 7dff995 commit 4c06868

File tree

3 files changed

+13
-14
lines changed

3 files changed

+13
-14
lines changed

src/crystal/event_loop/iocp.cr

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,9 @@ class Crystal::EventLoop::IOCP < Crystal::EventLoop
100100
timeout = blocking ? LibC::INFINITE : 0_i64
101101
elsif blocking
102102
if time = @timers_mutex.synchronize { @timers.next_ready? }
103-
# convert absolute time of next timer to relative time, expressed in
104-
# milliseconds, rounded up
105-
# Cannot use `time.elapsed` here because it calls `::Time.instant` which
106-
# could be mocked.
107-
relative = Crystal::System::Time.instant.duration_since(time)
103+
# convert absolute time to relative time, expressed in milliseconds,
104+
# rounded up; cannot use `::Time.instant` that could be mocked
105+
relative = time.duration_since(Crystal::System::Time.instant)
108106
timeout = (relative.to_i * 1000 + (relative.nanoseconds + 999_999) // 1_000_000)
109107
else
110108
timeout = LibC::INFINITE

src/crystal/system/win32/waitable_timer.cr

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@ class Crystal::System::WaitableTimer
1414

1515
def set(time : ::Time::Instant) : Nil
1616
# convert absolute time to relative time, expressed in 100ns interval,
17-
# rounded up
18-
# Cannot use `time.elapsed` here because it calls `::Time.instant` which
19-
# could be mocked.
20-
relative = Crystal::System::Time.instant.duration_since(time)
17+
# rounded up; cannot use `::Time.instant` that could be mocked
18+
relative = time.duration_since(Crystal::System::Time.instant)
2119
ticks = (relative.to_i * 10_000_000 + (relative.nanoseconds + 99) // 100)
2220

2321
# negative duration means relative time (positive would mean absolute

src/fiber/execution_context/monitor.cr

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,14 @@ module Fiber::ExecutionContext
4747

4848
loop do
4949
Thread.sleep(remaining)
50-
now = Crystal::System::Time.instant
51-
yield(now)
52-
# Cannot use `now.elapsed` here because it calls `::Time.instant` which
53-
# could be mocked.
54-
remaining = Crystal::System::Time.instant.duration_since(now) + @every
50+
51+
start = Crystal::System::Time.instant
52+
yield(start)
53+
stop = Crystal::System::Time.instant
54+
55+
# calculate remaining time for more steady wakeups (minimize exponential
56+
# delays)
57+
remaining = (start + @every - stop).clamp(Time::Span.zero..)
5558
rescue exception
5659
Crystal.print_error_buffered("BUG: %s#every crashed", self.class.name, exception: exception)
5760
end

0 commit comments

Comments
 (0)