proxygen
folly::futures::detail::Core< T > Class Template Referencefinal

#include <Core.h>

Classes

class  CoreAndCallbackReference
 

Public Types

using Result = Try< T >
 
using Callback = folly::Function< void(Result &&)>
 

Public Member Functions

 Core (Core const &)=delete
 
Coreoperator= (Core const &)=delete
 
 Core (Core &&) noexcept=delete
 
Coreoperator= (Core &&)=delete
 
bool hasCallback () const noexcept
 May call from any thread. More...
 
bool hasResult () const noexcept
 
bool ready () const noexcept
 
Try< T > & getTry ()
 
Try< T > const & getTry () const
 
template<typename F >
void setCallback (F &&func, std::shared_ptr< folly::RequestContext > context)
 
void setProxy (Core *proxy)
 
void setResult (Try< T > &&t)
 
void detachFuture () noexcept
 
void detachPromise () noexcept
 
void setExecutor (Executor::KeepAlive<> x, int8_t priority=Executor::MID_PRI)
 
void setExecutor (Executor *x, int8_t priority=Executor::MID_PRI)
 
ExecutorgetExecutor () const
 
int8_t getPriority () const
 
void raise (exception_wrapper e)
 
std::function< void(exception_wrapper const &)> getInterruptHandler ()
 
template<typename F >
void setInterruptHandler (F &&fn)
 
void setInterruptHandlerNoLock (std::function< void(exception_wrapper const &)> fn)
 

Static Public Member Functions

static Coremake ()
 State will be Start. More...
 
static Coremake (Try< T > &&t)
 
template<typename... Args>
static Core< T > * make (in_place_t, Args &&...args)
 

Private Types

using Context = std::shared_ptr< RequestContext >
 

Private Member Functions

 Core ()
 
 Core (Try< T > &&t)
 
template<typename... Args>
 Core (in_place_t, Args &&...args) noexcept(std::is_nothrow_constructible< T, Args &&... >::value)
 
 ~Core ()
 
void doCallback ()
 
void proxyCallback ()
 
void detachOne () noexcept
 
void derefCallback () noexcept
 

Private Attributes

union {
   Callback   callback_
 
}; 
 
union {
   Result   result_
 
   Core *   proxy_
 
}; 
 
std::atomic< Statestate_
 
std::atomic< unsigned char > attached_
 
std::atomic< unsigned char > callbackReferences_ {0}
 
std::atomic< bool > interruptHandlerSet_ {false}
 
SpinLock interruptLock_
 
int8_t priority_ {-1}
 
Executor::KeepAlive executor_
 
union {
   Context   context_
 
}; 
 
std::unique_ptr< exception_wrapperinterrupt_ {}
 
std::function< void(exception_wrapper const &)> interruptHandler_ {nullptr}
 

Detailed Description

template<typename T>
class folly::futures::detail::Core< T >

The shared state object for Future and Promise.

Nomenclature:

  • "result": a Try object which, when set, contains a T or exception.
  • "move-out the result": used to mean the Try object and/or its contents are moved-out by a move-constructor or move-assignment. After the result is set, Core itself never modifies (including moving out) the result; however the docs refer to both since caller-code can move-out the result implicitly (see below for examples) whereas other types of modifications are more explicit in the caller code.
  • "callback": a function provided by the future which Core may invoke. The thread in which the callback is invoked depends on the executor; if there is no executor or an inline executor the thread-choice depends on timing.
  • "executor": an object which may in the future invoke a provided function (some executors may, as a matter of policy, simply destroy provided functions without executing them).
  • "consumer thread": the thread which currently owns the Future and which may provide the callback and/or the interrupt.
  • "producer thread": the thread which owns the Future and which may provide the result and which may provide the interrupt handler.
  • "interrupt": if provided, an object managed by (if non-empty) exception_wrapper.
  • "interrupt handler": if provided, a function-object passed to promise.setInterruptHandler(). Core invokes the interrupt handler with the interrupt when both are provided (and, best effort, if there is not yet any result).

Core holds three sets of data, each of which is concurrency-controlled:

  • The primary producer-to-consumer info-flow: this info includes the result, callback, executor, and a priority for running the callback. Management of and concurrency control for this info is by an FSM based on enum class State. All state transitions are atomic; other producer-to-consumer data is sometimes modified within those transitions; see below for details.
  • The consumer-to-producer interrupt-request flow: this info includes an interrupt-handler and an interrupt. Concurrency of this info is controlled by a Spin Lock (interruptLock_).
  • Lifetime control info: this includes two reference counts, both which are internally synchronized (atomic).

