Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement zero time-outs with dedicated queue #2813

Conversation

RaimoNiskanen
Copy link
Contributor

The previous solution was flawed because it immediately inserted
a zero time-out in the event queue, and tried to compensate for
when and how they would not fire due to state changes and other
events.

That implementation did not cut it e.g when combining a state
time-out with inserting an event, and in the new state, with
the state time-out, changing states. Then the state time-out
was not cancelled because it was already in the event queue,
and it arrived in a later state.

This commit changes the implementation into having a dedicated
queue for zero time-outs, from which events are extracted
as from the process mailbox, but before the process mailbox.
Now when cancelling a time-out, for any reason, automatic
or explicit, a zero time-out can be removed from this queue
as it would have been from the process mailbox for time > 0.

With this implementation it should be guaranteed that
a state time-out is delivered only in the state for which
it was started. A state change can always cancel it when it
is in the dedicated queue.

The queue is stored in the Timers map, with the specical key 't0q',
that does not collide with any timeout_event_type(), but needs to
be handled in a few places to protect form abuse and to correct
the time-out count. Having it here allows for cancel_timeout/2,3
to still operate on only the Timers map, and does not cause
unnecessary rebuild of terms when updating timers
and not having any zero time-outs.

The previous solution was flawed because it immediately inserted
a zero time-out in the event queue, and tried to compensate for
when and how they would not fire due to state changes and other
events.

That implementation did not cut it e.g when combining a state
time-out with inserting an event, and in the new state, with
the state time-out, changing states.  Then the state time-out
was not cancelled because it was already in the event queue,
and it arrived in a later state.

This commit changes the implementation into having a dedicated
queue for zero time-outs, from which events are extracted
as from the process mailbox, but before the process mailbox.
Now when cancelling a time-out, for any reason, automatic
or explicit, a zero time-out can be removed from this queue
as it would have been from the process mailbox for time > 0.

With this implementation it should be guaranteed that
a state time-out is delivered only in the state for which
it was started.  A state change can always cancel it when it
is in the dedicated queue.

The queue is stored in the Timers map, with the specical key 't0q',
that does not collide with any timeout_event_type(), but needs to
be handled in a few places to protect form abuse and to correct
the time-out count.  Having it here allows for cancel_timeout/2,3
to still operate on only the Timers map, and does not cause
unnecessary rebuild of terms when updating timers
and not having any zero time-outs.
@IngelaAndin IngelaAndin added the team:PS Assigned to OTP team PS label Oct 26, 2020
@RaimoNiskanen RaimoNiskanen merged commit 1581580 into erlang:master Oct 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
team:PS Assigned to OTP team PS
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants