Skip to content

Commit

Permalink
Reimplement Scheduler affinity
Browse files Browse the repository at this point in the history
This diff changes how `unifex::task<>` implements *Scheduler* affinity to work
more like `folly::coro::Task<>`.  What Folly calls `co_viaIfAsync`, this diff
calls `with_scheduler_affinity`, which is a new CPO.

`with_scheduler_affinity` is a *Sender* algorithm that maps the given *Sender*
to another *Sender* that must meet new postconditions if the *Receiver* that
it's connected to meets certain preconditions.  The new preconditions are:
 - the eventual *Receiver* must provide a "current *Scheduler*";
 - the result of `with_scheduler_affinity` must be started on the *Receiver's*
   current *Scheduler*; and
 - stop requests delivered to the new *Sender* must be delivered on the
   *Receiver's* current *Scheduler*.

The *Sender* returned from `with_scheduler_affinity` must complete on its
*Receiver's* current *Scheduler* (i.e. must complete where it was started) so
long as all the above preconditions are met.

Any *Sender* type, `S`, that has `sender_traits<S>::is_always_scheduler_affine`
set to `true` will be returned unmodified from `with_scheduler_affinity`.  For
*Senders* that are not always *Scheduler*-affine and that do not customize
`with_scheduler_affinity`, the default implementation is:
```
template <typename Sender, typename Scheduler>
auto with_scheduler_affinity(Sender&& s, Scheduler&& sched) {
  return finally(
      std::forward<Sender>(s),
      unstoppable(schedule(std::forward<Scheduler>(sched))));
}
```
  • Loading branch information
ispeters committed May 24, 2023
1 parent 98d45ff commit 7bd7d60
Show file tree
Hide file tree
Showing 7 changed files with 611 additions and 109 deletions.
2 changes: 2 additions & 0 deletions include/unifex/at_coroutine_exit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,8 @@ namespace _at_coroutine_exit {
} at_coroutine_exit{};
} // namespace _at_coroutine_exit

// TODO: verify that `at_coroutine_exit()` can't be used to break scheduler
// affinity by running an async task that reschedules
using _at_coroutine_exit::at_coroutine_exit;

} // namespace unifex
Expand Down
7 changes: 7 additions & 0 deletions include/unifex/stop_if_requested.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ struct _fn {
// Provide an awaiter interface in addition to the sender interface
// because as an awaiter we can take advantage of symmetric transfer
// to save stack space:
//
// TODO: the scheduler affinity changes have mooted this because we check
// for sender-ness before awaitable-ness; two possible solutions:
// - check for awaitable-ness first
// - customize await_transform here to do something smarter than the
// default implementation; perhaps just return *this, but perhaps
// we could remove the branch in await_suspend
bool await_ready() const noexcept {
return false;
}
Expand Down
Loading

0 comments on commit 7bd7d60

Please sign in to comment.