cannam@147: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors cannam@147: // Licensed under the MIT License: cannam@147: // cannam@147: // Permission is hereby granted, free of charge, to any person obtaining a copy cannam@147: // of this software and associated documentation files (the "Software"), to deal cannam@147: // in the Software without restriction, including without limitation the rights cannam@147: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell cannam@147: // copies of the Software, and to permit persons to whom the Software is cannam@147: // furnished to do so, subject to the following conditions: cannam@147: // cannam@147: // The above copyright notice and this permission notice shall be included in cannam@147: // all copies or substantial portions of the Software. cannam@147: // cannam@147: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR cannam@147: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, cannam@147: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE cannam@147: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER cannam@147: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, cannam@147: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN cannam@147: // THE SOFTWARE. cannam@147: cannam@147: #ifndef KJ_ASYNC_H_ cannam@147: #define KJ_ASYNC_H_ cannam@147: cannam@147: #if defined(__GNUC__) && !KJ_HEADER_WARNINGS cannam@147: #pragma GCC system_header cannam@147: #endif cannam@147: cannam@147: #include "async-prelude.h" cannam@147: #include "exception.h" cannam@147: #include "refcount.h" cannam@147: cannam@147: namespace kj { cannam@147: cannam@147: class EventLoop; cannam@147: class WaitScope; cannam@147: cannam@147: template cannam@147: class Promise; cannam@147: template cannam@147: class ForkedPromise; cannam@147: template cannam@147: class PromiseFulfiller; cannam@147: template cannam@147: struct PromiseFulfillerPair; cannam@147: cannam@147: template cannam@147: using PromiseForResult = Promise<_::JoinPromises<_::ReturnType>>; cannam@147: // Evaluates to the type of Promise for the result of calling functor type Func with parameter type cannam@147: // T. If T is void, then the promise is for the result of calling Func with no arguments. If cannam@147: // Func itself returns a promise, the promises are joined, so you never get Promise>. cannam@147: cannam@147: // ======================================================================================= cannam@147: // Promises cannam@147: cannam@147: template cannam@147: class Promise: protected _::PromiseBase { cannam@147: // The basic primitive of asynchronous computation in KJ. Similar to "futures", but designed cannam@147: // specifically for event loop concurrency. Similar to E promises and JavaScript Promises/A. cannam@147: // cannam@147: // A Promise represents a promise to produce a value of type T some time in the future. Once cannam@147: // that value has been produced, the promise is "fulfilled". Alternatively, a promise can be cannam@147: // "broken", with an Exception describing what went wrong. You may implicitly convert a value of cannam@147: // type T to an already-fulfilled Promise. You may implicitly convert the constant cannam@147: // `kj::READY_NOW` to an already-fulfilled Promise. You may also implicitly convert a cannam@147: // `kj::Exception` to an already-broken promise of any type. cannam@147: // cannam@147: // Promises are linear types -- they are moveable but not copyable. If a Promise is destroyed cannam@147: // or goes out of scope (without being moved elsewhere), any ongoing asynchronous operations cannam@147: // meant to fulfill the promise will be canceled if possible. All methods of `Promise` (unless cannam@147: // otherwise noted) actually consume the promise in the sense of move semantics. (Arguably they cannam@147: // should be rvalue-qualified, but at the time this interface was created compilers didn't widely cannam@147: // support that yet and anyway it would be pretty ugly typing kj::mv(promise).whatever().) If cannam@147: // you want to use one Promise in two different places, you must fork it with `fork()`. cannam@147: // cannam@147: // To use the result of a Promise, you must call `then()` and supply a callback function to cannam@147: // call with the result. `then()` returns another promise, for the result of the callback. cannam@147: // Any time that this would result in Promise>, the promises are collapsed into a cannam@147: // simple Promise that first waits for the outer promise, then the inner. Example: cannam@147: // cannam@147: // // Open a remote file, read the content, and then count the cannam@147: // // number of lines of text. cannam@147: // // Note that none of the calls here block. `file`, `content` cannam@147: // // and `lineCount` are all initialized immediately before any cannam@147: // // asynchronous operations occur. The lambda callbacks are cannam@147: // // called later. cannam@147: // Promise> file = openFtp("ftp://host/foo/bar"); cannam@147: // Promise content = file.then( cannam@147: // [](Own file) -> Promise { cannam@147: // return file.readAll(); cannam@147: // }); cannam@147: // Promise lineCount = content.then( cannam@147: // [](String text) -> int { cannam@147: // uint count = 0; cannam@147: // for (char c: text) count += (c == '\n'); cannam@147: // return count; cannam@147: // }); cannam@147: // cannam@147: // For `then()` to work, the current thread must have an active `EventLoop`. Each callback cannam@147: // is scheduled to execute in that loop. Since `then()` schedules callbacks only on the current cannam@147: // thread's event loop, you do not need to worry about two callbacks running at the same time. cannam@147: // You will need to set up at least one `EventLoop` at the top level of your program before you cannam@147: // can use promises. cannam@147: // cannam@147: // To adapt a non-Promise-based asynchronous API to promises, use `newAdaptedPromise()`. cannam@147: // cannam@147: // Systems using promises should consider supporting the concept of "pipelining". Pipelining cannam@147: // means allowing a caller to start issuing method calls against a promised object before the cannam@147: // promise has actually been fulfilled. This is particularly useful if the promise is for a cannam@147: // remote object living across a network, as this can avoid round trips when chaining a series cannam@147: // of calls. It is suggested that any class T which supports pipelining implement a subclass of cannam@147: // Promise which adds "eventual send" methods -- methods which, when called, say "please cannam@147: // invoke the corresponding method on the promised value once it is available". These methods cannam@147: // should in turn return promises for the eventual results of said invocations. Cap'n Proto, cannam@147: // for example, implements the type `RemotePromise` which supports pipelining RPC requests -- see cannam@147: // `capnp/capability.h`. cannam@147: // cannam@147: // KJ Promises are based on E promises: cannam@147: // http://wiki.erights.org/wiki/Walnut/Distributed_Computing#Promises cannam@147: // cannam@147: // KJ Promises are also inspired in part by the evolving standards for JavaScript/ECMAScript cannam@147: // promises, which are themselves influenced by E promises: cannam@147: // http://promisesaplus.com/ cannam@147: // https://github.com/domenic/promises-unwrapping cannam@147: cannam@147: public: cannam@147: Promise(_::FixVoid value); cannam@147: // Construct an already-fulfilled Promise from a value of type T. For non-void promises, the cannam@147: // parameter type is simply T. So, e.g., in a function that returns `Promise`, you can cannam@147: // say `return 123;` to return a promise that is already fulfilled to 123. cannam@147: // cannam@147: // For void promises, use `kj::READY_NOW` as the value, e.g. `return kj::READY_NOW`. cannam@147: cannam@147: Promise(kj::Exception&& e); cannam@147: // Construct an already-broken Promise. cannam@147: cannam@147: inline Promise(decltype(nullptr)) {} cannam@147: cannam@147: template cannam@147: PromiseForResult then(Func&& func, ErrorFunc&& errorHandler = _::PropagateException()) cannam@147: KJ_WARN_UNUSED_RESULT; cannam@147: // Register a continuation function to be executed when the promise completes. The continuation cannam@147: // (`func`) takes the promised value (an rvalue of type `T`) as its parameter. The continuation cannam@147: // may return a new value; `then()` itself returns a promise for the continuation's eventual cannam@147: // result. If the continuation itself returns a `Promise`, then `then()` shall also return cannam@147: // a `Promise` which first waits for the original promise, then executes the continuation, cannam@147: // then waits for the inner promise (i.e. it automatically "unwraps" the promise). cannam@147: // cannam@147: // In all cases, `then()` returns immediately. The continuation is executed later. The cannam@147: // continuation is always executed on the same EventLoop (and, therefore, the same thread) which cannam@147: // called `then()`, therefore no synchronization is necessary on state shared by the continuation cannam@147: // and the surrounding scope. If no EventLoop is running on the current thread, `then()` throws cannam@147: // an exception. cannam@147: // cannam@147: // You may also specify an error handler continuation as the second parameter. `errorHandler` cannam@147: // must be a functor taking a parameter of type `kj::Exception&&`. It must return the same cannam@147: // type as `func` returns (except when `func` returns `Promise`, in which case `errorHandler` cannam@147: // may return either `Promise` or just `U`). The default error handler simply propagates the cannam@147: // exception to the returned promise. cannam@147: // cannam@147: // Either `func` or `errorHandler` may, of course, throw an exception, in which case the promise cannam@147: // is broken. When compiled with -fno-exceptions, the framework will still detect when a cannam@147: // recoverable exception was thrown inside of a continuation and will consider the promise cannam@147: // broken even though a (presumably garbage) result was returned. cannam@147: // cannam@147: // If the returned promise is destroyed before the callback runs, the callback will be canceled cannam@147: // (it will never run). cannam@147: // cannam@147: // Note that `then()` -- like all other Promise methods -- consumes the promise on which it is cannam@147: // called, in the sense of move semantics. After returning, the original promise is no longer cannam@147: // valid, but `then()` returns a new promise. cannam@147: // cannam@147: // *Advanced implementation tips:* Most users will never need to worry about the below, but cannam@147: // it is good to be aware of. cannam@147: // cannam@147: // As an optimization, if the callback function `func` does _not_ return another promise, then cannam@147: // execution of `func` itself may be delayed until its result is known to be needed. The cannam@147: // expectation here is that `func` is just doing some transformation on the results, not cannam@147: // scheduling any other actions, therefore the system doesn't need to be proactive about cannam@147: // evaluating it. This way, a chain of trivial then() transformations can be executed all at cannam@147: // once without repeatedly re-scheduling through the event loop. Use the `eagerlyEvaluate()` cannam@147: // method to suppress this behavior. cannam@147: // cannam@147: // On the other hand, if `func` _does_ return another promise, then the system evaluates `func` cannam@147: // as soon as possible, because the promise it returns might be for a newly-scheduled cannam@147: // long-running asynchronous task. cannam@147: // cannam@147: // As another optimization, when a callback function registered with `then()` is actually cannam@147: // scheduled, it is scheduled to occur immediately, preempting other work in the event queue. cannam@147: // This allows a long chain of `then`s to execute all at once, improving cache locality by cannam@147: // clustering operations on the same data. However, this implies that starvation can occur cannam@147: // if a chain of `then()`s takes a very long time to execute without ever stopping to wait for cannam@147: // actual I/O. To solve this, use `kj::evalLater()` to yield control; this way, all other events cannam@147: // in the queue will get a chance to run before your callback is executed. cannam@147: cannam@147: Promise ignoreResult() KJ_WARN_UNUSED_RESULT { return then([](T&&) {}); } cannam@147: // Convenience method to convert the promise to a void promise by ignoring the return value. cannam@147: // cannam@147: // You must still wait on the returned promise if you want the task to execute. cannam@147: cannam@147: template cannam@147: Promise catch_(ErrorFunc&& errorHandler) KJ_WARN_UNUSED_RESULT; cannam@147: // Equivalent to `.then(identityFunc, errorHandler)`, where `identifyFunc` is a function that cannam@147: // just returns its input. cannam@147: cannam@147: T wait(WaitScope& waitScope); cannam@147: // Run the event loop until the promise is fulfilled, then return its result. If the promise cannam@147: // is rejected, throw an exception. cannam@147: // cannam@147: // wait() is primarily useful at the top level of a program -- typically, within the function cannam@147: // that allocated the EventLoop. For example, a program that performs one or two RPCs and then cannam@147: // exits would likely use wait() in its main() function to wait on each RPC. On the other hand, cannam@147: // server-side code generally cannot use wait(), because it has to be able to accept multiple cannam@147: // requests at once. cannam@147: // cannam@147: // If the promise is rejected, `wait()` throws an exception. If the program was compiled without cannam@147: // exceptions (-fno-exceptions), this will usually abort. In this case you really should first cannam@147: // use `then()` to set an appropriate handler for the exception case, so that the promise you cannam@147: // actually wait on never throws. cannam@147: // cannam@147: // `waitScope` is an object proving that the caller is in a scope where wait() is allowed. By cannam@147: // convention, any function which might call wait(), or which might call another function which cannam@147: // might call wait(), must take `WaitScope&` as one of its parameters. This is needed for two cannam@147: // reasons: cannam@147: // * `wait()` is not allowed during an event callback, because event callbacks are themselves cannam@147: // called during some other `wait()`, and such recursive `wait()`s would only be able to cannam@147: // complete in LIFO order, which might mean that the outer `wait()` ends up waiting longer cannam@147: // than it is supposed to. To prevent this, a `WaitScope` cannot be constructed or used during cannam@147: // an event callback. cannam@147: // * Since `wait()` runs the event loop, unrelated event callbacks may execute before `wait()` cannam@147: // returns. This means that anyone calling `wait()` must be reentrant -- state may change cannam@147: // around them in arbitrary ways. Therefore, callers really need to know if a function they cannam@147: // are calling might wait(), and the `WaitScope&` parameter makes this clear. cannam@147: // cannam@147: // TODO(someday): Implement fibers, and let them call wait() even when they are handling an cannam@147: // event. cannam@147: cannam@147: ForkedPromise fork() KJ_WARN_UNUSED_RESULT; cannam@147: // Forks the promise, so that multiple different clients can independently wait on the result. cannam@147: // `T` must be copy-constructable for this to work. Or, in the special case where `T` is cannam@147: // `Own`, `U` must have a method `Own addRef()` which returns a new reference to the same cannam@147: // (or an equivalent) object (probably implemented via reference counting). cannam@147: cannam@147: _::SplitTuplePromise split(); cannam@147: // Split a promise for a tuple into a tuple of promises. cannam@147: // cannam@147: // E.g. if you have `Promise>`, `split()` returns cannam@147: // `kj::Tuple, Promise>`. cannam@147: cannam@147: Promise exclusiveJoin(Promise&& other) KJ_WARN_UNUSED_RESULT; cannam@147: // Return a new promise that resolves when either the original promise resolves or `other` cannam@147: // resolves (whichever comes first). The promise that didn't resolve first is canceled. cannam@147: cannam@147: // TODO(someday): inclusiveJoin(), or perhaps just join(), which waits for both completions cannam@147: // and produces a tuple? cannam@147: cannam@147: template cannam@147: Promise attach(Attachments&&... attachments) KJ_WARN_UNUSED_RESULT; cannam@147: // "Attaches" one or more movable objects (often, Owns) to the promise, such that they will cannam@147: // be destroyed when the promise resolves. This is useful when a promise's callback contains cannam@147: // pointers into some object and you want to make sure the object still exists when the callback cannam@147: // runs -- after calling then(), use attach() to add necessary objects to the result. cannam@147: cannam@147: template cannam@147: Promise eagerlyEvaluate(ErrorFunc&& errorHandler) KJ_WARN_UNUSED_RESULT; cannam@147: Promise eagerlyEvaluate(decltype(nullptr)) KJ_WARN_UNUSED_RESULT; cannam@147: // Force eager evaluation of this promise. Use this if you are going to hold on to the promise cannam@147: // for awhile without consuming the result, but you want to make sure that the system actually cannam@147: // processes it. cannam@147: // cannam@147: // `errorHandler` is a function that takes `kj::Exception&&`, like the second parameter to cannam@147: // `then()`, except that it must return void. We make you specify this because otherwise it's cannam@147: // easy to forget to handle errors in a promise that you never use. You may specify nullptr for cannam@147: // the error handler if you are sure that ignoring errors is fine, or if you know that you'll cannam@147: // eventually wait on the promise somewhere. cannam@147: cannam@147: template cannam@147: void detach(ErrorFunc&& errorHandler); cannam@147: // Allows the promise to continue running in the background until it completes or the cannam@147: // `EventLoop` is destroyed. Be careful when using this: since you can no longer cancel this cannam@147: // promise, you need to make sure that the promise owns all the objects it touches or make sure cannam@147: // those objects outlive the EventLoop. cannam@147: // cannam@147: // `errorHandler` is a function that takes `kj::Exception&&`, like the second parameter to cannam@147: // `then()`, except that it must return void. cannam@147: // cannam@147: // This function exists mainly to implement the Cap'n Proto requirement that RPC calls cannot be cannam@147: // canceled unless the callee explicitly permits it. cannam@147: cannam@147: kj::String trace(); cannam@147: // Returns a dump of debug info about this promise. Not for production use. Requires RTTI. cannam@147: // This method does NOT consume the promise as other methods do. cannam@147: cannam@147: private: cannam@147: Promise(bool, Own<_::PromiseNode>&& node): PromiseBase(kj::mv(node)) {} cannam@147: // Second parameter prevent ambiguity with immediate-value constructor. cannam@147: cannam@147: template cannam@147: friend class Promise; cannam@147: friend class EventLoop; cannam@147: template cannam@147: friend Promise newAdaptedPromise(Params&&... adapterConstructorParams); cannam@147: template cannam@147: friend PromiseFulfillerPair newPromiseAndFulfiller(); cannam@147: template cannam@147: friend class _::ForkHub; cannam@147: friend class _::TaskSetImpl; cannam@147: friend Promise _::yield(); cannam@147: friend class _::NeverDone; cannam@147: template cannam@147: friend Promise> joinPromises(Array>&& promises); cannam@147: friend Promise joinPromises(Array>&& promises); cannam@147: }; cannam@147: cannam@147: template cannam@147: class ForkedPromise { cannam@147: // The result of `Promise::fork()` and `EventLoop::fork()`. Allows branches to be created. cannam@147: // Like `Promise`, this is a pass-by-move type. cannam@147: cannam@147: public: cannam@147: inline ForkedPromise(decltype(nullptr)) {} cannam@147: cannam@147: Promise addBranch(); cannam@147: // Add a new branch to the fork. The branch is equivalent to the original promise. cannam@147: cannam@147: private: cannam@147: Own<_::ForkHub<_::FixVoid>> hub; cannam@147: cannam@147: inline ForkedPromise(bool, Own<_::ForkHub<_::FixVoid>>&& hub): hub(kj::mv(hub)) {} cannam@147: cannam@147: friend class Promise; cannam@147: friend class EventLoop; cannam@147: }; cannam@147: cannam@147: constexpr _::Void READY_NOW = _::Void(); cannam@147: // Use this when you need a Promise that is already fulfilled -- this value can be implicitly cannam@147: // cast to `Promise`. cannam@147: cannam@147: constexpr _::NeverDone NEVER_DONE = _::NeverDone(); cannam@147: // The opposite of `READY_NOW`, return this when the promise should never resolve. This can be cannam@147: // implicitly converted to any promise type. You may also call `NEVER_DONE.wait()` to wait cannam@147: // forever (useful for servers). cannam@147: cannam@147: template cannam@147: PromiseForResult evalLater(Func&& func) KJ_WARN_UNUSED_RESULT; cannam@147: // Schedule for the given zero-parameter function to be executed in the event loop at some cannam@147: // point in the near future. Returns a Promise for its result -- or, if `func()` itself returns cannam@147: // a promise, `evalLater()` returns a Promise for the result of resolving that promise. cannam@147: // cannam@147: // Example usage: cannam@147: // Promise x = evalLater([]() { return 123; }); cannam@147: // cannam@147: // The above is exactly equivalent to: cannam@147: // Promise x = Promise(READY_NOW).then([]() { return 123; }); cannam@147: // cannam@147: // If the returned promise is destroyed before the callback runs, the callback will be canceled cannam@147: // (never called). cannam@147: // cannam@147: // If you schedule several evaluations with `evalLater` during the same callback, they are cannam@147: // guaranteed to be executed in order. cannam@147: cannam@147: template cannam@147: PromiseForResult evalNow(Func&& func) KJ_WARN_UNUSED_RESULT; cannam@147: // Run `func()` and return a promise for its result. `func()` executes before `evalNow()` returns. cannam@147: // If `func()` throws an exception, the exception is caught and wrapped in a promise -- this is the cannam@147: // main reason why `evalNow()` is useful. cannam@147: cannam@147: template cannam@147: Promise> joinPromises(Array>&& promises); cannam@147: // Join an array of promises into a promise for an array. cannam@147: cannam@147: // ======================================================================================= cannam@147: // Hack for creating a lambda that holds an owned pointer. cannam@147: cannam@147: template cannam@147: class CaptureByMove { cannam@147: public: cannam@147: inline CaptureByMove(Func&& func, MovedParam&& param) cannam@147: : func(kj::mv(func)), param(kj::mv(param)) {} cannam@147: cannam@147: template cannam@147: inline auto operator()(Params&&... params) cannam@147: -> decltype(kj::instance()(kj::instance(), kj::fwd(params)...)) { cannam@147: return func(kj::mv(param), kj::fwd(params)...); cannam@147: } cannam@147: cannam@147: private: cannam@147: Func func; cannam@147: MovedParam param; cannam@147: }; cannam@147: cannam@147: template cannam@147: inline CaptureByMove> mvCapture(MovedParam&& param, Func&& func) { cannam@147: // Hack to create a "lambda" which captures a variable by moving it rather than copying or cannam@147: // referencing. C++14 generalized captures should make this obsolete, but for now in C++11 this cannam@147: // is commonly needed for Promise continuations that own their state. Example usage: cannam@147: // cannam@147: // Own ptr = makeFoo(); cannam@147: // Promise promise = callRpc(); cannam@147: // promise.then(mvCapture(ptr, [](Own&& ptr, int result) { cannam@147: // return ptr->finish(result); cannam@147: // })); cannam@147: cannam@147: return CaptureByMove>(kj::fwd(func), kj::mv(param)); cannam@147: } cannam@147: cannam@147: // ======================================================================================= cannam@147: // Advanced promise construction cannam@147: cannam@147: template cannam@147: class PromiseFulfiller { cannam@147: // A callback which can be used to fulfill a promise. Only the first call to fulfill() or cannam@147: // reject() matters; subsequent calls are ignored. cannam@147: cannam@147: public: cannam@147: virtual void fulfill(T&& value) = 0; cannam@147: // Fulfill the promise with the given value. cannam@147: cannam@147: virtual void reject(Exception&& exception) = 0; cannam@147: // Reject the promise with an error. cannam@147: cannam@147: virtual bool isWaiting() = 0; cannam@147: // Returns true if the promise is still unfulfilled and someone is potentially waiting for it. cannam@147: // Returns false if fulfill()/reject() has already been called *or* if the promise to be cannam@147: // fulfilled has been discarded and therefore the result will never be used anyway. cannam@147: cannam@147: template cannam@147: bool rejectIfThrows(Func&& func); cannam@147: // Call the function (with no arguments) and return true. If an exception is thrown, call cannam@147: // `fulfiller.reject()` and then return false. When compiled with exceptions disabled, cannam@147: // non-fatal exceptions are still detected and handled correctly. cannam@147: }; cannam@147: cannam@147: template <> cannam@147: class PromiseFulfiller { cannam@147: // Specialization of PromiseFulfiller for void promises. See PromiseFulfiller. cannam@147: cannam@147: public: cannam@147: virtual void fulfill(_::Void&& value = _::Void()) = 0; cannam@147: // Call with zero parameters. The parameter is a dummy that only exists so that subclasses don't cannam@147: // have to specialize for . cannam@147: cannam@147: virtual void reject(Exception&& exception) = 0; cannam@147: virtual bool isWaiting() = 0; cannam@147: cannam@147: template cannam@147: bool rejectIfThrows(Func&& func); cannam@147: }; cannam@147: cannam@147: template cannam@147: Promise newAdaptedPromise(Params&&... adapterConstructorParams); cannam@147: // Creates a new promise which owns an instance of `Adapter` which encapsulates the operation cannam@147: // that will eventually fulfill the promise. This is primarily useful for adapting non-KJ cannam@147: // asynchronous APIs to use promises. cannam@147: // cannam@147: // An instance of `Adapter` will be allocated and owned by the returned `Promise`. A cannam@147: // `PromiseFulfiller&` will be passed as the first parameter to the adapter's constructor, cannam@147: // and `adapterConstructorParams` will be forwarded as the subsequent parameters. The adapter cannam@147: // is expected to perform some asynchronous operation and call the `PromiseFulfiller` once cannam@147: // it is finished. cannam@147: // cannam@147: // The adapter is destroyed when its owning Promise is destroyed. This may occur before the cannam@147: // Promise has been fulfilled. In this case, the adapter's destructor should cancel the cannam@147: // asynchronous operation. Once the adapter is destroyed, the fulfillment callback cannot be cannam@147: // called. cannam@147: // cannam@147: // An adapter implementation should be carefully written to ensure that it cannot accidentally cannam@147: // be left unfulfilled permanently because of an exception. Consider making liberal use of cannam@147: // `PromiseFulfiller::rejectIfThrows()`. cannam@147: cannam@147: template cannam@147: struct PromiseFulfillerPair { cannam@147: Promise<_::JoinPromises> promise; cannam@147: Own> fulfiller; cannam@147: }; cannam@147: cannam@147: template cannam@147: PromiseFulfillerPair newPromiseAndFulfiller(); cannam@147: // Construct a Promise and a separate PromiseFulfiller which can be used to fulfill the promise. cannam@147: // If the PromiseFulfiller is destroyed before either of its methods are called, the Promise is cannam@147: // implicitly rejected. cannam@147: // cannam@147: // Although this function is easier to use than `newAdaptedPromise()`, it has the serious drawback cannam@147: // that there is no way to handle cancellation (i.e. detect when the Promise is discarded). cannam@147: // cannam@147: // You can arrange to fulfill a promise with another promise by using a promise type for T. E.g. cannam@147: // `newPromiseAndFulfiller>()` will produce a promise of type `Promise` but the cannam@147: // fulfiller will be of type `PromiseFulfiller>`. Thus you pass a `Promise` to the cannam@147: // `fulfill()` callback, and the promises are chained. cannam@147: cannam@147: // ======================================================================================= cannam@147: // TaskSet cannam@147: cannam@147: class TaskSet { cannam@147: // Holds a collection of Promises and ensures that each executes to completion. Memory cannam@147: // associated with each promise is automatically freed when the promise completes. Destroying cannam@147: // the TaskSet itself automatically cancels all unfinished promises. cannam@147: // cannam@147: // This is useful for "daemon" objects that perform background tasks which aren't intended to cannam@147: // fulfill any particular external promise, but which may need to be canceled (and thus can't cannam@147: // use `Promise::detach()`). The daemon object holds a TaskSet to collect these tasks it is cannam@147: // working on. This way, if the daemon itself is destroyed, the TaskSet is detroyed as well, cannam@147: // and everything the daemon is doing is canceled. cannam@147: cannam@147: public: cannam@147: class ErrorHandler { cannam@147: public: cannam@147: virtual void taskFailed(kj::Exception&& exception) = 0; cannam@147: }; cannam@147: cannam@147: TaskSet(ErrorHandler& errorHandler); cannam@147: // `loop` will be used to wait on promises. `errorHandler` will be executed any time a task cannam@147: // throws an exception, and will execute within the given EventLoop. cannam@147: cannam@147: ~TaskSet() noexcept(false); cannam@147: cannam@147: void add(Promise&& promise); cannam@147: cannam@147: kj::String trace(); cannam@147: // Return debug info about all promises currently in the TaskSet. cannam@147: cannam@147: private: cannam@147: Own<_::TaskSetImpl> impl; cannam@147: }; cannam@147: cannam@147: // ======================================================================================= cannam@147: // The EventLoop class cannam@147: cannam@147: class EventPort { cannam@147: // Interfaces between an `EventLoop` and events originating from outside of the loop's thread. cannam@147: // All such events come in through the `EventPort` implementation. cannam@147: // cannam@147: // An `EventPort` implementation may interface with low-level operating system APIs and/or other cannam@147: // threads. You can also write an `EventPort` which wraps some other (non-KJ) event loop cannam@147: // framework, allowing the two to coexist in a single thread. cannam@147: cannam@147: public: cannam@147: virtual bool wait() = 0; cannam@147: // Wait for an external event to arrive, sleeping if necessary. Once at least one event has cannam@147: // arrived, queue it to the event loop (e.g. by fulfilling a promise) and return. cannam@147: // cannam@147: // This is called during `Promise::wait()` whenever the event queue becomes empty, in order to cannam@147: // wait for new events to populate the queue. cannam@147: // cannam@147: // It is safe to return even if nothing has actually been queued, so long as calling `wait()` in cannam@147: // a loop will eventually sleep. (That is to say, false positives are fine.) cannam@147: // cannam@147: // Returns true if wake() has been called from another thread. (Precisely, returns true if cannam@147: // no previous call to wait `wait()` nor `poll()` has returned true since `wake()` was last cannam@147: // called.) cannam@147: cannam@147: virtual bool poll() = 0; cannam@147: // Check if any external events have arrived, but do not sleep. If any events have arrived, cannam@147: // add them to the event queue (e.g. by fulfilling promises) before returning. cannam@147: // cannam@147: // This may be called during `Promise::wait()` when the EventLoop has been executing for a while cannam@147: // without a break but is still non-empty. cannam@147: // cannam@147: // Returns true if wake() has been called from another thread. (Precisely, returns true if cannam@147: // no previous call to wait `wait()` nor `poll()` has returned true since `wake()` was last cannam@147: // called.) cannam@147: cannam@147: virtual void setRunnable(bool runnable); cannam@147: // Called to notify the `EventPort` when the `EventLoop` has work to do; specifically when it cannam@147: // transitions from empty -> runnable or runnable -> empty. This is typically useful when cannam@147: // integrating with an external event loop; if the loop is currently runnable then you should cannam@147: // arrange to call run() on it soon. The default implementation does nothing. cannam@147: cannam@147: virtual void wake() const; cannam@147: // Wake up the EventPort's thread from another thread. cannam@147: // cannam@147: // Unlike all other methods on this interface, `wake()` may be called from another thread, hence cannam@147: // it is `const`. cannam@147: // cannam@147: // Technically speaking, `wake()` causes the target thread to cease sleeping and not to sleep cannam@147: // again until `wait()` or `poll()` has returned true at least once. cannam@147: // cannam@147: // The default implementation throws an UNIMPLEMENTED exception. cannam@147: }; cannam@147: cannam@147: class EventLoop { cannam@147: // Represents a queue of events being executed in a loop. Most code won't interact with cannam@147: // EventLoop directly, but instead use `Promise`s to interact with it indirectly. See the cannam@147: // documentation for `Promise`. cannam@147: // cannam@147: // Each thread can have at most one current EventLoop. To make an `EventLoop` current for cannam@147: // the thread, create a `WaitScope`. Async APIs require that the thread has a current EventLoop, cannam@147: // or they will throw exceptions. APIs that use `Promise::wait()` additionally must explicitly cannam@147: // be passed a reference to the `WaitScope` to make the caller aware that they might block. cannam@147: // cannam@147: // Generally, you will want to construct an `EventLoop` at the top level of your program, e.g. cannam@147: // in the main() function, or in the start function of a thread. You can then use it to cannam@147: // construct some promises and wait on the result. Example: cannam@147: // cannam@147: // int main() { cannam@147: // // `loop` becomes the official EventLoop for the thread. cannam@147: // MyEventPort eventPort; cannam@147: // EventLoop loop(eventPort); cannam@147: // cannam@147: // // Now we can call an async function. cannam@147: // Promise textPromise = getHttp("http://example.com"); cannam@147: // cannam@147: // // And we can wait for the promise to complete. Note that you can only use `wait()` cannam@147: // // from the top level, not from inside a promise callback. cannam@147: // String text = textPromise.wait(); cannam@147: // print(text); cannam@147: // return 0; cannam@147: // } cannam@147: // cannam@147: // Most applications that do I/O will prefer to use `setupAsyncIo()` from `async-io.h` rather cannam@147: // than allocate an `EventLoop` directly. cannam@147: cannam@147: public: cannam@147: EventLoop(); cannam@147: // Construct an `EventLoop` which does not receive external events at all. cannam@147: cannam@147: explicit EventLoop(EventPort& port); cannam@147: // Construct an `EventLoop` which receives external events through the given `EventPort`. cannam@147: cannam@147: ~EventLoop() noexcept(false); cannam@147: cannam@147: void run(uint maxTurnCount = maxValue); cannam@147: // Run the event loop for `maxTurnCount` turns or until there is nothing left to be done, cannam@147: // whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will cannam@147: // call the `EventPort`'s `setRunnable(false)` if the queue becomes empty. cannam@147: cannam@147: bool isRunnable(); cannam@147: // Returns true if run() would currently do anything, or false if the queue is empty. cannam@147: cannam@147: private: cannam@147: EventPort& port; cannam@147: cannam@147: bool running = false; cannam@147: // True while looping -- wait() is then not allowed. cannam@147: cannam@147: bool lastRunnableState = false; cannam@147: // What did we last pass to port.setRunnable()? cannam@147: cannam@147: _::Event* head = nullptr; cannam@147: _::Event** tail = &head; cannam@147: _::Event** depthFirstInsertPoint = &head; cannam@147: cannam@147: Own<_::TaskSetImpl> daemons; cannam@147: cannam@147: bool turn(); cannam@147: void setRunnable(bool runnable); cannam@147: void enterScope(); cannam@147: void leaveScope(); cannam@147: cannam@147: friend void _::detach(kj::Promise&& promise); cannam@147: friend void _::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, cannam@147: WaitScope& waitScope); cannam@147: friend class _::Event; cannam@147: friend class WaitScope; cannam@147: }; cannam@147: cannam@147: class WaitScope { cannam@147: // Represents a scope in which asynchronous programming can occur. A `WaitScope` should usually cannam@147: // be allocated on the stack and serves two purposes: cannam@147: // * While the `WaitScope` exists, its `EventLoop` is registered as the current loop for the cannam@147: // thread. Most operations dealing with `Promise` (including all of its methods) do not work cannam@147: // unless the thread has a current `EventLoop`. cannam@147: // * `WaitScope` may be passed to `Promise::wait()` to synchronously wait for a particular cannam@147: // promise to complete. See `Promise::wait()` for an extended discussion. cannam@147: cannam@147: public: cannam@147: inline explicit WaitScope(EventLoop& loop): loop(loop) { loop.enterScope(); } cannam@147: inline ~WaitScope() { loop.leaveScope(); } cannam@147: KJ_DISALLOW_COPY(WaitScope); cannam@147: cannam@147: private: cannam@147: EventLoop& loop; cannam@147: friend class EventLoop; cannam@147: friend void _::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, cannam@147: WaitScope& waitScope); cannam@147: }; cannam@147: cannam@147: } // namespace kj cannam@147: cannam@147: #include "async-inl.h" cannam@147: cannam@147: #endif // KJ_ASYNC_H_