The FSM to manage the primary producer-to-consumer info-flow has these allowed (atomic) transitions:

+-------------------------------------------------------------—+ | —> OnlyResult --— | | / \ | | (setResult()) (setCallback()) | | / \ | | Start ------—> ---—> Done | | \ \ / | | \ (setCallback()) (setResult()) | | \ \ / | | \ —> OnlyCallback — | | \ \ | | (setProxy()) (setProxy()) | | \ \ | | \ ---—> Empty | | \ / | | \ (setCallback()) | | \ / | | ------—> Proxy -------— | +-------------------------------------------------------------—+

States and the corresponding producer-to-consumer data status & ownership:

  • Start: has neither result nor callback. While in this state, the producer thread may set the result (setResult()) or the consumer thread may set the callback (setCallback()).
  • OnlyResult: producer thread has set the result and must never access it. The result is logically owned by, and possibly modified or moved-out by, the consumer thread. Callers of the future object can do arbitrary modifications, including moving-out, via continuations or via non-const and/or rvalue-qualified future.result(), future.value(), etc. Future/SemiFuture proper also move-out the result in some cases, e.g., in wait(), get(), when passing through values or results from core to core, as then-value and then-error, etc.
  • OnlyCallback: consumer thread has set a callback/continuation. From this point forward only the producer thread can safely access that callback (see setResult() and doCallback() where the producer thread can both read and modify the callback).
  • Proxy: producer thread has set a proxy core which the callback should be proxied to.
  • Done: callback can be safely accessed only within doCallback(), which gets called on exactly one thread exactly once just after the transition to Done. The future object will have determined whether that callback has/will move-out the result, but either way the result remains logically owned exclusively by the consumer thread (the code of Future/SemiFuture, of the continuation, and/or of callers of future.result(), etc.).
  • Empty: the core successfully proxied the callback and is now empty.

Start state:

  • Start: e.g., Core<X>::make().
  • (See also Core<X>::make(x) which logically transitions Start => OnlyResult within the underlying constructor.)

Terminal states:

  • OnlyResult: a terminal state when a callback is never attached, and also sometimes when a callback is provided, e.g., sometimes when future.wait() and/or future.get() are used.
  • Done: a terminal state when future.then() is used, and sometimes also when future.wait() and/or future.get() are used.
  • Proxy: a terminal state if proxy core was set, but callback was never set.
  • Empty: a terminal state when proxying a callback was successful.

Notes and caveats:

  • Unfortunately, there are things that users can do to break concurrency and we can't detect that. However users should be ok if they follow move semantics religiously wrt threading.
  • Futures and/or Promises can and usually will migrate between threads, though this usually happens within the API code. For example, an async operation will probably make a promise-future pair (see overloads of makePromiseContract()), then move the Promise into another thread that will eventually fulfill it.
  • Things get slightly more complicated with executors and via, but the principle is the same.
  • In general, as long as the user doesn't access a future or promise object from more than one thread at a time there won't be any problems.

Definition at line 195 of file Core.h.

Member Typedef Documentation

template<typename T>
using folly::futures::detail::Core< T >::Callback = folly::Function<void(Result&&)>

Definition at line 202 of file Core.h.

template<typename T>
using folly::futures::detail::Core< T >::Context = std::shared_ptr<RequestContext>
private

Definition at line 659 of file Core.h.

template<typename T>
using folly::futures::detail::Core< T >::Result = Try<T>

Definition at line 201 of file Core.h.

Constructor & Destructor Documentation

template<typename T>
folly::futures::detail::Core< T >::Core ( Core< T > const &  )
delete
template<typename T>
folly::futures::detail::Core< T >::Core ( Core< T > &&  )
deletenoexcept
template<typename T>
folly::futures::detail::Core< T >::Core ( )
inlineprivate

Definition at line 501 of file Core.h.

501 : state_(State::Start), attached_(2) {}
std::atomic< State > state_
Definition: Core.h:670
std::atomic< unsigned char > attached_
Definition: Core.h:671
template<typename T>
folly::futures::detail::Core< T >::Core ( Try< T > &&  t)
inlineexplicitprivate

Definition at line 503 of file Core.h.

References testing::Args().

std::atomic< State > state_
Definition: Core.h:670
std::atomic< unsigned char > attached_
Definition: Core.h:671
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
template<typename T>
template<typename... Args>
folly::futures::detail::Core< T >::Core ( in_place_t  ,
Args &&...  args 
)
inlineexplicitprivatenoexcept

