annotate win32-mingw/include/kj/async-inl.h @ 50:37d53a7e8262

Headers for KJ/Capnp Win32
author Chris Cannam
date Wed, 26 Oct 2016 13:18:45 +0100
parents
children eccd51b72864
rev   line source
Chris@50 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
Chris@50 2 // Licensed under the MIT License:
Chris@50 3 //
Chris@50 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
Chris@50 5 // of this software and associated documentation files (the "Software"), to deal
Chris@50 6 // in the Software without restriction, including without limitation the rights
Chris@50 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Chris@50 8 // copies of the Software, and to permit persons to whom the Software is
Chris@50 9 // furnished to do so, subject to the following conditions:
Chris@50 10 //
Chris@50 11 // The above copyright notice and this permission notice shall be included in
Chris@50 12 // all copies or substantial portions of the Software.
Chris@50 13 //
Chris@50 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Chris@50 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Chris@50 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Chris@50 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Chris@50 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Chris@50 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Chris@50 20 // THE SOFTWARE.
Chris@50 21
Chris@50 22 // This file contains extended inline implementation details that are required along with async.h.
Chris@50 23 // We move this all into a separate file to make async.h more readable.
Chris@50 24 //
Chris@50 25 // Non-inline declarations here are defined in async.c++.
Chris@50 26
Chris@50 27 #ifndef KJ_ASYNC_H_
Chris@50 28 #error "Do not include this directly; include kj/async.h."
Chris@50 29 #include "async.h" // help IDE parse this file
Chris@50 30 #endif
Chris@50 31
Chris@50 32 #ifndef KJ_ASYNC_INL_H_
Chris@50 33 #define KJ_ASYNC_INL_H_
Chris@50 34
Chris@50 35 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS
Chris@50 36 #pragma GCC system_header
Chris@50 37 #endif
Chris@50 38
Chris@50 39 namespace kj {
Chris@50 40 namespace _ { // private
Chris@50 41
Chris@50 42 template <typename T>
Chris@50 43 class ExceptionOr;
Chris@50 44
Chris@50 45 class ExceptionOrValue {
Chris@50 46 public:
Chris@50 47 ExceptionOrValue(bool, Exception&& exception): exception(kj::mv(exception)) {}
Chris@50 48 KJ_DISALLOW_COPY(ExceptionOrValue);
Chris@50 49
Chris@50 50 void addException(Exception&& exception) {
Chris@50 51 if (this->exception == nullptr) {
Chris@50 52 this->exception = kj::mv(exception);
Chris@50 53 }
Chris@50 54 }
Chris@50 55
Chris@50 56 template <typename T>
Chris@50 57 ExceptionOr<T>& as() { return *static_cast<ExceptionOr<T>*>(this); }
Chris@50 58 template <typename T>
Chris@50 59 const ExceptionOr<T>& as() const { return *static_cast<const ExceptionOr<T>*>(this); }
Chris@50 60
Chris@50 61 Maybe<Exception> exception;
Chris@50 62
Chris@50 63 protected:
Chris@50 64 // Allow subclasses to have move constructor / assignment.
Chris@50 65 ExceptionOrValue() = default;
Chris@50 66 ExceptionOrValue(ExceptionOrValue&& other) = default;
Chris@50 67 ExceptionOrValue& operator=(ExceptionOrValue&& other) = default;
Chris@50 68 };
Chris@50 69
Chris@50 70 template <typename T>
Chris@50 71 class ExceptionOr: public ExceptionOrValue {
Chris@50 72 public:
Chris@50 73 ExceptionOr() = default;
Chris@50 74 ExceptionOr(T&& value): value(kj::mv(value)) {}
Chris@50 75 ExceptionOr(bool, Exception&& exception): ExceptionOrValue(false, kj::mv(exception)) {}
Chris@50 76 ExceptionOr(ExceptionOr&&) = default;
Chris@50 77 ExceptionOr& operator=(ExceptionOr&&) = default;
Chris@50 78
Chris@50 79 Maybe<T> value;
Chris@50 80 };
Chris@50 81
Chris@50 82 class Event {
Chris@50 83 // An event waiting to be executed. Not for direct use by applications -- promises use this
Chris@50 84 // internally.
Chris@50 85
Chris@50 86 public:
Chris@50 87 Event();
Chris@50 88 ~Event() noexcept(false);
Chris@50 89 KJ_DISALLOW_COPY(Event);
Chris@50 90
Chris@50 91 void armDepthFirst();
Chris@50 92 // Enqueue this event so that `fire()` will be called from the event loop soon.
Chris@50 93 //
Chris@50 94 // Events scheduled in this way are executed in depth-first order: if an event callback arms
Chris@50 95 // more events, those events are placed at the front of the queue (in the order in which they
Chris@50 96 // were armed), so that they run immediately after the first event's callback returns.
Chris@50 97 //
Chris@50 98 // Depth-first event scheduling is appropriate for events that represent simple continuations
Chris@50 99 // of a previous event that should be globbed together for performance. Depth-first scheduling
Chris@50 100 // can lead to starvation, so any long-running task must occasionally yield with
Chris@50 101 // `armBreadthFirst()`. (Promise::then() uses depth-first whereas evalLater() uses
Chris@50 102 // breadth-first.)
Chris@50 103 //
Chris@50 104 // To use breadth-first scheduling instead, use `armBreadthFirst()`.
Chris@50 105
Chris@50 106 void armBreadthFirst();
Chris@50 107 // Like `armDepthFirst()` except that the event is placed at the end of the queue.
Chris@50 108
Chris@50 109 kj::String trace();
Chris@50 110 // Dump debug info about this event.
Chris@50 111
Chris@50 112 virtual _::PromiseNode* getInnerForTrace();
Chris@50 113 // If this event wraps a PromiseNode, get that node. Used for debug tracing.
Chris@50 114 // Default implementation returns nullptr.
Chris@50 115
Chris@50 116 protected:
Chris@50 117 virtual Maybe<Own<Event>> fire() = 0;
Chris@50 118 // Fire the event. Possibly returns a pointer to itself, which will be discarded by the
Chris@50 119 // caller. This is the only way that an event can delete itself as a result of firing, as
Chris@50 120 // doing so from within fire() will throw an exception.
Chris@50 121
Chris@50 122 private:
Chris@50 123 friend class kj::EventLoop;
Chris@50 124 EventLoop& loop;
Chris@50 125 Event* next;
Chris@50 126 Event** prev;
Chris@50 127 bool firing = false;
Chris@50 128 };
Chris@50 129
Chris@50 130 class PromiseNode {
Chris@50 131 // A Promise<T> contains a chain of PromiseNodes tracking the pending transformations.
Chris@50 132 //
Chris@50 133 // To reduce generated code bloat, PromiseNode is not a template. Instead, it makes very hacky
Chris@50 134 // use of pointers to ExceptionOrValue which actually point to ExceptionOr<T>, but are only
Chris@50 135 // so down-cast in the few places that really need to be templated. Luckily this is all
Chris@50 136 // internal implementation details.
Chris@50 137
Chris@50 138 public:
Chris@50 139 virtual void onReady(Event& event) noexcept = 0;
Chris@50 140 // Arms the given event when ready.
Chris@50 141
Chris@50 142 virtual void setSelfPointer(Own<PromiseNode>* selfPtr) noexcept;
Chris@50 143 // Tells the node that `selfPtr` is the pointer that owns this node, and will continue to own
Chris@50 144 // this node until it is destroyed or setSelfPointer() is called again. ChainPromiseNode uses
Chris@50 145 // this to shorten redundant chains. The default implementation does nothing; only
Chris@50 146 // ChainPromiseNode should implement this.
Chris@50 147
Chris@50 148 virtual void get(ExceptionOrValue& output) noexcept = 0;
Chris@50 149 // Get the result. `output` points to an ExceptionOr<T> into which the result will be written.
Chris@50 150 // Can only be called once, and only after the node is ready. Must be called directly from the
Chris@50 151 // event loop, with no application code on the stack.
Chris@50 152
Chris@50 153 virtual PromiseNode* getInnerForTrace();
Chris@50 154 // If this node wraps some other PromiseNode, get the wrapped node. Used for debug tracing.
Chris@50 155 // Default implementation returns nullptr.
Chris@50 156
Chris@50 157 protected:
Chris@50 158 class OnReadyEvent {
Chris@50 159 // Helper class for implementing onReady().
Chris@50 160
Chris@50 161 public:
Chris@50 162 void init(Event& newEvent);
Chris@50 163 // Returns true if arm() was already called.
Chris@50 164
Chris@50 165 void arm();
Chris@50 166 // Arms the event if init() has already been called and makes future calls to init() return
Chris@50 167 // true.
Chris@50 168
Chris@50 169 private:
Chris@50 170 Event* event = nullptr;
Chris@50 171 };
Chris@50 172 };
Chris@50 173
Chris@50 174 // -------------------------------------------------------------------
Chris@50 175
Chris@50 176 class ImmediatePromiseNodeBase: public PromiseNode {
Chris@50 177 public:
Chris@50 178 ImmediatePromiseNodeBase();
Chris@50 179 ~ImmediatePromiseNodeBase() noexcept(false);
Chris@50 180
Chris@50 181 void onReady(Event& event) noexcept override;
Chris@50 182 };
Chris@50 183
Chris@50 184 template <typename T>
Chris@50 185 class ImmediatePromiseNode final: public ImmediatePromiseNodeBase {
Chris@50 186 // A promise that has already been resolved to an immediate value or exception.
Chris@50 187
Chris@50 188 public:
Chris@50 189 ImmediatePromiseNode(ExceptionOr<T>&& result): result(kj::mv(result)) {}
Chris@50 190
Chris@50 191 void get(ExceptionOrValue& output) noexcept override {
Chris@50 192 output.as<T>() = kj::mv(result);
Chris@50 193 }
Chris@50 194
Chris@50 195 private:
Chris@50 196 ExceptionOr<T> result;
Chris@50 197 };
Chris@50 198
Chris@50 199 class ImmediateBrokenPromiseNode final: public ImmediatePromiseNodeBase {
Chris@50 200 public:
Chris@50 201 ImmediateBrokenPromiseNode(Exception&& exception);
Chris@50 202
Chris@50 203 void get(ExceptionOrValue& output) noexcept override;
Chris@50 204
Chris@50 205 private:
Chris@50 206 Exception exception;
Chris@50 207 };
Chris@50 208
Chris@50 209 // -------------------------------------------------------------------
Chris@50 210
Chris@50 211 class AttachmentPromiseNodeBase: public PromiseNode {
Chris@50 212 public:
Chris@50 213 AttachmentPromiseNodeBase(Own<PromiseNode>&& dependency);
Chris@50 214
Chris@50 215 void onReady(Event& event) noexcept override;
Chris@50 216 void get(ExceptionOrValue& output) noexcept override;
Chris@50 217 PromiseNode* getInnerForTrace() override;
Chris@50 218
Chris@50 219 private:
Chris@50 220 Own<PromiseNode> dependency;
Chris@50 221
Chris@50 222 void dropDependency();
Chris@50 223
Chris@50 224 template <typename>
Chris@50 225 friend class AttachmentPromiseNode;
Chris@50 226 };
Chris@50 227
Chris@50 228 template <typename Attachment>
Chris@50 229 class AttachmentPromiseNode final: public AttachmentPromiseNodeBase {
Chris@50 230 // A PromiseNode that holds on to some object (usually, an Own<T>, but could be any movable
Chris@50 231 // object) until the promise resolves.
Chris@50 232
Chris@50 233 public:
Chris@50 234 AttachmentPromiseNode(Own<PromiseNode>&& dependency, Attachment&& attachment)
Chris@50 235 : AttachmentPromiseNodeBase(kj::mv(dependency)),
Chris@50 236 attachment(kj::mv<Attachment>(attachment)) {}
Chris@50 237
Chris@50 238 ~AttachmentPromiseNode() noexcept(false) {
Chris@50 239 // We need to make sure the dependency is deleted before we delete the attachment because the
Chris@50 240 // dependency may be using the attachment.
Chris@50 241 dropDependency();
Chris@50 242 }
Chris@50 243
Chris@50 244 private:
Chris@50 245 Attachment attachment;
Chris@50 246 };
Chris@50 247
Chris@50 248 // -------------------------------------------------------------------
Chris@50 249
Chris@50 250 class PtmfHelper {
Chris@50 251 // This class is a private helper for GetFunctorStartAddress. The class represents the internal
Chris@50 252 // representation of a pointer-to-member-function.
Chris@50 253
Chris@50 254 template <typename... ParamTypes>
Chris@50 255 friend struct GetFunctorStartAddress;
Chris@50 256
Chris@50 257 #if __GNUG__
Chris@50 258 void* ptr;
Chris@50 259 ptrdiff_t adj;
Chris@50 260 // Layout of a pointer-to-member-function used by GCC and compatible compilers.
Chris@50 261 #else
Chris@50 262 #error "TODO(port): PTMF instruction address extraction"
Chris@50 263 #endif
Chris@50 264
Chris@50 265 #define BODY \
Chris@50 266 PtmfHelper result; \
Chris@50 267 static_assert(sizeof(p) == sizeof(result), "unknown ptmf layout"); \
Chris@50 268 memcpy(&result, &p, sizeof(result)); \
Chris@50 269 return result
Chris@50 270
Chris@50 271 template <typename R, typename C, typename... P, typename F>
Chris@50 272 static PtmfHelper from(F p) { BODY; }
Chris@50 273 // Create a PtmfHelper from some arbitrary pointer-to-member-function which is not
Chris@50 274 // overloaded nor a template. In this case the compiler is able to deduce the full function
Chris@50 275 // signature directly given the name since there is only one function with that name.
Chris@50 276
Chris@50 277 template <typename R, typename C, typename... P>
Chris@50 278 static PtmfHelper from(R (C::*p)(NoInfer<P>...)) { BODY; }
Chris@50 279 template <typename R, typename C, typename... P>
Chris@50 280 static PtmfHelper from(R (C::*p)(NoInfer<P>...) const) { BODY; }
Chris@50 281 // Create a PtmfHelper from some poniter-to-member-function which is a template. In this case
Chris@50 282 // the function must match exactly the containing type C, return type R, and parameter types P...
Chris@50 283 // GetFunctorStartAddress normally specifies exactly the correct C and R, but can only make a
Chris@50 284 // guess at P. Luckily, if the function parameters are template parameters then it's not
Chris@50 285 // necessary to be precise about P.
Chris@50 286 #undef BODY
Chris@50 287
Chris@50 288 void* apply(void* obj) {
Chris@50 289 #if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
Chris@50 290 if (adj & 1) {
Chris@50 291 ptrdiff_t voff = (ptrdiff_t)ptr;
Chris@50 292 #else
Chris@50 293 ptrdiff_t voff = (ptrdiff_t)ptr;
Chris@50 294 if (voff & 1) {
Chris@50 295 voff &= ~1;
Chris@50 296 #endif
Chris@50 297 return *(void**)(*(char**)obj + voff);
Chris@50 298 } else {
Chris@50 299 return ptr;
Chris@50 300 }
Chris@50 301 }
Chris@50 302 };
Chris@50 303
Chris@50 304 template <typename... ParamTypes>
Chris@50 305 struct GetFunctorStartAddress {
Chris@50 306 // Given a functor (any object defining operator()), return the start address of the function,
Chris@50 307 // suitable for passing to addr2line to obtain a source file/line for debugging purposes.
Chris@50 308 //
Chris@50 309 // This turns out to be incredibly hard to implement in the presence of overloaded or templated
Chris@50 310 // functors. Therefore, we impose these specific restrictions, specific to our use case:
Chris@50 311 // - Overloading is not allowed, but templating is. (Generally we only intend to support lambdas
Chris@50 312 // anyway.)
Chris@50 313 // - The template parameters to GetFunctorStartAddress specify a hint as to the expected
Chris@50 314 // parameter types. If the functor is templated, its parameters must match exactly these types.
Chris@50 315 // (If it's not templated, ParamTypes are ignored.)
Chris@50 316
Chris@50 317 template <typename Func>
Chris@50 318 static void* apply(Func&& func) {
Chris@50 319 typedef decltype(func(instance<ParamTypes>()...)) ReturnType;
Chris@50 320 return PtmfHelper::from<ReturnType, Decay<Func>, ParamTypes...>(
Chris@50 321 &Decay<Func>::operator()).apply(&func);
Chris@50 322 }
Chris@50 323 };
Chris@50 324
Chris@50 325 template <>
Chris@50 326 struct GetFunctorStartAddress<Void&&>: public GetFunctorStartAddress<> {};
Chris@50 327 // Hack for TransformPromiseNode use case: an input type of `Void` indicates that the function
Chris@50 328 // actually has no parameters.
Chris@50 329
Chris@50 330 class TransformPromiseNodeBase: public PromiseNode {
Chris@50 331 public:
Chris@50 332 TransformPromiseNodeBase(Own<PromiseNode>&& dependency, void* continuationTracePtr);
Chris@50 333
Chris@50 334 void onReady(Event& event) noexcept override;
Chris@50 335 void get(ExceptionOrValue& output) noexcept override;
Chris@50 336 PromiseNode* getInnerForTrace() override;
Chris@50 337
Chris@50 338 private:
Chris@50 339 Own<PromiseNode> dependency;
Chris@50 340 void* continuationTracePtr;
Chris@50 341
Chris@50 342 void dropDependency();
Chris@50 343 void getDepResult(ExceptionOrValue& output);
Chris@50 344
Chris@50 345 virtual void getImpl(ExceptionOrValue& output) = 0;
Chris@50 346
Chris@50 347 template <typename, typename, typename, typename>
Chris@50 348 friend class TransformPromiseNode;
Chris@50 349 };
Chris@50 350
Chris@50 351 template <typename T, typename DepT, typename Func, typename ErrorFunc>
Chris@50 352 class TransformPromiseNode final: public TransformPromiseNodeBase {
Chris@50 353 // A PromiseNode that transforms the result of another PromiseNode through an application-provided
Chris@50 354 // function (implements `then()`).
Chris@50 355
Chris@50 356 public:
Chris@50 357 TransformPromiseNode(Own<PromiseNode>&& dependency, Func&& func, ErrorFunc&& errorHandler)
Chris@50 358 : TransformPromiseNodeBase(kj::mv(dependency),
Chris@50 359 GetFunctorStartAddress<DepT&&>::apply(func)),
Chris@50 360 func(kj::fwd<Func>(func)), errorHandler(kj::fwd<ErrorFunc>(errorHandler)) {}
Chris@50 361
Chris@50 362 ~TransformPromiseNode() noexcept(false) {
Chris@50 363 // We need to make sure the dependency is deleted before we delete the continuations because it
Chris@50 364 // is a common pattern for the continuations to hold ownership of objects that might be in-use
Chris@50 365 // by the dependency.
Chris@50 366 dropDependency();
Chris@50 367 }
Chris@50 368
Chris@50 369 private:
Chris@50 370 Func func;
Chris@50 371 ErrorFunc errorHandler;
Chris@50 372
Chris@50 373 void getImpl(ExceptionOrValue& output) override {
Chris@50 374 ExceptionOr<DepT> depResult;
Chris@50 375 getDepResult(depResult);
Chris@50 376 KJ_IF_MAYBE(depException, depResult.exception) {
Chris@50 377 output.as<T>() = handle(
Chris@50 378 MaybeVoidCaller<Exception, FixVoid<ReturnType<ErrorFunc, Exception>>>::apply(
Chris@50 379 errorHandler, kj::mv(*depException)));
Chris@50 380 } else KJ_IF_MAYBE(depValue, depResult.value) {
Chris@50 381 output.as<T>() = handle(MaybeVoidCaller<DepT, T>::apply(func, kj::mv(*depValue)));
Chris@50 382 }
Chris@50 383 }
Chris@50 384
Chris@50 385 ExceptionOr<T> handle(T&& value) {
Chris@50 386 return kj::mv(value);
Chris@50 387 }
Chris@50 388 ExceptionOr<T> handle(PropagateException::Bottom&& value) {
Chris@50 389 return ExceptionOr<T>(false, value.asException());
Chris@50 390 }
Chris@50 391 };
Chris@50 392
Chris@50 393 // -------------------------------------------------------------------
Chris@50 394
Chris@50 395 class ForkHubBase;
Chris@50 396
Chris@50 397 class ForkBranchBase: public PromiseNode {
Chris@50 398 public:
Chris@50 399 ForkBranchBase(Own<ForkHubBase>&& hub);
Chris@50 400 ~ForkBranchBase() noexcept(false);
Chris@50 401
Chris@50 402 void hubReady() noexcept;
Chris@50 403 // Called by the hub to indicate that it is ready.
Chris@50 404
Chris@50 405 // implements PromiseNode ------------------------------------------
Chris@50 406 void onReady(Event& event) noexcept override;
Chris@50 407 PromiseNode* getInnerForTrace() override;
Chris@50 408
Chris@50 409 protected:
Chris@50 410 inline ExceptionOrValue& getHubResultRef();
Chris@50 411
Chris@50 412 void releaseHub(ExceptionOrValue& output);
Chris@50 413 // Release the hub. If an exception is thrown, add it to `output`.
Chris@50 414
Chris@50 415 private:
Chris@50 416 OnReadyEvent onReadyEvent;
Chris@50 417
Chris@50 418 Own<ForkHubBase> hub;
Chris@50 419 ForkBranchBase* next = nullptr;
Chris@50 420 ForkBranchBase** prevPtr = nullptr;
Chris@50 421
Chris@50 422 friend class ForkHubBase;
Chris@50 423 };
Chris@50 424
Chris@50 425 template <typename T> T copyOrAddRef(T& t) { return t; }
Chris@50 426 template <typename T> Own<T> copyOrAddRef(Own<T>& t) { return t->addRef(); }
Chris@50 427
Chris@50 428 template <typename T>
Chris@50 429 class ForkBranch final: public ForkBranchBase {
Chris@50 430 // A PromiseNode that implements one branch of a fork -- i.e. one of the branches that receives
Chris@50 431 // a const reference.
Chris@50 432
Chris@50 433 public:
Chris@50 434 ForkBranch(Own<ForkHubBase>&& hub): ForkBranchBase(kj::mv(hub)) {}
Chris@50 435
Chris@50 436 void get(ExceptionOrValue& output) noexcept override {
Chris@50 437 ExceptionOr<T>& hubResult = getHubResultRef().template as<T>();
Chris@50 438 KJ_IF_MAYBE(value, hubResult.value) {
Chris@50 439 output.as<T>().value = copyOrAddRef(*value);
Chris@50 440 } else {
Chris@50 441 output.as<T>().value = nullptr;
Chris@50 442 }
Chris@50 443 output.exception = hubResult.exception;
Chris@50 444 releaseHub(output);
Chris@50 445 }
Chris@50 446 };
Chris@50 447
Chris@50 448 template <typename T, size_t index>
Chris@50 449 class SplitBranch final: public ForkBranchBase {
Chris@50 450 // A PromiseNode that implements one branch of a fork -- i.e. one of the branches that receives
Chris@50 451 // a const reference.
Chris@50 452
Chris@50 453 public:
Chris@50 454 SplitBranch(Own<ForkHubBase>&& hub): ForkBranchBase(kj::mv(hub)) {}
Chris@50 455
Chris@50 456 typedef kj::Decay<decltype(kj::get<index>(kj::instance<T>()))> Element;
Chris@50 457
Chris@50 458 void get(ExceptionOrValue& output) noexcept override {
Chris@50 459 ExceptionOr<T>& hubResult = getHubResultRef().template as<T>();
Chris@50 460 KJ_IF_MAYBE(value, hubResult.value) {
Chris@50 461 output.as<Element>().value = kj::mv(kj::get<index>(*value));
Chris@50 462 } else {
Chris@50 463 output.as<Element>().value = nullptr;
Chris@50 464 }
Chris@50 465 output.exception = hubResult.exception;
Chris@50 466 releaseHub(output);
Chris@50 467 }
Chris@50 468 };
Chris@50 469
Chris@50 470 // -------------------------------------------------------------------
Chris@50 471
Chris@50 472 class ForkHubBase: public Refcounted, protected Event {
Chris@50 473 public:
Chris@50 474 ForkHubBase(Own<PromiseNode>&& inner, ExceptionOrValue& resultRef);
Chris@50 475
Chris@50 476 inline ExceptionOrValue& getResultRef() { return resultRef; }
Chris@50 477
Chris@50 478 private:
Chris@50 479 Own<PromiseNode> inner;
Chris@50 480 ExceptionOrValue& resultRef;
Chris@50 481
Chris@50 482 ForkBranchBase* headBranch = nullptr;
Chris@50 483 ForkBranchBase** tailBranch = &headBranch;
Chris@50 484 // Tail becomes null once the inner promise is ready and all branches have been notified.
Chris@50 485
Chris@50 486 Maybe<Own<Event>> fire() override;
Chris@50 487 _::PromiseNode* getInnerForTrace() override;
Chris@50 488
Chris@50 489 friend class ForkBranchBase;
Chris@50 490 };
Chris@50 491
Chris@50 492 template <typename T>
Chris@50 493 class ForkHub final: public ForkHubBase {
Chris@50 494 // A PromiseNode that implements the hub of a fork. The first call to Promise::fork() replaces
Chris@50 495 // the promise's outer node with a ForkHub, and subsequent calls add branches to that hub (if
Chris@50 496 // possible).
Chris@50 497
Chris@50 498 public:
Chris@50 499 ForkHub(Own<PromiseNode>&& inner): ForkHubBase(kj::mv(inner), result) {}
Chris@50 500
Chris@50 501 Promise<_::UnfixVoid<T>> addBranch() {
Chris@50 502 return Promise<_::UnfixVoid<T>>(false, kj::heap<ForkBranch<T>>(addRef(*this)));
Chris@50 503 }
Chris@50 504
Chris@50 505 _::SplitTuplePromise<T> split() {
Chris@50 506 return splitImpl(MakeIndexes<tupleSize<T>()>());
Chris@50 507 }
Chris@50 508
Chris@50 509 private:
Chris@50 510 ExceptionOr<T> result;
Chris@50 511
Chris@50 512 template <size_t... indexes>
Chris@50 513 _::SplitTuplePromise<T> splitImpl(Indexes<indexes...>) {
Chris@50 514 return kj::tuple(addSplit<indexes>()...);
Chris@50 515 }
Chris@50 516
Chris@50 517 template <size_t index>
Chris@50 518 Promise<JoinPromises<typename SplitBranch<T, index>::Element>> addSplit() {
Chris@50 519 return Promise<JoinPromises<typename SplitBranch<T, index>::Element>>(
Chris@50 520 false, maybeChain(kj::heap<SplitBranch<T, index>>(addRef(*this)),
Chris@50 521 implicitCast<typename SplitBranch<T, index>::Element*>(nullptr)));
Chris@50 522 }
Chris@50 523 };
Chris@50 524
Chris@50 525 inline ExceptionOrValue& ForkBranchBase::getHubResultRef() {
Chris@50 526 return hub->getResultRef();
Chris@50 527 }
Chris@50 528
Chris@50 529 // -------------------------------------------------------------------
Chris@50 530
Chris@50 531 class ChainPromiseNode final: public PromiseNode, public Event {
Chris@50 532 // Promise node which reduces Promise<Promise<T>> to Promise<T>.
Chris@50 533 //
Chris@50 534 // `Event` is only a public base class because otherwise we can't cast Own<ChainPromiseNode> to
Chris@50 535 // Own<Event>. Ugh, templates and private...
Chris@50 536
Chris@50 537 public:
Chris@50 538 explicit ChainPromiseNode(Own<PromiseNode> inner);
Chris@50 539 ~ChainPromiseNode() noexcept(false);
Chris@50 540
Chris@50 541 void onReady(Event& event) noexcept override;
Chris@50 542 void setSelfPointer(Own<PromiseNode>* selfPtr) noexcept override;
Chris@50 543 void get(ExceptionOrValue& output) noexcept override;
Chris@50 544 PromiseNode* getInnerForTrace() override;
Chris@50 545
Chris@50 546 private:
Chris@50 547 enum State {
Chris@50 548 STEP1,
Chris@50 549 STEP2
Chris@50 550 };
Chris@50 551
Chris@50 552 State state;
Chris@50 553
Chris@50 554 Own<PromiseNode> inner;
Chris@50 555 // In STEP1, a PromiseNode for a Promise<T>.
Chris@50 556 // In STEP2, a PromiseNode for a T.
Chris@50 557
Chris@50 558 Event* onReadyEvent = nullptr;
Chris@50 559 Own<PromiseNode>* selfPtr = nullptr;
Chris@50 560
Chris@50 561 Maybe<Own<Event>> fire() override;
Chris@50 562 };
Chris@50 563
Chris@50 564 template <typename T>
Chris@50 565 Own<PromiseNode> maybeChain(Own<PromiseNode>&& node, Promise<T>*) {
Chris@50 566 return heap<ChainPromiseNode>(kj::mv(node));
Chris@50 567 }
Chris@50 568
Chris@50 569 template <typename T>
Chris@50 570 Own<PromiseNode>&& maybeChain(Own<PromiseNode>&& node, T*) {
Chris@50 571 return kj::mv(node);
Chris@50 572 }
Chris@50 573
Chris@50 574 // -------------------------------------------------------------------
Chris@50 575
Chris@50 576 class ExclusiveJoinPromiseNode final: public PromiseNode {
Chris@50 577 public:
Chris@50 578 ExclusiveJoinPromiseNode(Own<PromiseNode> left, Own<PromiseNode> right);
Chris@50 579 ~ExclusiveJoinPromiseNode() noexcept(false);
Chris@50 580
Chris@50 581 void onReady(Event& event) noexcept override;
Chris@50 582 void get(ExceptionOrValue& output) noexcept override;
Chris@50 583 PromiseNode* getInnerForTrace() override;
Chris@50 584
Chris@50 585 private:
Chris@50 586 class Branch: public Event {
Chris@50 587 public:
Chris@50 588 Branch(ExclusiveJoinPromiseNode& joinNode, Own<PromiseNode> dependency);
Chris@50 589 ~Branch() noexcept(false);
Chris@50 590
Chris@50 591 bool get(ExceptionOrValue& output);
Chris@50 592 // Returns true if this is the side that finished.
Chris@50 593
Chris@50 594 Maybe<Own<Event>> fire() override;
Chris@50 595 _::PromiseNode* getInnerForTrace() override;
Chris@50 596
Chris@50 597 private:
Chris@50 598 ExclusiveJoinPromiseNode& joinNode;
Chris@50 599 Own<PromiseNode> dependency;
Chris@50 600 };
Chris@50 601
Chris@50 602 Branch left;
Chris@50 603 Branch right;
Chris@50 604 OnReadyEvent onReadyEvent;
Chris@50 605 };
Chris@50 606
Chris@50 607 // -------------------------------------------------------------------
Chris@50 608
Chris@50 609 class ArrayJoinPromiseNodeBase: public PromiseNode {
Chris@50 610 public:
Chris@50 611 ArrayJoinPromiseNodeBase(Array<Own<PromiseNode>> promises,
Chris@50 612 ExceptionOrValue* resultParts, size_t partSize);
Chris@50 613 ~ArrayJoinPromiseNodeBase() noexcept(false);
Chris@50 614
Chris@50 615 void onReady(Event& event) noexcept override final;
Chris@50 616 void get(ExceptionOrValue& output) noexcept override final;
Chris@50 617 PromiseNode* getInnerForTrace() override final;
Chris@50 618
Chris@50 619 protected:
Chris@50 620 virtual void getNoError(ExceptionOrValue& output) noexcept = 0;
Chris@50 621 // Called to compile the result only in the case where there were no errors.
Chris@50 622
Chris@50 623 private:
Chris@50 624 uint countLeft;
Chris@50 625 OnReadyEvent onReadyEvent;
Chris@50 626
Chris@50 627 class Branch final: public Event {
Chris@50 628 public:
Chris@50 629 Branch(ArrayJoinPromiseNodeBase& joinNode, Own<PromiseNode> dependency,
Chris@50 630 ExceptionOrValue& output);
Chris@50 631 ~Branch() noexcept(false);
Chris@50 632
Chris@50 633 Maybe<Own<Event>> fire() override;
Chris@50 634 _::PromiseNode* getInnerForTrace() override;
Chris@50 635
Chris@50 636 Maybe<Exception> getPart();
Chris@50 637 // Calls dependency->get(output). If there was an exception, return it.
Chris@50 638
Chris@50 639 private:
Chris@50 640 ArrayJoinPromiseNodeBase& joinNode;
Chris@50 641 Own<PromiseNode> dependency;
Chris@50 642 ExceptionOrValue& output;
Chris@50 643 };
Chris@50 644
Chris@50 645 Array<Branch> branches;
Chris@50 646 };
Chris@50 647
Chris@50 648 template <typename T>
Chris@50 649 class ArrayJoinPromiseNode final: public ArrayJoinPromiseNodeBase {
Chris@50 650 public:
Chris@50 651 ArrayJoinPromiseNode(Array<Own<PromiseNode>> promises,
Chris@50 652 Array<ExceptionOr<T>> resultParts)
Chris@50 653 : ArrayJoinPromiseNodeBase(kj::mv(promises), resultParts.begin(), sizeof(ExceptionOr<T>)),
Chris@50 654 resultParts(kj::mv(resultParts)) {}
Chris@50 655
Chris@50 656 protected:
Chris@50 657 void getNoError(ExceptionOrValue& output) noexcept override {
Chris@50 658 auto builder = heapArrayBuilder<T>(resultParts.size());
Chris@50 659 for (auto& part: resultParts) {
Chris@50 660 KJ_IASSERT(part.value != nullptr,
Chris@50 661 "Bug in KJ promise framework: Promise result had neither value no exception.");
Chris@50 662 builder.add(kj::mv(*_::readMaybe(part.value)));
Chris@50 663 }
Chris@50 664 output.as<Array<T>>() = builder.finish();
Chris@50 665 }
Chris@50 666
Chris@50 667 private:
Chris@50 668 Array<ExceptionOr<T>> resultParts;
Chris@50 669 };
Chris@50 670
Chris@50 671 template <>
Chris@50 672 class ArrayJoinPromiseNode<void> final: public ArrayJoinPromiseNodeBase {
Chris@50 673 public:
Chris@50 674 ArrayJoinPromiseNode(Array<Own<PromiseNode>> promises,
Chris@50 675 Array<ExceptionOr<_::Void>> resultParts);
Chris@50 676 ~ArrayJoinPromiseNode();
Chris@50 677
Chris@50 678 protected:
Chris@50 679 void getNoError(ExceptionOrValue& output) noexcept override;
Chris@50 680
Chris@50 681 private:
Chris@50 682 Array<ExceptionOr<_::Void>> resultParts;
Chris@50 683 };
Chris@50 684
Chris@50 685 // -------------------------------------------------------------------
Chris@50 686
Chris@50 687 class EagerPromiseNodeBase: public PromiseNode, protected Event {
Chris@50 688 // A PromiseNode that eagerly evaluates its dependency even if its dependent does not eagerly
Chris@50 689 // evaluate it.
Chris@50 690
Chris@50 691 public:
Chris@50 692 EagerPromiseNodeBase(Own<PromiseNode>&& dependency, ExceptionOrValue& resultRef);
Chris@50 693
Chris@50 694 void onReady(Event& event) noexcept override;
Chris@50 695 PromiseNode* getInnerForTrace() override;
Chris@50 696
Chris@50 697 private:
Chris@50 698 Own<PromiseNode> dependency;
Chris@50 699 OnReadyEvent onReadyEvent;
Chris@50 700
Chris@50 701 ExceptionOrValue& resultRef;
Chris@50 702
Chris@50 703 Maybe<Own<Event>> fire() override;
Chris@50 704 };
Chris@50 705
Chris@50 706 template <typename T>
Chris@50 707 class EagerPromiseNode final: public EagerPromiseNodeBase {
Chris@50 708 public:
Chris@50 709 EagerPromiseNode(Own<PromiseNode>&& dependency)
Chris@50 710 : EagerPromiseNodeBase(kj::mv(dependency), result) {}
Chris@50 711
Chris@50 712 void get(ExceptionOrValue& output) noexcept override {
Chris@50 713 output.as<T>() = kj::mv(result);
Chris@50 714 }
Chris@50 715
Chris@50 716 private:
Chris@50 717 ExceptionOr<T> result;
Chris@50 718 };
Chris@50 719
Chris@50 720 template <typename T>
Chris@50 721 Own<PromiseNode> spark(Own<PromiseNode>&& node) {
Chris@50 722 // Forces evaluation of the given node to begin as soon as possible, even if no one is waiting
Chris@50 723 // on it.
Chris@50 724 return heap<EagerPromiseNode<T>>(kj::mv(node));
Chris@50 725 }
Chris@50 726
Chris@50 727 // -------------------------------------------------------------------
Chris@50 728
Chris@50 729 class AdapterPromiseNodeBase: public PromiseNode {
Chris@50 730 public:
Chris@50 731 void onReady(Event& event) noexcept override;
Chris@50 732
Chris@50 733 protected:
Chris@50 734 inline void setReady() {
Chris@50 735 onReadyEvent.arm();
Chris@50 736 }
Chris@50 737
Chris@50 738 private:
Chris@50 739 OnReadyEvent onReadyEvent;
Chris@50 740 };
Chris@50 741
Chris@50 742 template <typename T, typename Adapter>
Chris@50 743 class AdapterPromiseNode final: public AdapterPromiseNodeBase,
Chris@50 744 private PromiseFulfiller<UnfixVoid<T>> {
Chris@50 745 // A PromiseNode that wraps a PromiseAdapter.
Chris@50 746
Chris@50 747 public:
Chris@50 748 template <typename... Params>
Chris@50 749 AdapterPromiseNode(Params&&... params)
Chris@50 750 : adapter(static_cast<PromiseFulfiller<UnfixVoid<T>>&>(*this), kj::fwd<Params>(params)...) {}
Chris@50 751
Chris@50 752 void get(ExceptionOrValue& output) noexcept override {
Chris@50 753 KJ_IREQUIRE(!isWaiting());
Chris@50 754 output.as<T>() = kj::mv(result);
Chris@50 755 }
Chris@50 756
Chris@50 757 private:
Chris@50 758 ExceptionOr<T> result;
Chris@50 759 bool waiting = true;
Chris@50 760 Adapter adapter;
Chris@50 761
Chris@50 762 void fulfill(T&& value) override {
Chris@50 763 if (waiting) {
Chris@50 764 waiting = false;
Chris@50 765 result = ExceptionOr<T>(kj::mv(value));
Chris@50 766 setReady();
Chris@50 767 }
Chris@50 768 }
Chris@50 769
Chris@50 770 void reject(Exception&& exception) override {
Chris@50 771 if (waiting) {
Chris@50 772 waiting = false;
Chris@50 773 result = ExceptionOr<T>(false, kj::mv(exception));
Chris@50 774 setReady();
Chris@50 775 }
Chris@50 776 }
Chris@50 777
Chris@50 778 bool isWaiting() override {
Chris@50 779 return waiting;
Chris@50 780 }
Chris@50 781 };
Chris@50 782
Chris@50 783 } // namespace _ (private)
Chris@50 784
Chris@50 785 // =======================================================================================
Chris@50 786
Chris@50 787 template <typename T>
Chris@50 788 Promise<T>::Promise(_::FixVoid<T> value)
Chris@50 789 : PromiseBase(heap<_::ImmediatePromiseNode<_::FixVoid<T>>>(kj::mv(value))) {}
Chris@50 790
Chris@50 791 template <typename T>
Chris@50 792 Promise<T>::Promise(kj::Exception&& exception)
Chris@50 793 : PromiseBase(heap<_::ImmediateBrokenPromiseNode>(kj::mv(exception))) {}
Chris@50 794
Chris@50 795 template <typename T>
Chris@50 796 template <typename Func, typename ErrorFunc>
Chris@50 797 PromiseForResult<Func, T> Promise<T>::then(Func&& func, ErrorFunc&& errorHandler) {
Chris@50 798 typedef _::FixVoid<_::ReturnType<Func, T>> ResultT;
Chris@50 799
Chris@50 800 Own<_::PromiseNode> intermediate =
Chris@50 801 heap<_::TransformPromiseNode<ResultT, _::FixVoid<T>, Func, ErrorFunc>>(
Chris@50 802 kj::mv(node), kj::fwd<Func>(func), kj::fwd<ErrorFunc>(errorHandler));
Chris@50 803 return PromiseForResult<Func, T>(false,
Chris@50 804 _::maybeChain(kj::mv(intermediate), implicitCast<ResultT*>(nullptr)));
Chris@50 805 }
Chris@50 806
Chris@50 807 namespace _ { // private
Chris@50 808
Chris@50 809 template <typename T>
Chris@50 810 struct IdentityFunc {
Chris@50 811 inline T operator()(T&& value) const {
Chris@50 812 return kj::mv(value);
Chris@50 813 }
Chris@50 814 };
Chris@50 815 template <typename T>
Chris@50 816 struct IdentityFunc<Promise<T>> {
Chris@50 817 inline Promise<T> operator()(T&& value) const {
Chris@50 818 return kj::mv(value);
Chris@50 819 }
Chris@50 820 };
Chris@50 821 template <>
Chris@50 822 struct IdentityFunc<void> {
Chris@50 823 inline void operator()() const {}
Chris@50 824 };
Chris@50 825 template <>
Chris@50 826 struct IdentityFunc<Promise<void>> {
Chris@50 827 Promise<void> operator()() const;
Chris@50 828 // This can't be inline because it will make the translation unit depend on kj-async. Awkwardly,
Chris@50 829 // Cap'n Proto relies on being able to include this header without creating such a link-time
Chris@50 830 // dependency.
Chris@50 831 };
Chris@50 832
Chris@50 833 } // namespace _ (private)
Chris@50 834
Chris@50 835 template <typename T>
Chris@50 836 template <typename ErrorFunc>
Chris@50 837 Promise<T> Promise<T>::catch_(ErrorFunc&& errorHandler) {
Chris@50 838 // then()'s ErrorFunc can only return a Promise if Func also returns a Promise. In this case,
Chris@50 839 // Func is being filled in automatically. We want to make sure ErrorFunc can return a Promise,
Chris@50 840 // but we don't want the extra overhead of promise chaining if ErrorFunc doesn't actually
Chris@50 841 // return a promise. So we make our Func return match ErrorFunc.
Chris@50 842 return then(_::IdentityFunc<decltype(errorHandler(instance<Exception&&>()))>(),
Chris@50 843 kj::fwd<ErrorFunc>(errorHandler));
Chris@50 844 }
Chris@50 845
Chris@50 846 template <typename T>
Chris@50 847 T Promise<T>::wait(WaitScope& waitScope) {
Chris@50 848 _::ExceptionOr<_::FixVoid<T>> result;
Chris@50 849
Chris@50 850 waitImpl(kj::mv(node), result, waitScope);
Chris@50 851
Chris@50 852 KJ_IF_MAYBE(value, result.value) {
Chris@50 853 KJ_IF_MAYBE(exception, result.exception) {
Chris@50 854 throwRecoverableException(kj::mv(*exception));
Chris@50 855 }
Chris@50 856 return _::returnMaybeVoid(kj::mv(*value));
Chris@50 857 } else KJ_IF_MAYBE(exception, result.exception) {
Chris@50 858 throwFatalException(kj::mv(*exception));
Chris@50 859 } else {
Chris@50 860 // Result contained neither a value nor an exception?
Chris@50 861 KJ_UNREACHABLE;
Chris@50 862 }
Chris@50 863 }
Chris@50 864
Chris@50 865 template <typename T>
Chris@50 866 ForkedPromise<T> Promise<T>::fork() {
Chris@50 867 return ForkedPromise<T>(false, refcounted<_::ForkHub<_::FixVoid<T>>>(kj::mv(node)));
Chris@50 868 }
Chris@50 869
Chris@50 870 template <typename T>
Chris@50 871 Promise<T> ForkedPromise<T>::addBranch() {
Chris@50 872 return hub->addBranch();
Chris@50 873 }
Chris@50 874
Chris@50 875 template <typename T>
Chris@50 876 _::SplitTuplePromise<T> Promise<T>::split() {
Chris@50 877 return refcounted<_::ForkHub<_::FixVoid<T>>>(kj::mv(node))->split();
Chris@50 878 }
Chris@50 879
Chris@50 880 template <typename T>
Chris@50 881 Promise<T> Promise<T>::exclusiveJoin(Promise<T>&& other) {
Chris@50 882 return Promise(false, heap<_::ExclusiveJoinPromiseNode>(kj::mv(node), kj::mv(other.node)));
Chris@50 883 }
Chris@50 884
Chris@50 885 template <typename T>
Chris@50 886 template <typename... Attachments>
Chris@50 887 Promise<T> Promise<T>::attach(Attachments&&... attachments) {
Chris@50 888 return Promise(false, kj::heap<_::AttachmentPromiseNode<Tuple<Attachments...>>>(
Chris@50 889 kj::mv(node), kj::tuple(kj::fwd<Attachments>(attachments)...)));
Chris@50 890 }
Chris@50 891
Chris@50 892 template <typename T>
Chris@50 893 template <typename ErrorFunc>
Chris@50 894 Promise<T> Promise<T>::eagerlyEvaluate(ErrorFunc&& errorHandler) {
Chris@50 895 // See catch_() for commentary.
Chris@50 896 return Promise(false, _::spark<_::FixVoid<T>>(then(
Chris@50 897 _::IdentityFunc<decltype(errorHandler(instance<Exception&&>()))>(),
Chris@50 898 kj::fwd<ErrorFunc>(errorHandler)).node));
Chris@50 899 }
Chris@50 900
Chris@50 901 template <typename T>
Chris@50 902 Promise<T> Promise<T>::eagerlyEvaluate(decltype(nullptr)) {
Chris@50 903 return Promise(false, _::spark<_::FixVoid<T>>(kj::mv(node)));
Chris@50 904 }
Chris@50 905
Chris@50 906 template <typename T>
Chris@50 907 kj::String Promise<T>::trace() {
Chris@50 908 return PromiseBase::trace();
Chris@50 909 }
Chris@50 910
Chris@50 911 template <typename Func>
Chris@50 912 inline PromiseForResult<Func, void> evalLater(Func&& func) {
Chris@50 913 return _::yield().then(kj::fwd<Func>(func), _::PropagateException());
Chris@50 914 }
Chris@50 915
Chris@50 916 template <typename Func>
Chris@50 917 inline PromiseForResult<Func, void> evalNow(Func&& func) {
Chris@50 918 PromiseForResult<Func, void> result = nullptr;
Chris@50 919 KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() {
Chris@50 920 result = func();
Chris@50 921 })) {
Chris@50 922 result = kj::mv(*e);
Chris@50 923 }
Chris@50 924 return result;
Chris@50 925 }
Chris@50 926
Chris@50 927 template <typename T>
Chris@50 928 template <typename ErrorFunc>
Chris@50 929 void Promise<T>::detach(ErrorFunc&& errorHandler) {
Chris@50 930 return _::detach(then([](T&&) {}, kj::fwd<ErrorFunc>(errorHandler)));
Chris@50 931 }
Chris@50 932
Chris@50 933 template <>
Chris@50 934 template <typename ErrorFunc>
Chris@50 935 void Promise<void>::detach(ErrorFunc&& errorHandler) {
Chris@50 936 return _::detach(then([]() {}, kj::fwd<ErrorFunc>(errorHandler)));
Chris@50 937 }
Chris@50 938
Chris@50 939 template <typename T>
Chris@50 940 Promise<Array<T>> joinPromises(Array<Promise<T>>&& promises) {
Chris@50 941 return Promise<Array<T>>(false, kj::heap<_::ArrayJoinPromiseNode<T>>(
Chris@50 942 KJ_MAP(p, promises) { return kj::mv(p.node); },
Chris@50 943 heapArray<_::ExceptionOr<T>>(promises.size())));
Chris@50 944 }
Chris@50 945
Chris@50 946 // =======================================================================================
Chris@50 947
Chris@50 948 namespace _ { // private
Chris@50 949
Chris@50 950 template <typename T>
Chris@50 951 class WeakFulfiller final: public PromiseFulfiller<T>, private kj::Disposer {
Chris@50 952 // A wrapper around PromiseFulfiller which can be detached.
Chris@50 953 //
Chris@50 954 // There are a couple non-trivialities here:
Chris@50 955 // - If the WeakFulfiller is discarded, we want the promise it fulfills to be implicitly
Chris@50 956 // rejected.
Chris@50 957 // - We cannot destroy the WeakFulfiller until the application has discarded it *and* it has been
Chris@50 958 // detached from the underlying fulfiller, because otherwise the later detach() call will go
Chris@50 959 // to a dangling pointer. Essentially, WeakFulfiller is reference counted, although the
Chris@50 960 // refcount never goes over 2 and we manually implement the refcounting because we need to do
Chris@50 961 // other special things when each side detaches anyway. To this end, WeakFulfiller is its own
Chris@50 962 // Disposer -- dispose() is called when the application discards its owned pointer to the
Chris@50 963 // fulfiller and detach() is called when the promise is destroyed.
Chris@50 964
Chris@50 965 public:
Chris@50 966 KJ_DISALLOW_COPY(WeakFulfiller);
Chris@50 967
Chris@50 968 static kj::Own<WeakFulfiller> make() {
Chris@50 969 WeakFulfiller* ptr = new WeakFulfiller;
Chris@50 970 return Own<WeakFulfiller>(ptr, *ptr);
Chris@50 971 }
Chris@50 972
Chris@50 973 void fulfill(FixVoid<T>&& value) override {
Chris@50 974 if (inner != nullptr) {
Chris@50 975 inner->fulfill(kj::mv(value));
Chris@50 976 }
Chris@50 977 }
Chris@50 978
Chris@50 979 void reject(Exception&& exception) override {
Chris@50 980 if (inner != nullptr) {
Chris@50 981 inner->reject(kj::mv(exception));
Chris@50 982 }
Chris@50 983 }
Chris@50 984
Chris@50 985 bool isWaiting() override {
Chris@50 986 return inner != nullptr && inner->isWaiting();
Chris@50 987 }
Chris@50 988
Chris@50 989 void attach(PromiseFulfiller<T>& newInner) {
Chris@50 990 inner = &newInner;
Chris@50 991 }
Chris@50 992
Chris@50 993 void detach(PromiseFulfiller<T>& from) {
Chris@50 994 if (inner == nullptr) {
Chris@50 995 // Already disposed.
Chris@50 996 delete this;
Chris@50 997 } else {
Chris@50 998 KJ_IREQUIRE(inner == &from);
Chris@50 999 inner = nullptr;
Chris@50 1000 }
Chris@50 1001 }
Chris@50 1002
Chris@50 1003 private:
Chris@50 1004 mutable PromiseFulfiller<T>* inner;
Chris@50 1005
Chris@50 1006 WeakFulfiller(): inner(nullptr) {}
Chris@50 1007
Chris@50 1008 void disposeImpl(void* pointer) const override {
Chris@50 1009 // TODO(perf): Factor some of this out so it isn't regenerated for every fulfiller type?
Chris@50 1010
Chris@50 1011 if (inner == nullptr) {
Chris@50 1012 // Already detached.
Chris@50 1013 delete this;
Chris@50 1014 } else {
Chris@50 1015 if (inner->isWaiting()) {
Chris@50 1016 inner->reject(kj::Exception(kj::Exception::Type::FAILED, __FILE__, __LINE__,
Chris@50 1017 kj::heapString("PromiseFulfiller was destroyed without fulfilling the promise.")));
Chris@50 1018 }
Chris@50 1019 inner = nullptr;
Chris@50 1020 }
Chris@50 1021 }
Chris@50 1022 };
Chris@50 1023
Chris@50 1024 template <typename T>
Chris@50 1025 class PromiseAndFulfillerAdapter {
Chris@50 1026 public:
Chris@50 1027 PromiseAndFulfillerAdapter(PromiseFulfiller<T>& fulfiller,
Chris@50 1028 WeakFulfiller<T>& wrapper)
Chris@50 1029 : fulfiller(fulfiller), wrapper(wrapper) {
Chris@50 1030 wrapper.attach(fulfiller);
Chris@50 1031 }
Chris@50 1032
Chris@50 1033 ~PromiseAndFulfillerAdapter() noexcept(false) {
Chris@50 1034 wrapper.detach(fulfiller);
Chris@50 1035 }
Chris@50 1036
Chris@50 1037 private:
Chris@50 1038 PromiseFulfiller<T>& fulfiller;
Chris@50 1039 WeakFulfiller<T>& wrapper;
Chris@50 1040 };
Chris@50 1041
Chris@50 1042 } // namespace _ (private)
Chris@50 1043
Chris@50 1044 template <typename T>
Chris@50 1045 template <typename Func>
Chris@50 1046 bool PromiseFulfiller<T>::rejectIfThrows(Func&& func) {
Chris@50 1047 KJ_IF_MAYBE(exception, kj::runCatchingExceptions(kj::mv(func))) {
Chris@50 1048 reject(kj::mv(*exception));
Chris@50 1049 return false;
Chris@50 1050 } else {
Chris@50 1051 return true;
Chris@50 1052 }
Chris@50 1053 }
Chris@50 1054
Chris@50 1055 template <typename Func>
Chris@50 1056 bool PromiseFulfiller<void>::rejectIfThrows(Func&& func) {
Chris@50 1057 KJ_IF_MAYBE(exception, kj::runCatchingExceptions(kj::mv(func))) {
Chris@50 1058 reject(kj::mv(*exception));
Chris@50 1059 return false;
Chris@50 1060 } else {
Chris@50 1061 return true;
Chris@50 1062 }
Chris@50 1063 }
Chris@50 1064
Chris@50 1065 template <typename T, typename Adapter, typename... Params>
Chris@50 1066 Promise<T> newAdaptedPromise(Params&&... adapterConstructorParams) {
Chris@50 1067 return Promise<T>(false, heap<_::AdapterPromiseNode<_::FixVoid<T>, Adapter>>(
Chris@50 1068 kj::fwd<Params>(adapterConstructorParams)...));
Chris@50 1069 }
Chris@50 1070
Chris@50 1071 template <typename T>
Chris@50 1072 PromiseFulfillerPair<T> newPromiseAndFulfiller() {
Chris@50 1073 auto wrapper = _::WeakFulfiller<T>::make();
Chris@50 1074
Chris@50 1075 Own<_::PromiseNode> intermediate(
Chris@50 1076 heap<_::AdapterPromiseNode<_::FixVoid<T>, _::PromiseAndFulfillerAdapter<T>>>(*wrapper));
Chris@50 1077 Promise<_::JoinPromises<T>> promise(false,
Chris@50 1078 _::maybeChain(kj::mv(intermediate), implicitCast<T*>(nullptr)));
Chris@50 1079
Chris@50 1080 return PromiseFulfillerPair<T> { kj::mv(promise), kj::mv(wrapper) };
Chris@50 1081 }
Chris@50 1082
Chris@50 1083 } // namespace kj
Chris@50 1084
Chris@50 1085 #endif // KJ_ASYNC_INL_H_