ngo
ngo copied to clipboard
Resolve the atomicity issues when changing pollee's state
Background
The async_io::event::Pollee
maintains a state of Events
that can be polled by poller. Currently, there are three methods that can change the Events
state:
-
add_events
: Add some new events, triggering interesting pollers. -
del_events
: Delete some events. -
reset_events
: Clear all events.
Problem
The individual methods are thread safe. But sometime the user code may want to use them in combination.
pollee.reset_events();
pollee.add_events(Events::OUT);
The problem with this code is that since the two operations as a whole are not atomic, other concurrent threads may observe an intermediate states (no events). This could cause problems in some use cases. The user code may use an auxiliary mutex to ensure the atomicity, but this is fragile.
Solution
I propose two actions. First, review the current usage of Pollee
and confirm the atomicity issue. Second, replace the three methods with the following two new methods.
-
set_events(new: Events, will_notify: bool)
, which sets a pollee's state to a new state atomically. Ifwill_notify
is true, then interesting pollers will be notified. -
update_events(to_del: Events, to_add: Events)
, which removes some events from a pollee's state and add some new ones to it atomically. The interesting pollers will be notified about the new events.
Their semantics are shown below.
-
set_events(new) = reset_events() + add_events(new)
-
update_events(to_del, to_add) = del_events(to_del) + add_events(to_add)
The old three methods can be readily implemented with the new ones.
-
add_events(to_add) = update_events(Events::empty(), to_add)
-
del_events(to_del) = update_events(to_del, Events::empty())
-
reset_events() = set_events(Events::empty())
As you can see, the two new methods are more powerful.