Definition at line 507 of file Core.h.

509  : result_(in_place, std::forward<Args>(args)...),
511  attached_(1) {}
std::atomic< State > state_
Definition: Core.h:670
std::atomic< unsigned char > attached_
Definition: Core.h:671
in_place_tag in_place(in_place_tag={})
Definition: Utility.h:235
template<typename T>
folly::futures::detail::Core< T >::~Core ( )
inlineprivate

Definition at line 513 of file Core.h.

References folly::futures::detail::Done, folly::futures::detail::Empty, FOLLY_FALLTHROUGH, folly::futures::detail::OnlyResult, and folly::futures::detail::Proxy.

513  {
514  DCHECK(attached_ == 0);
515  auto state = state_.load(std::memory_order_relaxed);
516  switch (state) {
517  case State::OnlyResult:
519 
520  case State::Done:
521  result_.~Result();
522  break;
523 
524  case State::Proxy:
525  proxy_->detachFuture();
526  break;
527 
528  case State::Empty:
529  break;
530 
531  default:
532  terminate_with<std::logic_error>("~Core unexpected state");
533  }
534  }
std::atomic< State > state_
Definition: Core.h:670
std::atomic< unsigned char > attached_
Definition: Core.h:671
void detachFuture() noexcept
Definition: Core.h:409
#define FOLLY_FALLTHROUGH
Definition: CppAttributes.h:63
state
Definition: http_parser.c:272

Member Function Documentation

template<typename T>
void folly::futures::detail::Core< T >::derefCallback ( )
inlineprivatenoexcept

Definition at line 650 of file Core.h.

References c, and callback_.

650  {
651  auto c = callbackReferences_.fetch_sub(1, std::memory_order_acq_rel);
652  assert(c >= 1);
653  if (c == 1) {
654  context_.~Context();
655  callback_.~Callback();
656  }
657  }
std::atomic< unsigned char > callbackReferences_
Definition: Core.h:672
char c
template<typename T>
void folly::futures::detail::Core< T >::detachFuture ( )
inlinenoexcept

Called by a destructing Future (in the consumer thread, by definition). Calls delete this if there are no more references to this (including if detachPromise() is called previously or concurrently).

Definition at line 409 of file Core.h.

Referenced by folly::futures::detail::FutureBase< T >::detach(), and folly::Promise< T >::detach().

409  {
410  detachOne();
411  }
void detachOne() noexcept
Definition: Core.h:642
template<typename T>
void folly::futures::detail::Core< T >::detachOne ( )
inlineprivatenoexcept

Definition at line 642 of file Core.h.

References a.

642  {
643  auto a = attached_.fetch_sub(1, std::memory_order_acq_rel);
644  assert(a >= 1);
645  if (a == 1) {
646  delete this;
647  }
648  }
std::atomic< unsigned char > attached_
Definition: Core.h:671
char a
template<typename T>
void folly::futures::detail::Core< T >::detachPromise ( )
inlinenoexcept

Called by a destructing Promise (in the producer thread, by definition). Calls delete this if there are no more references to this (including if detachFuture() is called previously or concurrently).

Definition at line 416 of file Core.h.

Referenced by folly::futures::detail::coreDetachPromiseMaybeWithResult().

416  {
417  DCHECK(hasResult());
418  detachOne();
419  }
void detachOne() noexcept
Definition: Core.h:642
bool hasResult() const noexcept
Definition: Core.h:242
template<typename T>
void folly::futures::detail::Core< T >::doCallback ( )
inlineprivate

Definition at line 570 of file Core.h.

References callback_, folly::futures::detail::Core< T >::callback_, folly::futures::detail::Core< T >::context_, folly::futures::detail::Done, folly::exchange(), int8_t, LIKELY, folly::gen::move, folly::futures::detail::Core< T >::result_, and SCOPE_EXIT.

