cannam@149: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors cannam@149: // Licensed under the MIT License: cannam@149: // cannam@149: // Permission is hereby granted, free of charge, to any person obtaining a copy cannam@149: // of this software and associated documentation files (the "Software"), to deal cannam@149: // in the Software without restriction, including without limitation the rights cannam@149: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell cannam@149: // copies of the Software, and to permit persons to whom the Software is cannam@149: // furnished to do so, subject to the following conditions: cannam@149: // cannam@149: // The above copyright notice and this permission notice shall be included in cannam@149: // all copies or substantial portions of the Software. cannam@149: // cannam@149: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR cannam@149: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, cannam@149: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE cannam@149: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER cannam@149: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, cannam@149: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN cannam@149: // THE SOFTWARE. cannam@149: cannam@149: // This file contains extended inline implementation details that are required along with async.h. cannam@149: // We move this all into a separate file to make async.h more readable. cannam@149: // cannam@149: // Non-inline declarations here are defined in async.c++. cannam@149: cannam@149: #ifndef KJ_ASYNC_H_ cannam@149: #error "Do not include this directly; include kj/async.h." cannam@149: #include "async.h" // help IDE parse this file cannam@149: #endif cannam@149: cannam@149: #ifndef KJ_ASYNC_INL_H_ cannam@149: #define KJ_ASYNC_INL_H_ cannam@149: cannam@149: #if defined(__GNUC__) && !KJ_HEADER_WARNINGS cannam@149: #pragma GCC system_header cannam@149: #endif cannam@149: cannam@149: namespace kj { cannam@149: namespace _ { // private cannam@149: cannam@149: template cannam@149: class ExceptionOr; cannam@149: cannam@149: class ExceptionOrValue { cannam@149: public: cannam@149: ExceptionOrValue(bool, Exception&& exception): exception(kj::mv(exception)) {} cannam@149: KJ_DISALLOW_COPY(ExceptionOrValue); cannam@149: cannam@149: void addException(Exception&& exception) { cannam@149: if (this->exception == nullptr) { cannam@149: this->exception = kj::mv(exception); cannam@149: } cannam@149: } cannam@149: cannam@149: template cannam@149: ExceptionOr& as() { return *static_cast*>(this); } cannam@149: template cannam@149: const ExceptionOr& as() const { return *static_cast*>(this); } cannam@149: cannam@149: Maybe exception; cannam@149: cannam@149: protected: cannam@149: // Allow subclasses to have move constructor / assignment. cannam@149: ExceptionOrValue() = default; cannam@149: ExceptionOrValue(ExceptionOrValue&& other) = default; cannam@149: ExceptionOrValue& operator=(ExceptionOrValue&& other) = default; cannam@149: }; cannam@149: cannam@149: template cannam@149: class ExceptionOr: public ExceptionOrValue { cannam@149: public: cannam@149: ExceptionOr() = default; cannam@149: ExceptionOr(T&& value): value(kj::mv(value)) {} cannam@149: ExceptionOr(bool, Exception&& exception): ExceptionOrValue(false, kj::mv(exception)) {} cannam@149: ExceptionOr(ExceptionOr&&) = default; cannam@149: ExceptionOr& operator=(ExceptionOr&&) = default; cannam@149: cannam@149: Maybe value; cannam@149: }; cannam@149: cannam@149: class Event { cannam@149: // An event waiting to be executed. Not for direct use by applications -- promises use this cannam@149: // internally. cannam@149: cannam@149: public: cannam@149: Event(); cannam@149: ~Event() noexcept(false); cannam@149: KJ_DISALLOW_COPY(Event); cannam@149: cannam@149: void armDepthFirst(); cannam@149: // Enqueue this event so that `fire()` will be called from the event loop soon. cannam@149: // cannam@149: // Events scheduled in this way are executed in depth-first order: if an event callback arms cannam@149: // more events, those events are placed at the front of the queue (in the order in which they cannam@149: // were armed), so that they run immediately after the first event's callback returns. cannam@149: // cannam@149: // Depth-first event scheduling is appropriate for events that represent simple continuations cannam@149: // of a previous event that should be globbed together for performance. Depth-first scheduling cannam@149: // can lead to starvation, so any long-running task must occasionally yield with cannam@149: // `armBreadthFirst()`. (Promise::then() uses depth-first whereas evalLater() uses cannam@149: // breadth-first.) cannam@149: // cannam@149: // To use breadth-first scheduling instead, use `armBreadthFirst()`. cannam@149: cannam@149: void armBreadthFirst(); cannam@149: // Like `armDepthFirst()` except that the event is placed at the end of the queue. cannam@149: cannam@149: kj::String trace(); cannam@149: // Dump debug info about this event. cannam@149: cannam@149: virtual _::PromiseNode* getInnerForTrace(); cannam@149: // If this event wraps a PromiseNode, get that node. Used for debug tracing. cannam@149: // Default implementation returns nullptr. cannam@149: cannam@149: protected: cannam@149: virtual Maybe> fire() = 0; cannam@149: // Fire the event. Possibly returns a pointer to itself, which will be discarded by the cannam@149: // caller. This is the only way that an event can delete itself as a result of firing, as cannam@149: // doing so from within fire() will throw an exception. cannam@149: cannam@149: private: cannam@149: friend class kj::EventLoop; cannam@149: EventLoop& loop; cannam@149: Event* next; cannam@149: Event** prev; cannam@149: bool firing = false; cannam@149: }; cannam@149: cannam@149: class PromiseNode { cannam@149: // A Promise contains a chain of PromiseNodes tracking the pending transformations. cannam@149: // cannam@149: // To reduce generated code bloat, PromiseNode is not a template. Instead, it makes very hacky cannam@149: // use of pointers to ExceptionOrValue which actually point to ExceptionOr, but are only cannam@149: // so down-cast in the few places that really need to be templated. Luckily this is all cannam@149: // internal implementation details. cannam@149: cannam@149: public: cannam@149: virtual void onReady(Event& event) noexcept = 0; cannam@149: // Arms the given event when ready. cannam@149: cannam@149: virtual void setSelfPointer(Own* selfPtr) noexcept; cannam@149: // Tells the node that `selfPtr` is the pointer that owns this node, and will continue to own cannam@149: // this node until it is destroyed or setSelfPointer() is called again. ChainPromiseNode uses cannam@149: // this to shorten redundant chains. The default implementation does nothing; only cannam@149: // ChainPromiseNode should implement this. cannam@149: cannam@149: virtual void get(ExceptionOrValue& output) noexcept = 0; cannam@149: // Get the result. `output` points to an ExceptionOr into which the result will be written. cannam@149: // Can only be called once, and only after the node is ready. Must be called directly from the cannam@149: // event loop, with no application code on the stack. cannam@149: cannam@149: virtual PromiseNode* getInnerForTrace(); cannam@149: // If this node wraps some other PromiseNode, get the wrapped node. Used for debug tracing. cannam@149: // Default implementation returns nullptr. cannam@149: cannam@149: protected: cannam@149: class OnReadyEvent { cannam@149: // Helper class for implementing onReady(). cannam@149: cannam@149: public: cannam@149: void init(Event& newEvent); cannam@149: // Returns true if arm() was already called. cannam@149: cannam@149: void arm(); cannam@149: // Arms the event if init() has already been called and makes future calls to init() return cannam@149: // true. cannam@149: cannam@149: private: cannam@149: Event* event = nullptr; cannam@149: }; cannam@149: }; cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class ImmediatePromiseNodeBase: public PromiseNode { cannam@149: public: cannam@149: ImmediatePromiseNodeBase(); cannam@149: ~ImmediatePromiseNodeBase() noexcept(false); cannam@149: cannam@149: void onReady(Event& event) noexcept override; cannam@149: }; cannam@149: cannam@149: template cannam@149: class ImmediatePromiseNode final: public ImmediatePromiseNodeBase { cannam@149: // A promise that has already been resolved to an immediate value or exception. cannam@149: cannam@149: public: cannam@149: ImmediatePromiseNode(ExceptionOr&& result): result(kj::mv(result)) {} cannam@149: cannam@149: void get(ExceptionOrValue& output) noexcept override { cannam@149: output.as() = kj::mv(result); cannam@149: } cannam@149: cannam@149: private: cannam@149: ExceptionOr result; cannam@149: }; cannam@149: cannam@149: class ImmediateBrokenPromiseNode final: public ImmediatePromiseNodeBase { cannam@149: public: cannam@149: ImmediateBrokenPromiseNode(Exception&& exception); cannam@149: cannam@149: void get(ExceptionOrValue& output) noexcept override; cannam@149: cannam@149: private: cannam@149: Exception exception; cannam@149: }; cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class AttachmentPromiseNodeBase: public PromiseNode { cannam@149: public: cannam@149: AttachmentPromiseNodeBase(Own&& dependency); cannam@149: cannam@149: void onReady(Event& event) noexcept override; cannam@149: void get(ExceptionOrValue& output) noexcept override; cannam@149: PromiseNode* getInnerForTrace() override; cannam@149: cannam@149: private: cannam@149: Own dependency; cannam@149: cannam@149: void dropDependency(); cannam@149: cannam@149: template cannam@149: friend class AttachmentPromiseNode; cannam@149: }; cannam@149: cannam@149: template cannam@149: class AttachmentPromiseNode final: public AttachmentPromiseNodeBase { cannam@149: // A PromiseNode that holds on to some object (usually, an Own, but could be any movable cannam@149: // object) until the promise resolves. cannam@149: cannam@149: public: cannam@149: AttachmentPromiseNode(Own&& dependency, Attachment&& attachment) cannam@149: : AttachmentPromiseNodeBase(kj::mv(dependency)), cannam@149: attachment(kj::mv(attachment)) {} cannam@149: cannam@149: ~AttachmentPromiseNode() noexcept(false) { cannam@149: // We need to make sure the dependency is deleted before we delete the attachment because the cannam@149: // dependency may be using the attachment. cannam@149: dropDependency(); cannam@149: } cannam@149: cannam@149: private: cannam@149: Attachment attachment; cannam@149: }; cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class PtmfHelper { cannam@149: // This class is a private helper for GetFunctorStartAddress. The class represents the internal cannam@149: // representation of a pointer-to-member-function. cannam@149: cannam@149: template cannam@149: friend struct GetFunctorStartAddress; cannam@149: cannam@149: #if __GNUG__ cannam@149: cannam@149: void* ptr; cannam@149: ptrdiff_t adj; cannam@149: // Layout of a pointer-to-member-function used by GCC and compatible compilers. cannam@149: cannam@149: void* apply(void* obj) { cannam@149: #if defined(__arm__) || defined(__mips__) || defined(__aarch64__) cannam@149: if (adj & 1) { cannam@149: ptrdiff_t voff = (ptrdiff_t)ptr; cannam@149: #else cannam@149: ptrdiff_t voff = (ptrdiff_t)ptr; cannam@149: if (voff & 1) { cannam@149: voff &= ~1; cannam@149: #endif cannam@149: return *(void**)(*(char**)obj + voff); cannam@149: } else { cannam@149: return ptr; cannam@149: } cannam@149: } cannam@149: cannam@149: #define BODY \ cannam@149: PtmfHelper result; \ cannam@149: static_assert(sizeof(p) == sizeof(result), "unknown ptmf layout"); \ cannam@149: memcpy(&result, &p, sizeof(result)); \ cannam@149: return result cannam@149: cannam@149: #else // __GNUG__ cannam@149: cannam@149: void* apply(void* obj) { return nullptr; } cannam@149: // TODO(port): PTMF instruction address extraction cannam@149: cannam@149: #define BODY return PtmfHelper{} cannam@149: cannam@149: #endif // __GNUG__, else cannam@149: cannam@149: template cannam@149: static PtmfHelper from(F p) { BODY; } cannam@149: // Create a PtmfHelper from some arbitrary pointer-to-member-function which is not cannam@149: // overloaded nor a template. In this case the compiler is able to deduce the full function cannam@149: // signature directly given the name since there is only one function with that name. cannam@149: cannam@149: template cannam@149: static PtmfHelper from(R (C::*p)(NoInfer

