ngo icon indicating copy to clipboard operation
ngo copied to clipboard

Resolve the atomicity issues when changing pollee's state

Open tatetian opened this issue 3 years ago • 0 comments

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. If will_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.

tatetian avatar Oct 21 '21 02:10 tatetian