570  {
571  DCHECK(state_ == State::Done);
572  auto x = exchange(executor_, Executor::KeepAlive<>());
573  int8_t priority = priority_;
574 
575  if (x) {
576  exception_wrapper ew;
577  // We need to reset `callback_` after it was executed (which can happen
578  // through the executor or, if `Executor::add` throws, below). The
579  // executor might discard the function without executing it (now or
580  // later), in which case `callback_` also needs to be reset.
581  // The `Core` has to be kept alive throughout that time, too. Hence we
582  // increment `attached_` and `callbackReferences_` by two, and construct
583  // exactly two `CoreAndCallbackReference` objects, which call
584  // `derefCallback` and `detachOne` in their destructor. One will guard
585  // this scope, the other one will guard the lambda passed to the executor.
586  attached_.fetch_add(2, std::memory_order_relaxed);
587  callbackReferences_.fetch_add(2, std::memory_order_relaxed);
588  CoreAndCallbackReference guard_local_scope(this);
589  CoreAndCallbackReference guard_lambda(this);
590  try {
591  auto xPtr = x.get();
592  if (LIKELY(x->getNumPriorities() == 1)) {
593  xPtr->add([core_ref = std::move(guard_lambda),
594  keepAlive = std::move(x)]() mutable {
595  auto cr = std::move(core_ref);
596  Core* const core = cr.getCore();
597  RequestContextScopeGuard rctx(core->context_);
598  core->callback_(std::move(core->result_));
599  });
600  } else {
601  xPtr->addWithPriority(
602  [core_ref = std::move(guard_lambda),
603  keepAlive = std::move(x)]() mutable {
604  auto cr = std::move(core_ref);
605  Core* const core = cr.getCore();
606  RequestContextScopeGuard rctx(core->context_);
607  core->callback_(std::move(core->result_));
608  },
609  priority);
610  }
611  } catch (const std::exception& e) {
612  ew = exception_wrapper(std::current_exception(), e);
613  } catch (...) {
614  ew = exception_wrapper(std::current_exception());
615  }
616  if (ew) {
617  RequestContextScopeGuard rctx(context_);
618  result_ = Try<T>(std::move(ew));
620  }
621  } else {
622  attached_.fetch_add(1, std::memory_order_relaxed);
623  SCOPE_EXIT {
624  context_.~Context();
625  callback_.~Callback();
626  detachOne();
627  };
628  RequestContextScopeGuard rctx(context_);
630  }
631  }
Definition: InvokeTest.cpp:58
std::atomic< State > state_
Definition: Core.h:670
std::atomic< unsigned char > attached_
Definition: Core.h:671
void detachOne() noexcept
Definition: Core.h:642
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
#define LIKELY(x)
Definition: Likely.h:47
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
std::atomic< unsigned char > callbackReferences_
Definition: Core.h:672
Executor::KeepAlive executor_
Definition: Core.h:676
T exchange(T &obj, U &&new_value)
Definition: Utility.h:120
template<typename T>
Executor* folly::futures::detail::Core< T >::getExecutor ( ) const
inline

Definition at line 436 of file Core.h.

Referenced by folly::SemiFuture< T >::releaseDeferredExecutor().

436  {
437  return executor_.get();
438  }
ExecutorT * get() const
Definition: Executor.h:100
Executor::KeepAlive executor_
Definition: Core.h:676
template<typename T>
std::function<void(exception_wrapper const&)> folly::futures::detail::Core< T >::getInterruptHandler ( )
inline

Definition at line 463 of file Core.h.

References folly::lock().

463  {
464  if (!interruptHandlerSet_.load(std::memory_order_acquire)) {
465  return nullptr;
466  }
467  std::lock_guard<SpinLock> lock(interruptLock_);
468  return interruptHandler_;
469  }
std::function< void(exception_wrapper const &)> interruptHandler_
Definition: Core.h:681
auto lock(Synchronized< D, M > &synchronized, Args &&...args)
std::atomic< bool > interruptHandlerSet_
Definition: Core.h:673
template<typename T>
int8_t folly::futures::detail::Core< T >::getPriority ( ) const
inline

Definition at line 440 of file Core.h.

440  {
441  return priority_;
442  }
template<typename T>
Try<T>& folly::futures::detail::Core< T >::getTry ( )
inline

Call only from consumer thread (since the consumer thread can modify the referenced Try object; see non-const overloads of future.result(), etc., and certain Future-provided callbacks which move-out the result).

Unconditionally returns a reference to the result.

State dependent preconditions:

  • Start or OnlyCallback: Never safe - do not call. (Access in those states would be undefined behavior since the producer thread can, in those states, asynchronously set the referenced Try object.)
  • OnlyResult: Always safe. (Though the consumer thread should not use the returned reference after it attaches a callback unless it knows that the callback does not move-out the referenced result.)
  • Done: Safe but sometimes unusable. (Always returns a valid reference, but the referenced result may or may not have been modified, including possibly moved-out, depending on what the callback did; some but not all callbacks modify (possibly move-out) the result.)

