Fiber-compatible Future

Fiber-compatible Future

folly's Future API is Fiber-compatible.

Calling get() on a folly::Future object will only suspend the calling fiber-task. It won't block the system thread, letting it process other tasks. – https://github.com/facebook/folly/blob/master/folly/fibers/README.md

But how does it actually work? E.g. what happens when calling folly::futures::sleep(1).get() inside a Fiber?

When you call get() on a future, it will first wait() https://github.com/facebook/folly/blob/master/folly/futures/Future-inl.h#L2259-L2265 until the promise is fulfilled.

template <class T>
Try<T> SemiFuture<T>::getTry() && {
  wait();
  auto future = folly::Future<T>(this->core_);
  this->core_ = nullptr;
  return std::move(std::move(future).result());
}

wait() is implemented by waiting on a baton of FutureBatonType which is typedefed to folly::fibers::Baton (https://github.com/facebook/folly/blob/master/folly/futures/Future-inl.h#L2078-L2099).

template <class FutureType, typename T = typename FutureType::value_type>
void waitImpl(FutureType& f) {
  if (std::is_base_of<Future<T>, FutureType>::value) {
    f = std::move(f).via(&InlineExecutor::instance());
  }
  // short-circuit if there's nothing to do
  if (f.isReady()) {
    return;
  }

  Promise<T> promise;
  auto ret = convertFuture(promise.getSemiFuture(), f);
  FutureBatonType baton;
  f.setCallback_([&baton, promise = std::move(promise)](
                     Executor::KeepAlive<>&&, Try<T>&& t) mutable {
    promise.setTry(std::move(t));
    baton.post();
  });
  f = std::move(ret);
  baton.wait();
  assert(f.isReady());
}

This code says

  • if f is a child of Future<T> type, just execute the future inline
  • it schedules a callback on the future, which posts the baton when ready
  • it then waits on the baton

Now it's clear that why folly::Future is fiber-compatible. The short answer is that because it uses fiber::baton for waiting. When a fiber::baton is waited upon, it will try to get the thread-local fiber manager FiberManager::getFiberManagerUnsafe() if it has one. Then it can perform cooperative multi-tasking.