X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Ffutures%2Fdetail%2FCore.h;h=d3dba861613506f7727f627477037c9125cfa1f9;hb=4d499e087e0445ff71a12eb1d5071cf33529d046;hp=773da5e0e146ee4cb3669fc93b5a50df3d7dd724;hpb=56a2009b5016f207906f0fa80831b82769fd1f6a;p=folly.git diff --git a/folly/futures/detail/Core.h b/folly/futures/detail/Core.h index 773da5e0..d3dba861 100644 --- a/folly/futures/detail/Core.h +++ b/folly/futures/detail/Core.h @@ -1,5 +1,5 @@ /* - * Copyright 2015 Facebook, Inc. + * Copyright 2016 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,13 +21,13 @@ #include #include -#include +#include +#include #include - -#include -#include +#include #include -#include +#include +#include #include #include @@ -99,6 +99,26 @@ class Core { Core(Core&&) noexcept = delete; Core& operator=(Core&&) = delete; + // Core is assumed to be convertible only if the type is convertible + // and the size is the same. This is a compromise for the complexity + // of having to make Core truly have a conversion constructor which + // would cause various other problems. + // If we made Core move constructible then we would need to update the + // Promise and Future with the location of the new Core. This is complex + // and may be inefficient. + // Core should only be modified so that for size(T) == size(U), + // sizeof(Core) == size(Core). + // This assumption is used as a proxy to make sure that + // the members of Core and Core line up so that we can use a + // reinterpret cast. + template < + class U, + typename = typename std::enable_if::value && + sizeof(U) == sizeof(T)>::type> + static Core* convert(Core* from) { + return reinterpret_cast*>(from); + } + /// May call from any thread bool hasResult() const { switch (fsm_.getState()) { @@ -127,34 +147,13 @@ class Core { } } - template - class LambdaBufHelper { - public: - template - explicit LambdaBufHelper(FF&& func) : func_(std::forward(func)) {} - void operator()(Try&& t) { - SCOPE_EXIT { this->~LambdaBufHelper(); }; - func_(std::move(t)); - } - private: - F func_; - }; - /// Call only from Future thread. template - void setCallback(F func) { + void setCallback(F&& func) { bool transitionToArmed = false; auto setCallback_ = [&]{ context_ = RequestContext::saveContext(); - - // Move the lambda into the Core if it fits - if (sizeof(LambdaBufHelper) <= lambdaBufSize) { - auto funcLoc = reinterpret_cast*>(&lambdaBuf_); - new (funcLoc) LambdaBufHelper(std::forward(func)); - callback_ = std::ref(*funcLoc); - } else { - callback_ = std::move(func); - } + callback_ = std::forward(func); }; FSM_START(fsm_) @@ -327,31 +326,37 @@ class Core { executorLock_.unlock(); } + // keep Core alive until callback did its thing + ++attached_; + if (x) { - // keep Core alive until executor did its thing - ++attached_; try { if (LIKELY(x->getNumPriorities() == 1)) { x->add([this]() mutable { SCOPE_EXIT { detachOne(); }; - RequestContext::setContext(context_); + RequestContextScopeGuard rctx(context_); + SCOPE_EXIT { callback_ = {}; }; callback_(std::move(*result_)); }); } else { x->addWithPriority([this]() mutable { SCOPE_EXIT { detachOne(); }; - RequestContext::setContext(context_); + RequestContextScopeGuard rctx(context_); + SCOPE_EXIT { callback_ = {}; }; callback_(std::move(*result_)); }, priority); } } catch (...) { --attached_; // Account for extra ++attached_ before try - RequestContext::setContext(context_); + RequestContextScopeGuard rctx(context_); result_ = Try(exception_wrapper(std::current_exception())); + SCOPE_EXIT { callback_ = {}; }; callback_(std::move(*result_)); } } else { - RequestContext::setContext(context_); + SCOPE_EXIT { detachOne(); }; + RequestContextScopeGuard rctx(context_); + SCOPE_EXIT { callback_ = {}; }; callback_(std::move(*result_)); } } @@ -365,13 +370,14 @@ class Core { } } - // lambdaBuf occupies exactly one cache line - static constexpr size_t lambdaBufSize = 8 * sizeof(void*); - typename std::aligned_storage::type lambdaBuf_; + // Core should only be modified so that for size(T) == size(U), + // sizeof(Core) == size(Core). + // See Core::convert for details. + + folly::Function&&)> callback_; // place result_ next to increase the likelihood that the value will be // contained entirely in one cache line folly::Optional> result_; - std::function&&)> callback_ {nullptr}; FSM fsm_; std::atomic attached_; std::atomic active_ {true}; @@ -437,14 +443,14 @@ struct CollectVariadicContext { std::move(*std::get(o))); } - static std::tuple unwrap(std::tuple...>&& o, + static std::tuple unwrap(std::tuple...>&& /* o */, Ts&&... ts) { return std::tuple(std::forward(ts)...); } }; -template