Definition at line 280 of file Core.h.

References folly::futures::detail::Proxy.

280  {
281  DCHECK(hasResult());
282  auto core = this;
283  while (core->state_.load(std::memory_order_relaxed) == State::Proxy) {
284  core = core->proxy_;
285  }
286  return core->result_;
287  }
bool hasResult() const noexcept
Definition: Core.h:242
template<typename T>
Try<T> const& folly::futures::detail::Core< T >::getTry ( ) const
inline

Definition at line 288 of file Core.h.

References folly::futures::detail::Proxy.

288  {
289  DCHECK(hasResult());
290  auto core = this;
291  while (core->state_.load(std::memory_order_relaxed) == State::Proxy) {
292  core = core->proxy_;
293  }
294  return core->result_;
295  }
bool hasResult() const noexcept
Definition: Core.h:242
template<typename T>
bool folly::futures::detail::Core< T >::hasCallback ( ) const
inlinenoexcept

May call from any thread.

Definition at line 231 of file Core.h.

References folly::futures::detail::Done, and folly::futures::detail::OnlyCallback.

Referenced by folly::futures::detail::FutureBase< T >::throwIfContinued().

231  {
232  constexpr auto allowed = State::OnlyCallback | State::Done;
233  auto const state = state_.load(std::memory_order_acquire);
234  return State() != (state & allowed);
235  }
std::atomic< State > state_
Definition: Core.h:670
State
See Core for details.
Definition: Core.h:43
state
Definition: http_parser.c:272
template<typename T>
bool folly::futures::detail::Core< T >::hasResult ( ) const
inlinenoexcept

May call from any thread

True if state is OnlyResult or Done.

Identical to this->ready()

Definition at line 242 of file Core.h.

References folly::futures::detail::Done, folly::futures::detail::OnlyResult, and folly::futures::detail::Proxy.

Referenced by folly::futures::detail::coreDetachPromiseMaybeWithResult(), folly::Promise< T >::isFulfilled(), and folly::futures::detail::FutureBase< T >::isReady().

242  {
243  constexpr auto allowed = State::OnlyResult | State::Done;
244  auto core = this;
245  auto state = core->state_.load(std::memory_order_acquire);
246  while (state == State::Proxy) {
247  core = core->proxy_;
248  state = core->state_.load(std::memory_order_acquire);
249  }
250  return State() != (state & allowed);
251  }
State
See Core for details.
Definition: Core.h:43
state
Definition: http_parser.c:272
template<typename T>
static Core* folly::futures::detail::Core< T >::make ( )
inlinestatic

State will be Start.

Definition at line 205 of file Core.h.

Referenced by folly::makeFuture(), and folly::makeSemiFuture().

205  {
206  return new Core();
207  }
template<typename T>
static Core* folly::futures::detail::Core< T >::make ( Try< T > &&  t)
inlinestatic

State will be OnlyResult Result held will be move-constructed from t

Definition at line 211 of file Core.h.

References testing::Args(), folly::gen::move, and folly::pushmi::detail::t.

211  {
212  return new Core(std::move(t));
213  }
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
template<typename T>
template<typename... Args>
static Core<T>* folly::futures::detail::Core< T >::make ( in_place_t  ,
Args &&...  args 
)
inlinestatic

State will be OnlyResult Result held will be the T constructed from forwarded args

Definition at line 218 of file Core.h.

References folly::in_place(), and folly::pushmi::__adl::noexcept().

218  {
219  return new Core<T>(in_place, std::forward<Args>(args)...);
220  }
in_place_tag in_place(in_place_tag={})
Definition: Utility.h:235
template<typename T>
Core& folly::futures::detail::Core< T >::operator= ( Core< T > const &  )
delete
template<typename T>
Core& folly::futures::detail::Core< T >::operator= ( Core< T > &&  )
delete
template<typename T>
void folly::futures::detail::Core< T >::proxyCallback ( )
inlineprivate

Definition at line 633 of file Core.h.

References callback_, folly::futures::detail::Empty, and folly::gen::move.

633  {
634  state_.store(State::Empty, std::memory_order_relaxed);
637  proxy_->detachFuture();
638  context_.~Context();
639  callback_.~Callback();
640  }
std::atomic< State > state_
Definition: Core.h:670
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
void detachFuture() noexcept
Definition: Core.h:409
Executor::KeepAlive executor_
Definition: Core.h:676
void setExecutor(Executor::KeepAlive<> x, int8_t priority=Executor::MID_PRI)
Definition: Core.h:424
void setCallback(F &&func, std::shared_ptr< folly::RequestContext > context)
Definition: Core.h:306
template<typename T>
void folly::futures::detail::Core< T >::raise ( exception_wrapper  e)
inline

