Timers scheduled with identical `fire_time` could fire out of order
because the heap is not stable. This change assigns a monotonically
increasing `sequence_id` when a timer is scheduled and extend the heap
comparator to order by (`fire_time`, `sequence_id`). This guarantees
FIFO among timers with the same deadline.
This matches the HTML "run steps after a timeout" ordering requirement:
older invocations with <= delay complete before newer ones.
https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#run-steps-after-a-timeout
The issue with that refactor was that the same fd can be used in more
than one notifier. This reverts us back to using 2 members to track the
notifiers in play.
POLLHUP is set when the remote end of the monitored fd is closed. There
may still be some buffered data to read from the socket, however. Some
systems do not set POLLIN in these cases. So we should just always try
to read from fds when we receive this event.