15#ifndef THREAD_FIBER_FIBER_H_ 
   16#define THREAD_FIBER_FIBER_H_ 
   25#include <absl/log/check.h> 
   27#include "thread/boost_primitives.h" 
   28#include "thread/selectables.h" 
   33using InvocableWork = absl::AnyInvocable<void() &&>;
 
   36concept InvocableWithNoArgsAndReturnsVoid =
 
   37    std::is_invocable_v<std::decay_t<F>> &&
 
   38    std::is_same_v<std::invoke_result_t<F>, 
void>;
 
   41InvocableWork MakeInvocable(F&& f) 
requires 
   42    InvocableWithNoArgsAndReturnsVoid<F> {
 
   43  return InvocableWork(std::forward<F>(f));
 
   49std::unique_ptr<Fiber> CreateTree(InvocableWork f, TreeOptions&& tree_options);
 
   52Fiber* absl_nullable GetPerThreadFiberPtr();
 
   58  friend class FiberProperties;
 
   61  explicit Fiber(F&& f) 
requires InvocableWithNoArgsAndReturnsVoid<F>
 
   62      : Fiber(Unstarted{}, {std::forward<F>(f)}) {
 
   66  Fiber(
const Fiber&) = 
delete;
 
   67  Fiber& operator=(
const Fiber&) = 
delete;
 
   73  static Fiber* absl_nonnull Current();
 
   78  bool Cancelled()
 const { 
return cancellation_.HasBeenNotified(); }
 
   80  Case OnCancel()
 const { 
return cancellation_.OnEvent(); }
 
   82  Case OnJoinable()
 const { 
return joinable_.OnEvent(); }
 
   90  explicit Fiber(Unstarted, InvocableWork work, TreeOptions&& tree_options);
 
   92  explicit Fiber(Unstarted, InvocableWork work,
 
   93                 Fiber* absl_nonnull parent = Current());
 
  100  void PushBackChild(Fiber* absl_nonnull child)
 
  102      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
 
  103    if (first_child_ == 
nullptr) {
 
  104      first_child_ = child;
 
  106      child->prev_sibling_ = child;
 
  107      child->next_sibling_ = first_child_;
 
  108      first_child_->prev_sibling_ = child;
 
  112  void UnlinkChild(
const Fiber* absl_nonnull child)
 
  114      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
 
  115    if (child->next_sibling_ == child) {
 
  116      DCHECK(first_child_ == child)
 
  117          << 
"Unlinking a child that's the \"only\" sibling on its level, but " 
  118             "is not the first child.";
 
  119      first_child_ = 
nullptr;
 
  123    child->next_sibling_->prev_sibling_ = child->prev_sibling_;
 
  124    child->prev_sibling_->next_sibling_ = child->next_sibling_;
 
  125    if (first_child_ == child) {
 
  126      first_child_ = child->next_sibling_;
 
  130  mutable act::concurrency::impl::Mutex mu_;
 
  133  FiberProperties* absl_nullable properties_ ABSL_GUARDED_BY(mu_) = 
nullptr;
 
  138  std::atomic<bool> detached_ ABSL_GUARDED_BY(mu_) = 
false;
 
  140  enum State : uint8_t { RUNNING, FINISHED, JOINED };
 
  142  State state_ ABSL_GUARDED_BY(mu_) = RUNNING;
 
  144  Fiber* absl_nullable 
const parent_;
 
  145  Fiber* absl_nullable first_child_ ABSL_GUARDED_BY(mu_) = 
nullptr;
 
  146  Fiber* absl_nullable next_sibling_;
 
  147  Fiber* absl_nullable prev_sibling_;
 
  149  PermanentEvent cancellation_;
 
  150  PermanentEvent joinable_;
 
  152  friend std::unique_ptr<Fiber> internal::CreateTree(
 
  153      InvocableWork f, TreeOptions&& tree_options);
 
  155  friend class act::concurrency::impl::CondVar;
 
  157  friend struct ThreadLocalFiber;
 
  158  friend bool IsFiberDetached(
const Fiber* absl_nonnull fiber);
 
  159  friend void Detach(std::unique_ptr<Fiber> fiber);
 
  162class FiberProperties final : 
public boost::fibers::fiber_properties {
 
  165  friend class act::concurrency::impl::CondVar;
 
  167  explicit FiberProperties(boost::fibers::context* absl_nonnull ctx) = 
delete;
 
  169  explicit FiberProperties(Fiber* absl_nonnull fiber)
 
  170      : boost::fibers::fiber_properties(nullptr), fiber_(fiber) {}
 
  172  [[nodiscard]] Fiber* absl_nullable GetFiber()
 const { 
return fiber_; }
 
  175  Fiber* absl_nullable fiber_ = 
nullptr;
 
  176  act::concurrency::impl::CondVar* absl_nullable waiting_on_
 
  177      ABSL_GUARDED_BY(fiber_->mu_) = 
nullptr;
 
  181inline std::unique_ptr<Fiber> CreateTree(InvocableWork f,
 
  182                                         TreeOptions&& tree_options) {
 
  184      new Fiber(Fiber::Unstarted{}, std::move(f), std::move(tree_options));
 
  186  return absl::WrapUnique(fiber);
 
  191[[nodiscard]] std::unique_ptr<Fiber> NewTree(TreeOptions tree_options, F&& f) {
 
  192  return internal::CreateTree(MakeInvocable(std::forward<F>(f)),
 
  193                              std::move(tree_options));
 
  196inline void Detach(std::unique_ptr<Fiber> fiber) {
 
  198    act::concurrency::impl::MutexLock lock(&fiber->mu_);
 
  199    DCHECK(!fiber->detached_.load(std::memory_order_relaxed))
 
  200        << 
"Detach() called on already detached fiber, this should not be " 
  201           "possible without calling WrapUnique or similar on a Fiber* you do " 
  205    if (fiber->state_ != Fiber::FINISHED) {
 
  206      fiber->detached_.store(
true, std::memory_order_relaxed);
 
  210  if (ABSL_PREDICT_FALSE(fiber != 
nullptr)) {
 
  211    fiber->InternalJoin();
 
  215FiberProperties* absl_nullable GetCurrentFiberProperties();
 
  218void Detach(TreeOptions tree_options, F&& f) {
 
  219  Detach(NewTree(std::move(tree_options), std::forward<F>(f)));
 
  222inline bool Cancelled() {
 
  223  const Fiber* fiber_ptr = GetPerThreadFiberPtr();
 
  224  if (fiber_ptr == 
nullptr) {
 
  228  return fiber_ptr->Cancelled();
 
  231inline Case OnCancel() {
 
  232  const Fiber* current_fiber = Fiber::Current();
 
  233  if (current_fiber == 
nullptr) {
 
  234    return NonSelectableCase();
 
  236  return current_fiber->OnCancel();
 
A Case represents a selectable case in a Select statement.
Definition cases.h:80