Call only from consumer thread

Eventual effect is to pass e to the Promise's interrupt handler, either synchronously within this call or asynchronously within setInterruptHandler(), depending on which happens first (a coin-toss if the two calls are racing).

Has no effect if it was called previously. Has no effect if State is OnlyResult or Done.

Definition at line 453 of file Core.h.

References folly::lock(), and folly::gen::move.

Referenced by folly::futures::detail::FutureBase< T >::raise().

453  {
454  std::lock_guard<SpinLock> lock(interruptLock_);
455  if (!interrupt_ && !hasResult()) {
456  interrupt_ = std::make_unique<exception_wrapper>(std::move(e));
457  if (interruptHandler_) {
459  }
460  }
461  }
std::function< void(exception_wrapper const &)> interruptHandler_
Definition: Core.h:681
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
auto lock(Synchronized< D, M > &synchronized, Args &&...args)
std::unique_ptr< exception_wrapper > interrupt_
Definition: Core.h:680
bool hasResult() const noexcept
Definition: Core.h:242
template<typename T>
bool folly::futures::detail::Core< T >::ready ( ) const
inlinenoexcept

May call from any thread

True if state is OnlyResult or Done.

Identical to this->hasResult()

Definition at line 258 of file Core.h.

258  {
259  return hasResult();
260  }
bool hasResult() const noexcept
Definition: Core.h:242
template<typename T>
template<typename F >
void folly::futures::detail::Core< T >::setCallback ( F &&  func,
std::shared_ptr< folly::RequestContext context 
)
inline

Call only from consumer thread. Call only once - else undefined behavior.

See FSM graph for allowed transitions.

If it transitions to Done, synchronously initiates a call to the callback, and might also synchronously execute that callback (e.g., if there is no executor or if the executor is inline).

Definition at line 306 of file Core.h.

References folly::assume(), callback_, folly::futures::detail::Done, folly::gen::move, folly::futures::detail::OnlyCallback, folly::futures::detail::OnlyResult, folly::futures::detail::Proxy, and folly::futures::detail::Start.

Referenced by folly::futures::detail::FutureBase< T >::setCallback_().

