Repository navigation
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
An overdue timer currently causes
hloop_process_events()to jump directly to timer processing, skipping the backend I/O poll:If a repeating timer continually overruns its interval, the loop can take this branch on every subsequent iteration. Ready sockets and posted custom events can then remain undiscovered for as long as the overrun continues, even though every timer callback returns normally.
The relevant code is the overdue-timer branch in
hloop_process_events(). The condition can sustain itself because repeating timers are rescheduled before their callbacks execute.Example: a small timer overrun stalls network work
Consider a server with a repeating 1 ms timer whose callback performs 2 ms of finite work. These timings are illustrative.
The timer expires. The loop advances its next deadline past the current timer-collection time, reinserts it into the timer heap, and schedules its callback.
The callback runs for 2 ms and returns. Its next deadline is now already overdue. Meanwhile, a client sends data and another thread posts a custom event. The socket and the custom-event wake descriptor become readable.
The next iteration skips polling. Because the timer is overdue,
hloop_process_events()jumps toprocess_timers. The readable socket and wake descriptor are not discovered.The same sequence repeats. The timer is rescheduled and its callback overruns again. Timer callbacks keep executing, while the client’s data and the posted custom event remain unprocessed.
This can make an application appear partially alive: timer callbacks continue running, but readiness-driven network handling stops making progress. Clients may wait despite their data already being available, and work submitted from other threads may remain queued.
Native events posted through
hloop_post_event()are affected because their queue is drained by the wake descriptor’s read callback. C++EventLoop::queueInLoop()ultimately uses this posting path.The failure occurs between finite callbacks: after a callback returns, the loop repeatedly misses the opportunity to discover other ready work.
Change
This change uses a zero poll timeout when the nearest timer is due or overdue, then continues through the existing I/O, clock-update, STOP-check and callback-dispatch path. Future-timer timeout rounding, the caller's timeout cap, timer repeat scheduling and callback priorities are preserved.
The new bounded regression uses real socket reads and posted events while forcing a repeating timer overdue for eight loop turns. It covers both timer heaps and remains active in Release builds. Static Linux CMake builds also check the actual backend timeout, exactly-due deadlines, future waits, the no-I/O path and STOP handling. The test is registered in both build systems and the Make test runner.