fix: Resolve timer bugs causing lost timers and resource leaks #1894
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.
This PR fixes five bugs in
Timers.cppthat could cause timers to be lost, file descriptors to leak, and memory to accumulate.1. Inverted EAGAIN retry condition (line 162)
When the pipe buffer fills up and
write()returns EAGAIN, the retry loop had the wrong condition:This caused live timers to be silently dropped when the pipe was full, because the loop never executed for timers that weren't deleted.
Additionally, if a timer is cancelled while waiting for buffer space, the fix now cleans up
deletedTimers_to prevent leaking the timer ID:2. File descriptor leak (line 192)
Destroy()was closing only the read end of the pipe:Now both ends are properly closed:
3. deletedTimers_ accumulation (line 323)
Immediate timers (delay ≤ 0) skip the
sortedTimers_queue and write directly to the pipe. If cleared before the callback runs, their IDs were added todeletedTimers_but never removed.Added cleanup in
PumpTimerLoopCallback:4. Data race on stopped flag (Timers.h line 131)
The
stoppedflag was written under mutex inDestroy()but read without synchronization inPumpTimerLoopCallback(), causing undefined behavior per C++ standard.5. Non-EAGAIN write errors drop timers (line 92)
The condition
if (result != -1 || errno != EAGAIN)treated all non-EAGAIN errors (EPIPE, EBADF, EINTR) as success, disabling fallback scheduling:Additional fix: isBufferFull reset guard (line 171)
The
isBufferFulloptimization flag was being reset even whenwrite()failed with non-EAGAIN errors:This prevents incorrectly re-enabling the immediate timer optimization when the pipe is broken.