306  {
307  DCHECK(!hasCallback());
308 
309  // construct callback_ first; if that fails, context_ will not leak
310  ::new (&callback_) Callback(std::forward<F>(func));
311  ::new (&context_) Context(std::move(context));
312 
313  auto state = state_.load(std::memory_order_acquire);
314 
315  if (state == State::Start) {
316  if (state_.compare_exchange_strong(
317  state, State::OnlyCallback, std::memory_order_release)) {
318  return;
319  }
321  }
322 
323  if (state == State::OnlyResult) {
324  state_.store(State::Done, std::memory_order_relaxed);
325  doCallback();
326  return;
327  }
328 
329  if (state == State::Proxy) {
330  return proxyCallback();
331  }
332 
333  terminate_with<std::logic_error>("setCallback unexpected state");
334  }
std::atomic< State > state_
Definition: Core.h:670
folly::Function< void(Result &&)> Callback
Definition: Core.h:202
context
Definition: CMakeCache.txt:563
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
STL namespace.
def load()
Definition: deadlock.py:441
State
See Core for details.
Definition: Core.h:43
bool hasCallback() const noexcept
May call from any thread.
Definition: Core.h:231
if(FOLLY_USE_SYMBOLIZER) add_library(folly_exception_tracer_base ExceptionTracer.cpp StackTrace.cpp) apply_folly_compile_options_to_target(folly_exception_tracer_base) target_link_libraries(folly_exception_tracer_base PUBLIC folly) add_library(folly_exception_tracer ExceptionStackTraceLib.cpp ExceptionTracerLib.cpp) apply_folly_compile_options_to_target(folly_exception_tracer) target_link_libraries(folly_exception_tracer PUBLIC folly_exception_tracer_base) add_library(folly_exception_counter ExceptionCounterLib.cpp) apply_folly_compile_options_to_target(folly_exception_counter) target_link_libraries(folly_exception_counter PUBLIC folly_exception_tracer) install(FILES ExceptionAbi.h ExceptionCounterLib.h ExceptionTracer.h ExceptionTracerLib.h StackTrace.h DESTINATION $
Definition: CMakeLists.txt:1
std::shared_ptr< RequestContext > Context
Definition: Core.h:659
FOLLY_ALWAYS_INLINE void assume(bool cond)
Definition: Assume.h:41
state
Definition: http_parser.c:272
template<typename T>
void folly::futures::detail::Core< T >::setExecutor ( Executor::KeepAlive<>  x,
int8_t  priority = Executor::MID_PRI 
)
inline

Call only from consumer thread, either before attaching a callback or after the callback has already been invoked, but not concurrently with anything which might trigger invocation of the callback.

Definition at line 424 of file Core.h.

References folly::gen::move, and folly::futures::detail::OnlyCallback.

Referenced by folly::SemiFuture< T >::defer(), folly::SemiFuture< T >::releaseDeferredExecutor(), folly::SemiFuture< T >::stealDeferredExecutor(), and folly::SemiFuture< T >::via().

426  {
427  DCHECK(state_ != State::OnlyCallback);
428  executor_ = std::move(x);
429  priority_ = priority;
430  }
Definition: InvokeTest.cpp:58
std::atomic< State > state_
Definition: Core.h:670
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
Executor::KeepAlive executor_
Definition: Core.h:676
template<typename T>
void folly::futures::detail::Core< T >::setExecutor ( Executor x,
int8_t  priority = Executor::MID_PRI 
)
inline

Definition at line 432 of file Core.h.

References folly::getKeepAliveToken().

432  {
433  setExecutor(getKeepAliveToken(x), priority);
434  }
Definition: InvokeTest.cpp:58
void setExecutor(Executor::KeepAlive<> x, int8_t priority=Executor::MID_PRI)
Definition: Core.h:424
Executor::KeepAlive< ExecutorT > getKeepAliveToken(ExecutorT *executor)
Definition: Executor.h:200
template<typename T>
template<typename F >
void folly::futures::detail::Core< T >::setInterruptHandler ( F &&  fn)
inline

Call only from producer thread

May invoke fn() (passing the interrupt) synchronously within this call (if raise() preceded or perhaps if raise() is called concurrently).

Has no effect if State is OnlyResult or Done.

Note: fn() must not touch resources that are destroyed immediately after setResult() is called. Reason: it is possible for fn() to get called asynchronously (in the consumer thread) after the producer thread calls setResult().

Definition at line 483 of file Core.h.

References folly::as_const(), and folly::lock().

Referenced by folly::Promise< T >::setInterruptHandler().

483  {
484  std::lock_guard<SpinLock> lock(interruptLock_);
485  if (!hasResult()) {
486  if (interrupt_) {
487  fn(as_const(*interrupt_));
488  } else {
489  setInterruptHandlerNoLock(std::forward<F>(fn));
490  }
491  }
492  }
constexpr T const & as_const(T &t) noexcept
Definition: Utility.h:96
auto lock(Synchronized< D, M > &synchronized, Args &&...args)
std::unique_ptr< exception_wrapper > interrupt_
Definition: Core.h:680
void setInterruptHandlerNoLock(std::function< void(exception_wrapper const &)> fn)
Definition: Core.h:494
bool hasResult() const noexcept
Definition: Core.h:242
template<typename T>
void folly::futures::detail::Core< T >::setInterruptHandlerNoLock ( std::function< void(exception_wrapper const &)>  fn)
inline

Definition at line 494 of file Core.h.

References folly::gen::move.

Referenced by folly::Future< T >::onError().

495  {
496  interruptHandlerSet_.store(true, std::memory_order_relaxed);
498  }
std::function< void(exception_wrapper const &)> interruptHandler_
Definition: Core.h:681
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::atomic< bool > interruptHandlerSet_
Definition: Core.h:673
template<typename T>
void folly::futures::detail::Core< T >::setProxy ( Core< T > *  proxy)
inline

Call only from producer thread. Call only once - else undefined behavior.

See FSM graph for allowed transitions.

This can not be called concurrently with setResult().

Definition at line 342 of file Core.h.

References folly::assume(), FOLLY_FALLTHROUGH, folly::futures::detail::OnlyCallback, folly::futures::detail::Proxy, and folly::futures::detail::Start.

342  {
343  DCHECK(!hasResult());
344 
345  proxy_ = proxy;
346 
347  auto state = state_.load(std::memory_order_acquire);
348  switch (state) {
349  case State::Start:
350  if (state_.compare_exchange_strong(
351  state, State::Proxy, std::memory_order_release)) {
352  break;
353  }
356 
357  case State::OnlyCallback:
358  proxyCallback();
359  break;
360 
361  default:
362  terminate_with<std::logic_error>("setCallback unexpected state");
363  }
364 
365  detachOne();
366  }
std::atomic< State > state_
Definition: Core.h:670
void detachOne() noexcept
Definition: Core.h:642
FOLLY_ALWAYS_INLINE void assume(bool cond)
Definition: Assume.h:41
bool hasResult() const noexcept
Definition: Core.h:242
#define FOLLY_FALLTHROUGH
Definition: CppAttributes.h:63
state
Definition: http_parser.c:272
template<typename T>
void folly::futures::detail::Core< T >::setResult ( Try< T > &&  t)
inline

Call only from producer thread. Call only once - else undefined behavior.

See FSM graph for allowed transitions.

If it transitions to Done, synchronously initiates a call to the callback, and might also synchronously execute that callback (e.g., if there is no executor or if the executor is inline).

Definition at line 376 of file Core.h.

References folly::assume(), folly::futures::detail::Done, FOLLY_FALLTHROUGH, folly::gen::move, folly::futures::detail::OnlyCallback, folly::futures::detail::OnlyResult, folly::futures::detail::Start, and folly::pushmi::detail::t.

Referenced by folly::futures::detail::coreDetachPromiseMaybeWithResult(), and folly::Promise< T >::setTry().

376  {
377  DCHECK(!hasResult());
378 
379  ::new (&result_) Result(std::move(t));
380 
381  auto state = state_.load(std::memory_order_acquire);
382  while (true) {
383  switch (state) {
384  case State::Start:
385  if (state_.compare_exchange_strong(
386  state, State::OnlyResult, std::memory_order_release)) {
387  return;
388  }
391 
392  case State::OnlyCallback:
393  if (state_.compare_exchange_strong(
394  state, State::Done, std::memory_order_release)) {
395  doCallback();
396  return;
397  }
399 
400  default:
401  terminate_with<std::logic_error>("setResult unexpected state");
402  }
403  }
404  }
std::atomic< State > state_
Definition: Core.h:670
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
STL namespace.
def load()
Definition: deadlock.py:441
FOLLY_ALWAYS_INLINE void assume(bool cond)
Definition: Assume.h:41
bool hasResult() const noexcept
Definition: Core.h:242
#define FOLLY_FALLTHROUGH
Definition: CppAttributes.h:63
state
Definition: http_parser.c:272

Member Data Documentation

union { ... }
union { ... }
union { ... }
template<typename T>
std::atomic<unsigned char> folly::futures::detail::Core< T >::attached_
private

Definition at line 671 of file Core.h.

template<typename T>
Callback folly::futures::detail::Core< T >::callback_

Definition at line 662 of file Core.h.

Referenced by folly::futures::detail::Core< T >::doCallback().

template<typename T>
std::atomic<unsigned char> folly::futures::detail::Core< T >::callbackReferences_ {0}
private

Definition at line 672 of file Core.h.

template<typename T>
Context folly::futures::detail::Core< T >::context_

Definition at line 678 of file Core.h.

Referenced by folly::futures::detail::Core< T >::doCallback().

template<typename T>
Executor::KeepAlive folly::futures::detail::Core< T >::executor_
private

Definition at line 676 of file Core.h.

template<typename T>
std::unique_ptr<exception_wrapper> folly::futures::detail::Core< T >::interrupt_ {}
private

Definition at line 680 of file Core.h.

template<typename T>
std::function<void(exception_wrapper const&)> folly::futures::detail::Core< T >::interruptHandler_ {nullptr}
private

Definition at line 681 of file Core.h.

template<typename T>
std::atomic<bool> folly::futures::detail::Core< T >::interruptHandlerSet_ {false}
private

Definition at line 673 of file Core.h.

template<typename T>
SpinLock folly::futures::detail::Core< T >::interruptLock_
private

Definition at line 674 of file Core.h.

template<typename T>
int8_t folly::futures::detail::Core< T >::priority_ {-1}
private

Definition at line 675 of file Core.h.

template<typename T>
Core* folly::futures::detail::Core< T >::proxy_

Definition at line 668 of file Core.h.

template<typename T>
Result folly::futures::detail::Core< T >::result_

Definition at line 667 of file Core.h.

Referenced by folly::futures::detail::Core< T >::doCallback().

template<typename T>
std::atomic<State> folly::futures::detail::Core< T >::state_
private

Definition at line 670 of file Core.h.


The documentation for this class was generated from the following file: