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

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

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