...)) { BODY; } cannam@149: template cannam@149: static PtmfHelper from(R (C::*p)(NoInfer

...) const) { BODY; } cannam@149: // Create a PtmfHelper from some poniter-to-member-function which is a template. In this case cannam@149: // the function must match exactly the containing type C, return type R, and parameter types P... cannam@149: // GetFunctorStartAddress normally specifies exactly the correct C and R, but can only make a cannam@149: // guess at P. Luckily, if the function parameters are template parameters then it's not cannam@149: // necessary to be precise about P. cannam@149: #undef BODY cannam@149: }; cannam@149: cannam@149: template cannam@149: struct GetFunctorStartAddress { cannam@149: // Given a functor (any object defining operator()), return the start address of the function, cannam@149: // suitable for passing to addr2line to obtain a source file/line for debugging purposes. cannam@149: // cannam@149: // This turns out to be incredibly hard to implement in the presence of overloaded or templated cannam@149: // functors. Therefore, we impose these specific restrictions, specific to our use case: cannam@149: // - Overloading is not allowed, but templating is. (Generally we only intend to support lambdas cannam@149: // anyway.) cannam@149: // - The template parameters to GetFunctorStartAddress specify a hint as to the expected cannam@149: // parameter types. If the functor is templated, its parameters must match exactly these types. cannam@149: // (If it's not templated, ParamTypes are ignored.) cannam@149: cannam@149: template cannam@149: static void* apply(Func&& func) { cannam@149: typedef decltype(func(instance()...)) ReturnType; cannam@149: return PtmfHelper::from, ParamTypes...>( cannam@149: &Decay::operator()).apply(&func); cannam@149: } cannam@149: }; cannam@149: cannam@149: template <> cannam@149: struct GetFunctorStartAddress: public GetFunctorStartAddress<> {}; cannam@149: // Hack for TransformPromiseNode use case: an input type of `Void` indicates that the function cannam@149: // actually has no parameters. cannam@149: cannam@149: class TransformPromiseNodeBase: public PromiseNode { cannam@149: public: cannam@149: TransformPromiseNodeBase(Own&& dependency, void* continuationTracePtr); cannam@149: cannam@149: void onReady(Event& event) noexcept override; cannam@149: void get(ExceptionOrValue& output) noexcept override; cannam@149: PromiseNode* getInnerForTrace() override; cannam@149: cannam@149: private: cannam@149: Own dependency; cannam@149: void* continuationTracePtr; cannam@149: cannam@149: void dropDependency(); cannam@149: void getDepResult(ExceptionOrValue& output); cannam@149: cannam@149: virtual void getImpl(ExceptionOrValue& output) = 0; cannam@149: cannam@149: template cannam@149: friend class TransformPromiseNode; cannam@149: }; cannam@149: cannam@149: template cannam@149: class TransformPromiseNode final: public TransformPromiseNodeBase { cannam@149: // A PromiseNode that transforms the result of another PromiseNode through an application-provided cannam@149: // function (implements `then()`). cannam@149: cannam@149: public: cannam@149: TransformPromiseNode(Own&& dependency, Func&& func, ErrorFunc&& errorHandler) cannam@149: : TransformPromiseNodeBase(kj::mv(dependency), cannam@149: GetFunctorStartAddress::apply(func)), cannam@149: func(kj::fwd(func)), errorHandler(kj::fwd(errorHandler)) {} cannam@149: cannam@149: ~TransformPromiseNode() noexcept(false) { cannam@149: // We need to make sure the dependency is deleted before we delete the continuations because it cannam@149: // is a common pattern for the continuations to hold ownership of objects that might be in-use cannam@149: // by the dependency. cannam@149: dropDependency(); cannam@149: } cannam@149: cannam@149: private: cannam@149: Func func; cannam@149: ErrorFunc errorHandler; cannam@149: cannam@149: void getImpl(ExceptionOrValue& output) override { cannam@149: ExceptionOr depResult; cannam@149: getDepResult(depResult); cannam@149: KJ_IF_MAYBE(depException, depResult.exception) { cannam@149: output.as() = handle( cannam@149: MaybeVoidCaller>>::apply( cannam@149: errorHandler, kj::mv(*depException))); cannam@149: } else KJ_IF_MAYBE(depValue, depResult.value) { cannam@149: output.as() = handle(MaybeVoidCaller::apply(func, kj::mv(*depValue))); cannam@149: } cannam@149: } cannam@149: cannam@149: ExceptionOr handle(T&& value) { cannam@149: return kj::mv(value); cannam@149: } cannam@149: ExceptionOr handle(PropagateException::Bottom&& value) { cannam@149: return ExceptionOr(false, value.asException()); cannam@149: } cannam@149: }; cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class ForkHubBase; cannam@149: cannam@149: class ForkBranchBase: public PromiseNode { cannam@149: public: cannam@149: ForkBranchBase(Own&& hub); cannam@149: ~ForkBranchBase() noexcept(false); cannam@149: cannam@149: void hubReady() noexcept; cannam@149: // Called by the hub to indicate that it is ready. cannam@149: cannam@149: // implements PromiseNode ------------------------------------------ cannam@149: void onReady(Event& event) noexcept override; cannam@149: PromiseNode* getInnerForTrace() override; cannam@149: cannam@149: protected: cannam@149: inline ExceptionOrValue& getHubResultRef(); cannam@149: cannam@149: void releaseHub(ExceptionOrValue& output); cannam@149: // Release the hub. If an exception is thrown, add it to `output`. cannam@149: cannam@149: private: cannam@149: OnReadyEvent onReadyEvent; cannam@149: cannam@149: Own hub; cannam@149: ForkBranchBase* next = nullptr; cannam@149: ForkBranchBase** prevPtr = nullptr; cannam@149: cannam@149: friend class ForkHubBase; cannam@149: }; cannam@149: cannam@149: template T copyOrAddRef(T& t) { return t; } cannam@149: template Own copyOrAddRef(Own& t) { return t->addRef(); } cannam@149: cannam@149: template cannam@149: class ForkBranch final: public ForkBranchBase { cannam@149: // A PromiseNode that implements one branch of a fork -- i.e. one of the branches that receives cannam@149: // a const reference. cannam@149: cannam@149: public: cannam@149: ForkBranch(Own&& hub): ForkBranchBase(kj::mv(hub)) {} cannam@149: cannam@149: void get(ExceptionOrValue& output) noexcept override { cannam@149: ExceptionOr& hubResult = getHubResultRef().template as(); cannam@149: KJ_IF_MAYBE(value, hubResult.value) { cannam@149: output.as().value = copyOrAddRef(*value); cannam@149: } else { cannam@149: output.as().value = nullptr; cannam@149: } cannam@149: output.exception = hubResult.exception; cannam@149: releaseHub(output); cannam@149: } cannam@149: }; cannam@149: cannam@149: template cannam@149: class SplitBranch final: public ForkBranchBase { cannam@149: // A PromiseNode that implements one branch of a fork -- i.e. one of the branches that receives cannam@149: // a const reference. cannam@149: cannam@149: public: cannam@149: SplitBranch(Own&& hub): ForkBranchBase(kj::mv(hub)) {} cannam@149: cannam@149: typedef kj::Decay(kj::instance()))> Element; cannam@149: cannam@149: void get(ExceptionOrValue& output) noexcept override { cannam@149: ExceptionOr& hubResult = getHubResultRef().template as(); cannam@149: KJ_IF_MAYBE(value, hubResult.value) { cannam@149: output.as().value = kj::mv(kj::get(*value)); cannam@149: } else { cannam@149: output.as().value = nullptr; cannam@149: } cannam@149: output.exception = hubResult.exception; cannam@149: releaseHub(output); cannam@149: } cannam@149: }; cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class ForkHubBase: public Refcounted, protected Event { cannam@149: public: cannam@149: ForkHubBase(Own&& inner, ExceptionOrValue& resultRef); cannam@149: cannam@149: inline ExceptionOrValue& getResultRef() { return resultRef; } cannam@149: cannam@149: private: cannam@149: Own inner; cannam@149: ExceptionOrValue& resultRef; cannam@149: cannam@149: ForkBranchBase* headBranch = nullptr; cannam@149: ForkBranchBase** tailBranch = &headBranch; cannam@149: // Tail becomes null once the inner promise is ready and all branches have been notified. cannam@149: cannam@149: Maybe> fire() override; cannam@149: _::PromiseNode* getInnerForTrace() override; cannam@149: cannam@149: friend class ForkBranchBase; cannam@149: }; cannam@149: cannam@149: template cannam@149: class ForkHub final: public ForkHubBase { cannam@149: // A PromiseNode that implements the hub of a fork. The first call to Promise::fork() replaces cannam@149: // the promise's outer node with a ForkHub, and subsequent calls add branches to that hub (if cannam@149: // possible). cannam@149: cannam@149: public: cannam@149: ForkHub(Own&& inner): ForkHubBase(kj::mv(inner), result) {} cannam@149: cannam@149: Promise<_::UnfixVoid> addBranch() { cannam@149: return Promise<_::UnfixVoid>(false, kj::heap>(addRef(*this))); cannam@149: } cannam@149: cannam@149: _::SplitTuplePromise split() { cannam@149: return splitImpl(MakeIndexes()>()); cannam@149: } cannam@149: cannam@149: private: cannam@149: ExceptionOr result; cannam@149: cannam@149: template cannam@149: _::SplitTuplePromise splitImpl(Indexes) { cannam@149: return kj::tuple(addSplit()...); cannam@149: } cannam@149: cannam@149: template cannam@149: Promise::Element>> addSplit() { cannam@149: return Promise::Element>>( cannam@149: false, maybeChain(kj::heap>(addRef(*this)), cannam@149: implicitCast::Element*>(nullptr))); cannam@149: } cannam@149: }; cannam@149: cannam@149: inline ExceptionOrValue& ForkBranchBase::getHubResultRef() { cannam@149: return hub->getResultRef(); cannam@149: } cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class ChainPromiseNode final: public PromiseNode, public Event { cannam@149: // Promise node which reduces Promise> to Promise. cannam@149: // cannam@149: // `Event` is only a public base class because otherwise we can't cast Own to cannam@149: // Own. Ugh, templates and private... cannam@149: cannam@149: public: cannam@149: explicit ChainPromiseNode(Own inner); cannam@149: ~ChainPromiseNode() noexcept(false); cannam@149: cannam@149: void onReady(Event& event) noexcept override; cannam@149: void setSelfPointer(Own* selfPtr) noexcept override; cannam@149: void get(ExceptionOrValue& output) noexcept override; cannam@149: PromiseNode* getInnerForTrace() override; cannam@149: cannam@149: private: cannam@149: enum State { cannam@149: STEP1, cannam@149: STEP2 cannam@149: }; cannam@149: cannam@149: State state; cannam@149: cannam@149: Own inner; cannam@149: // In STEP1, a PromiseNode for a Promise. cannam@149: // In STEP2, a PromiseNode for a T. cannam@149: cannam@149: Event* onReadyEvent = nullptr; cannam@149: Own* selfPtr = nullptr; cannam@149: cannam@149: Maybe> fire() override; cannam@149: }; cannam@149: cannam@149: template cannam@149: Own maybeChain(Own&& node, Promise*) { cannam@149: return heap(kj::mv(node)); cannam@149: } cannam@149: cannam@149: template cannam@149: Own&& maybeChain(Own&& node, T*) { cannam@149: return kj::mv(node); cannam@149: } cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class ExclusiveJoinPromiseNode final: public PromiseNode { cannam@149: public: cannam@149: ExclusiveJoinPromiseNode(Own left, Own right); cannam@149: ~ExclusiveJoinPromiseNode() noexcept(false); cannam@149: cannam@149: void onReady(Event& event) noexcept override; cannam@149: void get(ExceptionOrValue& output) noexcept override; cannam@149: PromiseNode* getInnerForTrace() override; cannam@149: cannam@149: private: cannam@149: class Branch: public Event { cannam@149: public: cannam@149: Branch(ExclusiveJoinPromiseNode& joinNode, Own dependency); cannam@149: ~Branch() noexcept(false); cannam@149: cannam@149: bool get(ExceptionOrValue& output); cannam@149: // Returns true if this is the side that finished. cannam@149: cannam@149: Maybe> fire() override; cannam@149: _::PromiseNode* getInnerForTrace() override; cannam@149: cannam@149: private: cannam@149: ExclusiveJoinPromiseNode& joinNode; cannam@149: Own dependency; cannam@149: }; cannam@149: cannam@149: Branch left; cannam@149: Branch right; cannam@149: OnReadyEvent onReadyEvent; cannam@149: }; cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class ArrayJoinPromiseNodeBase: public PromiseNode { cannam@149: public: cannam@149: ArrayJoinPromiseNodeBase(Array> promises, cannam@149: ExceptionOrValue* resultParts, size_t partSize); cannam@149: ~ArrayJoinPromiseNodeBase() noexcept(false); cannam@149: cannam@149: void onReady(Event& event) noexcept override final; cannam@149: void get(ExceptionOrValue& output) noexcept override final; cannam@149: PromiseNode* getInnerForTrace() override final; cannam@149: cannam@149: protected: cannam@149: virtual void getNoError(ExceptionOrValue& output) noexcept = 0; cannam@149: // Called to compile the result only in the case where there were no errors. cannam@149: cannam@149: private: cannam@149: uint countLeft; cannam@149: OnReadyEvent onReadyEvent; cannam@149: cannam@149: class Branch final: public Event { cannam@149: public: cannam@149: Branch(ArrayJoinPromiseNodeBase& joinNode, Own dependency, cannam@149: ExceptionOrValue& output); cannam@149: ~Branch() noexcept(false); cannam@149: cannam@149: Maybe> fire() override; cannam@149: _::PromiseNode* getInnerForTrace() override; cannam@149: cannam@149: Maybe getPart(); cannam@149: // Calls dependency->get(output). If there was an exception, return it. cannam@149: cannam@149: private: cannam@149: ArrayJoinPromiseNodeBase& joinNode; cannam@149: Own dependency; cannam@149: ExceptionOrValue& output; cannam@149: }; cannam@149: cannam@149: Array branches; cannam@149: }; cannam@149: cannam@149: template cannam@149: class ArrayJoinPromiseNode final: public ArrayJoinPromiseNodeBase { cannam@149: public: cannam@149: ArrayJoinPromiseNode(Array> promises, cannam@149: Array> resultParts) cannam@149: : ArrayJoinPromiseNodeBase(kj::mv(promises), resultParts.begin(), sizeof(ExceptionOr)), cannam@149: resultParts(kj::mv(resultParts)) {} cannam@149: cannam@149: protected: cannam@149: void getNoError(ExceptionOrValue& output) noexcept override { cannam@149: auto builder = heapArrayBuilder(resultParts.size()); cannam@149: for (auto& part: resultParts) { cannam@149: KJ_IASSERT(part.value != nullptr, cannam@149: "Bug in KJ promise framework: Promise result had neither value no exception."); cannam@149: builder.add(kj::mv(*_::readMaybe(part.value))); cannam@149: } cannam@149: output.as>() = builder.finish(); cannam@149: } cannam@149: cannam@149: private: cannam@149: Array> resultParts; cannam@149: }; cannam@149: cannam@149: template <> cannam@149: class ArrayJoinPromiseNode final: public ArrayJoinPromiseNodeBase { cannam@149: public: cannam@149: ArrayJoinPromiseNode(Array> promises, cannam@149: Array> resultParts); cannam@149: ~ArrayJoinPromiseNode(); cannam@149: cannam@149: protected: cannam@149: void getNoError(ExceptionOrValue& output) noexcept override; cannam@149: cannam@149: private: cannam@149: Array> resultParts; cannam@149: }; cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class EagerPromiseNodeBase: public PromiseNode, protected Event { cannam@149: // A PromiseNode that eagerly evaluates its dependency even if its dependent does not eagerly cannam@149: // evaluate it. cannam@149: cannam@149: public: cannam@149: EagerPromiseNodeBase(Own&& dependency, ExceptionOrValue& resultRef); cannam@149: cannam@149: void onReady(Event& event) noexcept override; cannam@149: PromiseNode* getInnerForTrace() override; cannam@149: cannam@149: private: cannam@149: Own dependency; cannam@149: OnReadyEvent onReadyEvent; cannam@149: cannam@149: ExceptionOrValue& resultRef; cannam@149: cannam@149: Maybe> fire() override; cannam@149: }; cannam@149: cannam@149: template cannam@149: class EagerPromiseNode final: public EagerPromiseNodeBase { cannam@149: public: cannam@149: EagerPromiseNode(Own&& dependency) cannam@149: : EagerPromiseNodeBase(kj::mv(dependency), result) {} cannam@149: cannam@149: void get(ExceptionOrValue& output) noexcept override { cannam@149: output.as() = kj::mv(result); cannam@149: } cannam@149: cannam@149: private: cannam@149: ExceptionOr result; cannam@149: }; cannam@149: cannam@149: template cannam@149: Own spark(Own&& node) { cannam@149: // Forces evaluation of the given node to begin as soon as possible, even if no one is waiting cannam@149: // on it. cannam@149: return heap>(kj::mv(node)); cannam@149: } cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class AdapterPromiseNodeBase: public PromiseNode { cannam@149: public: cannam@149: void onReady(Event& event) noexcept override; cannam@149: cannam@149: protected: cannam@149: inline void setReady() { cannam@149: onReadyEvent.arm(); cannam@149: } cannam@149: cannam@149: private: cannam@149: OnReadyEvent onReadyEvent; cannam@149: }; cannam@149: cannam@149: template cannam@149: class AdapterPromiseNode final: public AdapterPromiseNodeBase, cannam@149: private PromiseFulfiller> { cannam@149: // A PromiseNode that wraps a PromiseAdapter. cannam@149: cannam@149: public: cannam@149: template cannam@149: AdapterPromiseNode(Params&&... params) cannam@149: : adapter(static_cast>&>(*this), kj::fwd(params)...) {} cannam@149: cannam@149: void get(ExceptionOrValue& output) noexcept override { cannam@149: KJ_IREQUIRE(!isWaiting()); cannam@149: output.as() = kj::mv(result); cannam@149: } cannam@149: cannam@149: private: cannam@149: ExceptionOr result; cannam@149: bool waiting = true; cannam@149: Adapter adapter; cannam@149: cannam@149: void fulfill(T&& value) override { cannam@149: if (waiting) { cannam@149: waiting = false; cannam@149: result = ExceptionOr(kj::mv(value)); cannam@149: setReady(); cannam@149: } cannam@149: } cannam@149: cannam@149: void reject(Exception&& exception) override { cannam@149: if (waiting) { cannam@149: waiting = false; cannam@149: result = ExceptionOr(false, kj::mv(exception)); cannam@149: setReady(); cannam@149: } cannam@149: } cannam@149: cannam@149: bool isWaiting() override { cannam@149: return waiting; cannam@149: } cannam@149: }; cannam@149: cannam@149: } // namespace _ (private) cannam@149: cannam@149: // ======================================================================================= cannam@149: cannam@149: template cannam@149: Promise::Promise(_::FixVoid value) cannam@149: : PromiseBase(heap<_::ImmediatePromiseNode<_::FixVoid>>(kj::mv(value))) {} cannam@149: cannam@149: template cannam@149: Promise::Promise(kj::Exception&& exception) cannam@149: : PromiseBase(heap<_::ImmediateBrokenPromiseNode>(kj::mv(exception))) {} cannam@149: cannam@149: template cannam@149: template cannam@149: PromiseForResult Promise::then(Func&& func, ErrorFunc&& errorHandler) { cannam@149: typedef _::FixVoid<_::ReturnType> ResultT; cannam@149: cannam@149: Own<_::PromiseNode> intermediate = cannam@149: heap<_::TransformPromiseNode, Func, ErrorFunc>>( cannam@149: kj::mv(node), kj::fwd(func), kj::fwd(errorHandler)); cannam@149: return PromiseForResult(false, cannam@149: _::maybeChain(kj::mv(intermediate), implicitCast(nullptr))); cannam@149: } cannam@149: cannam@149: namespace _ { // private cannam@149: cannam@149: template cannam@149: struct IdentityFunc { cannam@149: inline T operator()(T&& value) const { cannam@149: return kj::mv(value); cannam@149: } cannam@149: }; cannam@149: template cannam@149: struct IdentityFunc> { cannam@149: inline Promise operator()(T&& value) const { cannam@149: return kj::mv(value); cannam@149: } cannam@149: }; cannam@149: template <> cannam@149: struct IdentityFunc { cannam@149: inline void operator()() const {} cannam@149: }; cannam@149: template <> cannam@149: struct IdentityFunc> { cannam@149: Promise operator()() const; cannam@149: // This can't be inline because it will make the translation unit depend on kj-async. Awkwardly, cannam@149: // Cap'n Proto relies on being able to include this header without creating such a link-time cannam@149: // dependency. cannam@149: }; cannam@149: cannam@149: } // namespace _ (private) cannam@149: cannam@149: template cannam@149: template cannam@149: Promise Promise::catch_(ErrorFunc&& errorHandler) { cannam@149: // then()'s ErrorFunc can only return a Promise if Func also returns a Promise. In this case, cannam@149: // Func is being filled in automatically. We want to make sure ErrorFunc can return a Promise, cannam@149: // but we don't want the extra overhead of promise chaining if ErrorFunc doesn't actually cannam@149: // return a promise. So we make our Func return match ErrorFunc. cannam@149: return then(_::IdentityFunc()))>(), cannam@149: kj::fwd(errorHandler)); cannam@149: } cannam@149: cannam@149: template cannam@149: T Promise::wait(WaitScope& waitScope) { cannam@149: _::ExceptionOr<_::FixVoid> result; cannam@149: cannam@149: waitImpl(kj::mv(node), result, waitScope); cannam@149: cannam@149: KJ_IF_MAYBE(value, result.value) { cannam@149: KJ_IF_MAYBE(exception, result.exception) { cannam@149: throwRecoverableException(kj::mv(*exception)); cannam@149: } cannam@149: return _::returnMaybeVoid(kj::mv(*value)); cannam@149: } else KJ_IF_MAYBE(exception, result.exception) { cannam@149: throwFatalException(kj::mv(*exception)); cannam@149: } else { cannam@149: // Result contained neither a value nor an exception? cannam@149: KJ_UNREACHABLE; cannam@149: } cannam@149: } cannam@149: cannam@149: template <> cannam@149: inline void Promise::wait(WaitScope& waitScope) { cannam@149: // Override case to use throwRecoverableException(). cannam@149: cannam@149: _::ExceptionOr<_::Void> result; cannam@149: cannam@149: waitImpl(kj::mv(node), result, waitScope); cannam@149: cannam@149: if (result.value != nullptr) { cannam@149: KJ_IF_MAYBE(exception, result.exception) { cannam@149: throwRecoverableException(kj::mv(*exception)); cannam@149: } cannam@149: } else KJ_IF_MAYBE(exception, result.exception) { cannam@149: throwRecoverableException(kj::mv(*exception)); cannam@149: } else { cannam@149: // Result contained neither a value nor an exception? cannam@149: KJ_UNREACHABLE; cannam@149: } cannam@149: } cannam@149: cannam@149: template cannam@149: ForkedPromise Promise::fork() { cannam@149: return ForkedPromise(false, refcounted<_::ForkHub<_::FixVoid>>(kj::mv(node))); cannam@149: } cannam@149: cannam@149: template cannam@149: Promise ForkedPromise::addBranch() { cannam@149: return hub->addBranch(); cannam@149: } cannam@149: cannam@149: template cannam@149: _::SplitTuplePromise Promise::split() { cannam@149: return refcounted<_::ForkHub<_::FixVoid>>(kj::mv(node))->split(); cannam@149: } cannam@149: cannam@149: template cannam@149: Promise Promise::exclusiveJoin(Promise&& other) { cannam@149: return Promise(false, heap<_::ExclusiveJoinPromiseNode>(kj::mv(node), kj::mv(other.node))); cannam@149: } cannam@149: cannam@149: template cannam@149: template cannam@149: Promise Promise::attach(Attachments&&... attachments) { cannam@149: return Promise(false, kj::heap<_::AttachmentPromiseNode>>( cannam@149: kj::mv(node), kj::tuple(kj::fwd(attachments)...))); cannam@149: } cannam@149: cannam@149: template cannam@149: template cannam@149: Promise Promise::eagerlyEvaluate(ErrorFunc&& errorHandler) { cannam@149: // See catch_() for commentary. cannam@149: return Promise(false, _::spark<_::FixVoid>(then( cannam@149: _::IdentityFunc()))>(), cannam@149: kj::fwd(errorHandler)).node)); cannam@149: } cannam@149: cannam@149: template cannam@149: Promise Promise::eagerlyEvaluate(decltype(nullptr)) { cannam@149: return Promise(false, _::spark<_::FixVoid>(kj::mv(node))); cannam@149: } cannam@149: cannam@149: template cannam@149: kj::String Promise::trace() { cannam@149: return PromiseBase::trace(); cannam@149: } cannam@149: cannam@149: template cannam@149: inline PromiseForResult evalLater(Func&& func) { cannam@149: return _::yield().then(kj::fwd(func), _::PropagateException()); cannam@149: } cannam@149: cannam@149: template cannam@149: inline PromiseForResult evalNow(Func&& func) { cannam@149: PromiseForResult result = nullptr; cannam@149: KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() { cannam@149: result = func(); cannam@149: })) { cannam@149: result = kj::mv(*e); cannam@149: } cannam@149: return result; cannam@149: } cannam@149: cannam@149: template cannam@149: template cannam@149: void Promise::detach(ErrorFunc&& errorHandler) { cannam@149: return _::detach(then([](T&&) {}, kj::fwd(errorHandler))); cannam@149: } cannam@149: cannam@149: template <> cannam@149: template cannam@149: void Promise::detach(ErrorFunc&& errorHandler) { cannam@149: return _::detach(then([]() {}, kj::fwd(errorHandler))); cannam@149: } cannam@149: cannam@149: template cannam@149: Promise> joinPromises(Array>&& promises) { cannam@149: return Promise>(false, kj::heap<_::ArrayJoinPromiseNode>( cannam@149: KJ_MAP(p, promises) { return kj::mv(p.node); }, cannam@149: heapArray<_::ExceptionOr>(promises.size()))); cannam@149: } cannam@149: cannam@149: // ======================================================================================= cannam@149: cannam@149: namespace _ { // private cannam@149: cannam@149: template cannam@149: class WeakFulfiller final: public PromiseFulfiller, private kj::Disposer { cannam@149: // A wrapper around PromiseFulfiller which can be detached. cannam@149: // cannam@149: // There are a couple non-trivialities here: cannam@149: // - If the WeakFulfiller is discarded, we want the promise it fulfills to be implicitly cannam@149: // rejected. cannam@149: // - We cannot destroy the WeakFulfiller until the application has discarded it *and* it has been cannam@149: // detached from the underlying fulfiller, because otherwise the later detach() call will go cannam@149: // to a dangling pointer. Essentially, WeakFulfiller is reference counted, although the cannam@149: // refcount never goes over 2 and we manually implement the refcounting because we need to do cannam@149: // other special things when each side detaches anyway. To this end, WeakFulfiller is its own cannam@149: // Disposer -- dispose() is called when the application discards its owned pointer to the cannam@149: // fulfiller and detach() is called when the promise is destroyed. cannam@149: cannam@149: public: cannam@149: KJ_DISALLOW_COPY(WeakFulfiller); cannam@149: cannam@149: static kj::Own make() { cannam@149: WeakFulfiller* ptr = new WeakFulfiller; cannam@149: return Own(ptr, *ptr); cannam@149: } cannam@149: cannam@149: void fulfill(FixVoid&& value) override { cannam@149: if (inner != nullptr) { cannam@149: inner->fulfill(kj::mv(value)); cannam@149: } cannam@149: } cannam@149: cannam@149: void reject(Exception&& exception) override { cannam@149: if (inner != nullptr) { cannam@149: inner->reject(kj::mv(exception)); cannam@149: } cannam@149: } cannam@149: cannam@149: bool isWaiting() override { cannam@149: return inner != nullptr && inner->isWaiting(); cannam@149: } cannam@149: cannam@149: void attach(PromiseFulfiller& newInner) { cannam@149: inner = &newInner; cannam@149: } cannam@149: cannam@149: void detach(PromiseFulfiller& from) { cannam@149: if (inner == nullptr) { cannam@149: // Already disposed. cannam@149: delete this; cannam@149: } else { cannam@149: KJ_IREQUIRE(inner == &from); cannam@149: inner = nullptr; cannam@149: } cannam@149: } cannam@149: cannam@149: private: cannam@149: mutable PromiseFulfiller* inner; cannam@149: cannam@149: WeakFulfiller(): inner(nullptr) {} cannam@149: cannam@149: void disposeImpl(void* pointer) const override { cannam@149: // TODO(perf): Factor some of this out so it isn't regenerated for every fulfiller type? cannam@149: cannam@149: if (inner == nullptr) { cannam@149: // Already detached. cannam@149: delete this; cannam@149: } else { cannam@149: if (inner->isWaiting()) { cannam@149: inner->reject(kj::Exception(kj::Exception::Type::FAILED, __FILE__, __LINE__, cannam@149: kj::heapString("PromiseFulfiller was destroyed without fulfilling the promise."))); cannam@149: } cannam@149: inner = nullptr; cannam@149: } cannam@149: } cannam@149: }; cannam@149: cannam@149: template cannam@149: class PromiseAndFulfillerAdapter { cannam@149: public: cannam@149: PromiseAndFulfillerAdapter(PromiseFulfiller& fulfiller, cannam@149: WeakFulfiller& wrapper) cannam@149: : fulfiller(fulfiller), wrapper(wrapper) { cannam@149: wrapper.attach(fulfiller); cannam@149: } cannam@149: cannam@149: ~PromiseAndFulfillerAdapter() noexcept(false) { cannam@149: wrapper.detach(fulfiller); cannam@149: } cannam@149: cannam@149: private: cannam@149: PromiseFulfiller& fulfiller; cannam@149: WeakFulfiller& wrapper; cannam@149: }; cannam@149: cannam@149: } // namespace _ (private) cannam@149: cannam@149: template cannam@149: template cannam@149: bool PromiseFulfiller::rejectIfThrows(Func&& func) { cannam@149: KJ_IF_MAYBE(exception, kj::runCatchingExceptions(kj::mv(func))) { cannam@149: reject(kj::mv(*exception)); cannam@149: return false; cannam@149: } else { cannam@149: return true; cannam@149: } cannam@149: } cannam@149: cannam@149: template cannam@149: bool PromiseFulfiller::rejectIfThrows(Func&& func) { cannam@149: KJ_IF_MAYBE(exception, kj::runCatchingExceptions(kj::mv(func))) { cannam@149: reject(kj::mv(*exception)); cannam@149: return false; cannam@149: } else { cannam@149: return true; cannam@149: } cannam@149: } cannam@149: cannam@149: template cannam@149: Promise newAdaptedPromise(Params&&... adapterConstructorParams) { cannam@149: return Promise(false, heap<_::AdapterPromiseNode<_::FixVoid, Adapter>>( cannam@149: kj::fwd(adapterConstructorParams)...)); cannam@149: } cannam@149: cannam@149: template cannam@149: PromiseFulfillerPair newPromiseAndFulfiller() { cannam@149: auto wrapper = _::WeakFulfiller::make(); cannam@149: cannam@149: Own<_::PromiseNode> intermediate( cannam@149: heap<_::AdapterPromiseNode<_::FixVoid, _::PromiseAndFulfillerAdapter>>(*wrapper)); cannam@149: Promise<_::JoinPromises> promise(false, cannam@149: _::maybeChain(kj::mv(intermediate), implicitCast(nullptr))); cannam@149: cannam@149: return PromiseFulfillerPair { kj::mv(promise), kj::mv(wrapper) }; cannam@149: } cannam@149: cannam@149: } // namespace kj cannam@149: cannam@149: #endif // KJ_ASYNC_INL_H_