1/*
2 * Copyright 2014-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <functional>
20
21#include <folly/Portability.h>
22#include <folly/Try.h>
23#include <folly/futures/detail/Core.h>
24#include <folly/lang/Exception.h>
25
26namespace folly {
27
28class FOLLY_EXPORT PromiseException : public std::logic_error {
29 public:
30 using std::logic_error::logic_error;
31};
32
33class FOLLY_EXPORT PromiseInvalid : public PromiseException {
34 public:
35 PromiseInvalid() : PromiseException("Promise invalid") {}
36};
37
38class FOLLY_EXPORT PromiseAlreadySatisfied : public PromiseException {
39 public:
40 PromiseAlreadySatisfied() : PromiseException("Promise already satisfied") {}
41};
42
43class FOLLY_EXPORT FutureAlreadyRetrieved : public PromiseException {
44 public:
45 FutureAlreadyRetrieved() : PromiseException("Future already retrieved") {}
46};
47
48class FOLLY_EXPORT BrokenPromise : public PromiseException {
49 public:
50 explicit BrokenPromise(const std::string& type)
51 : PromiseException("Broken promise for type name `" + type + '`') {}
52
53 explicit BrokenPromise(const char* type) : BrokenPromise(std::string(type)) {}
54};
55
56// forward declaration
57template <class T>
58class SemiFuture;
59template <class T>
60class Future;
61
62namespace futures {
63namespace detail {
64template <class T>
65class FutureBase;
66struct EmptyConstruct {};
67template <typename T, typename F>
68class CoreCallbackState;
69} // namespace detail
70} // namespace futures
71
72/// Promises and futures provide a potentially nonblocking mechanism
73/// to execute a producer/consumer operation concurrently, with
74/// threading/pools controlled via an executor. There are multiple potential
75/// patterns for using promises and futures including some that block the
76/// caller, though that is discouraged; it should be used only when necessary.
77///
78/// One typical pattern uses a series of calls to set up a small, limited
79/// program that...
80///
81/// - ...performs the desired operations (based on a lambda)...
82/// - ...on an asynchronously provided input (an exception or a value)...
83/// - ...lazily, when that input is ready (without blocking the caller)...
84/// - ...using appropriate execution resources (determined by the executor)...
85/// - ...then after constructing the 'program,' launches the asynchronous
86/// producer.
87///
88/// That usage pattern looks roughly like this:
89///
90/// auto [p, f] = makePromiseContract(executor);
91/// g = std::move(f).then([](MyValue&& x) {
92/// ...executor runs this code if/when a MyValue is ready...
93/// });
94/// ...launch the async producer that eventually calls p.setResult()...
95///
96/// This is just one of many potential usage patterns. It has the desired
97/// property of being nonblocking to the caller. Of course the `.then()`
98/// code is deferred until the produced value (or exception) is ready,
99/// but no code actually blocks pending completion of other operations.
100///
101/// The promise/future mechanism is limited to a single object of some arbitrary
102/// type. It also supports a (logically) void result, i.e., in cases where the
103/// continuation/consumer (the `.then()` code if using the above pattern) is not
104/// expecting a value because the 'producer' is running for its side-effects.
105///
106/// The primary data movement is from producer to consumer, however Promise and
107/// Future also provide a mechanism where the consumer can send an interruption
108/// message to the producer. The meaning and response to that interruption
109/// message is controlled by the promise; see `Promise::setInterruptHandler()`.
110///
111/// Neither Promise nor Future is thread-safe. All internal interactions
112/// between a promise and its associated future are thread-safe, provided that
113/// callers otherwise honor the promise's contract and the future's contract.
114///
115/// Logically there are up to three threads (though in practice there are often
116/// fewer - one thread might take on more than one role):
117///
118/// - Set-up thread: thread used to construct the Promise, and often also to
119/// set up the SemiFuture/Future.
120/// - Producer thread: thread that produces the result.
121/// - Consumer thread: thread in which the continuation is invoked (a
122/// continuation is a callback provided to `.then` or to a variant).
123///
124/// For description purposes, the term 'shared state' is used to describe the
125/// logical state shared by the promise and the future. This 'third object'
126/// represents things like whether the result has been fulfilled, the value or
127/// exception in that result, and the data needed to handle interruption
128/// requests.
129///
130/// A promise can be in various logical states:
131///
132/// - valid vs. invalid (has vs. does not have a shared state, respectfully).
133/// - fulfilled vs. unfulfilled (an invalid promise is always fulfilled; a valid
134/// promise is fulfilled if the shared-state has a result).
135///
136/// A promise `p` may optionally have an associated future. This future, if it
137/// exists, may be either a SemiFuture or a Future, and is defined as the
138/// future (if any) that holds the same shared state as promise `p`.
139/// The associated future is initially the future returned from
140/// `p.getFuture()` or `p.getSemiFuture()`, but various operations
141/// may transfer the shared state from one future to another.
142template <class T>
143class Promise {
144 public:
145 /// Returns an invalid promise.
146 ///
147 /// Postconditions:
148 ///
149 /// - `RESULT.valid() == false`
150 /// - `RESULT.isFulfilled() == true`
151 static Promise<T> makeEmpty() noexcept;
152
153 /// Constructs a valid but unfulfilled promise.
154 ///
155 /// Postconditions:
156 ///
157 /// - `valid() == true` (it will have a shared state)
158 /// - `isFulfilled() == false` (its shared state won't have a result)
159 Promise();
160
161 /// Postconditions:
162 ///
163 /// - If `valid()` and `!isFulfilled()`, the associated future (if any) will
164 /// be completed with a `BrokenPromise` exception *as if* by
165 /// `setException(...)`.
166 /// - If `valid()`, releases, possibly destroying, the shared state.
167 ~Promise();
168
169 // not copyable
170 Promise(Promise const&) = delete;
171 Promise& operator=(Promise const&) = delete;
172
173 /// Move ctor
174 ///
175 /// Postconditions:
176 ///
177 /// - `this` will have whatever shared-state was previously held by `other`
178 /// (if any)
179 /// - `other.valid()` will be false (`other` will not have any shared state)
180 Promise(Promise<T>&& other) noexcept;
181
182 /// Move assignment
183 ///
184 /// Postconditions:
185 ///
186 /// - If `valid()` and `!isFulfilled()`, the associated future (if any) will
187 /// be completed with a `BrokenPromise` exception *as if* by
188 /// `setException(...)`.
189 /// - If `valid()`, releases, possibly destroying, the original shared state.
190 /// - `this` will have whatever shared-state was previously held by `other`
191 /// (if any)
192 /// - `other.valid()` will be false (`other` will not have any shared state)
193 Promise& operator=(Promise<T>&& other) noexcept;
194
195 /// Return a SemiFuture associated with this Promise, sharing the same shared
196 /// state as `this`.
197 ///
198 /// Preconditions:
199 ///
200 /// - `valid() == true` (else throws PromiseInvalid)
201 /// - neither getSemiFuture() nor getFuture() may have been called previously
202 /// on `this` Promise (else throws FutureAlreadyRetrieved)
203 ///
204 /// Postconditions:
205 ///
206 /// - `RESULT.valid() == true`
207 /// - RESULT will share the same shared-state as `this`
208 ///
209 /// DEPRECATED: use `folly::makePromiseContract()` instead.
210 SemiFuture<T> getSemiFuture();
211
212 /// Return a Future associated with this Promise, sharing the same shared
213 /// state as `this`.
214 ///
215 /// Preconditions:
216 ///
217 /// - `valid() == true` (else throws PromiseInvalid)
218 /// - neither getSemiFuture() nor getFuture() may have been called previously
219 /// on `this` Promise (else throws FutureAlreadyRetrieved)
220 ///
221 /// Postconditions:
222 ///
223 /// - `RESULT.valid() == true`
224 /// - RESULT will share the same shared-state as `this`
225 ///
226 /// DEPRECATED: use `folly::makePromiseContract()` instead. If you can't use
227 /// that, use `this->getSemiFuture()` then get a Future by calling `.via()`
228 /// with an appropriate executor.
229 Future<T> getFuture();
230
231 /// Fulfill the Promise with an exception_wrapper.
232 ///
233 /// Sample usage:
234 ///
235 /// Promise<MyValue> p = ...
236 /// ...
237 /// auto const ep = std::exception_ptr();
238 /// auto const ew = exception_wrapper::from_exception_ptr(ep);
239 /// p.setException(ew);
240 ///
241 /// Functionally equivalent to `setTry(Try<T>(std::move(ew)))`
242 ///
243 /// Preconditions:
244 ///
245 /// - `valid() == true` (else throws PromiseInvalid)
246 /// - `isFulfilled() == false` (else throws PromiseAlreadySatisfied)
247 ///
248 /// Postconditions:
249 ///
250 /// - `isFulfilled() == true`
251 /// - `valid() == true` (unchanged)
252 /// - The associated future (if any) will complete with the exception.
253 void setException(exception_wrapper ew);
254
255 /// Fulfill the Promise with exception `e` *as if* by
256 /// `setException(make_exception_wrapper<E>(e))`.
257 ///
258 /// Please see `setException(exception_wrapper)` for semantics/contract.
259 template <class E>
260 typename std::enable_if<std::is_base_of<std::exception, E>::value>::type
261 setException(E const& e);
262
263 /// Sets a handler for the producer to receive a (logical) interruption
264 /// request (exception) sent from the consumer via `future.raise()`.
265 ///
266 /// Details: The consumer calls `future.raise()` when it wishes to send a
267 /// logical interruption message (an exception), and that exception/message
268 /// is passed to `fn()`. The thread used to call `fn()` depends on timing
269 /// (see Postconditions for threading details).
270 ///
271 /// Handler `fn()` can do anything you want, but if you bother to set one
272 /// then you probably will want to (more or less immediately) fulfill the
273 /// promise with an exception (or other special value) indicating how the
274 /// interrupt was handled.
275 ///
276 /// This call silently does nothing if `isFulfilled()`.
277 ///
278 /// Preconditions:
279 ///
280 /// - `valid() == true` (else throws PromiseInvalid)
281 /// - `fn` must be copyable and must be invocable with
282 /// `exception_wrapper const&`
283 /// - the code within `fn()` must be safe to run either synchronously within
284 /// the `setInterruptHandler()` call or asynchronously within the consumer
285 /// thread's call to `future.raise()`.
286 /// - the code within `fn()` must also be safe to run after this promise is
287 /// fulfilled; this may have lifetime/race-case ramifications, e.g., if the
288 /// code of `fn()` might access producer-resources that will be destroyed,
289 /// then the destruction of those producer-resources must be deferred beyond
290 /// the moment when this promise is fulfilled.
291 ///
292 /// Postconditions:
293 ///
294 /// - if the consumer calls `future.raise()` early enough (up to a particular
295 /// moment within the `setInterruptHandler()` call), `fn()` will be called
296 /// synchronously (in the current thread, during this call).
297 /// - if the consumer calls `future.raise()` after that moment within
298 /// `setInterruptHandler()` but before this promise is fulfilled, `fn()`
299 /// will be called asynchronously (in the consumer's thread, within the call
300 /// to `future.raise()`).
301 /// - if the consumer calls `future.raise()` after this promise is fulfilled,
302 /// `fn()` may or may not be called at all, and if it is called, it will be
303 /// called asynchronously (within the consumer's call to `future.raise()`).
304 ///
305 /// IMPORTANT: `fn()` should return quickly since it could block this call
306 /// to `promise.setInterruptHandler()` and/or a concurrent call to
307 /// `future.raise()`. Those two functions contend on the same lock; those
308 /// calls could block if `fn()` is invoked within one of those while the
309 /// lock is held.
310 template <typename F>
311 void setInterruptHandler(F&& fn);
312
313 /// Fulfills a (logically) void Promise, that is, Promise<Unit>.
314 /// (If you want a void-promise, use Promise<Unit>, not Promise<void>.)
315 ///
316 /// Preconditions:
317 ///
318 /// - `valid() == true` (else throws PromiseInvalid)
319 /// - `isFulfilled() == false` (else throws PromiseAlreadySatisfied)
320 ///
321 /// Postconditions:
322 ///
323 /// - `isFulfilled() == true`
324 /// - `valid() == true` (unchanged)
325 template <class B = T>
326 typename std::enable_if<std::is_same<Unit, B>::value, void>::type setValue() {
327 setTry(Try<T>(T()));
328 }
329
330 /// Fulfill the Promise with the specified value using perfect forwarding.
331 ///
332 /// Functionally equivalent to `setTry(Try<T>(std::forward<M>(value)))`
333 ///
334 /// Preconditions:
335 ///
336 /// - `valid() == true` (else throws PromiseInvalid)
337 /// - `isFulfilled() == false` (else throws PromiseAlreadySatisfied)
338 ///
339 /// Postconditions:
340 ///
341 /// - `isFulfilled() == true`
342 /// - `valid() == true` (unchanged)
343 /// - The associated future will see the value, e.g., in its continuation.
344 template <class M>
345 void setValue(M&& value);
346
347 /// Fulfill the Promise with the specified Try (value or exception).
348 ///
349 /// Preconditions:
350 ///
351 /// - `valid() == true` (else throws PromiseInvalid)
352 /// - `isFulfilled() == false` (else throws PromiseAlreadySatisfied)
353 ///
354 /// Postconditions:
355 ///
356 /// - `isFulfilled() == true`
357 /// - `valid() == true` (unchanged)
358 /// - The associated future will see the result, e.g., in its continuation.
359 void setTry(Try<T>&& t);
360
361 /// Fulfill this Promise with the result of a function that takes no
362 /// arguments and returns something implicitly convertible to T.
363 ///
364 /// Example:
365 ///
366 /// p.setWith([] { do something that may throw; return a T; });
367 ///
368 /// Functionally equivalent to `setTry(makeTryWith(static_cast<F&&>(func)));`
369 ///
370 /// Preconditions:
371 ///
372 /// - `valid() == true` (else throws PromiseInvalid)
373 /// - `isFulfilled() == false` (else throws PromiseAlreadySatisfied)
374 ///
375 /// Postconditions:
376 ///
377 /// - `func()` will be run synchronously (in this thread, during this call)
378 /// - If `func()` returns, the return value will be captured as if via
379 /// `setValue()`
380 /// - If `func()` throws, the exception will be captured as if via
381 /// `setException()`
382 /// - `isFulfilled() == true`
383 /// - `valid() == true` (unchanged)
384 /// - The associated future will see the result, e.g., in its continuation.
385 template <class F>
386 void setWith(F&& func);
387
388 /// true if this has a shared state;
389 /// false if this has been consumed/moved-out.
390 bool valid() const noexcept {
391 return core_ != nullptr;
392 }
393
394 /// True if either this promise was fulfilled or is invalid.
395 ///
396 /// - True if `!valid()`
397 /// - True if `valid()` and this was fulfilled (a prior call to `setValue()`,
398 /// `setTry()`, `setException()`, or `setWith()`)
399 bool isFulfilled() const noexcept;
400
401 private:
402 template <class>
403 friend class futures::detail::FutureBase;
404 template <class>
405 friend class SemiFuture;
406 template <class>
407 friend class Future;
408 template <class, class>
409 friend class futures::detail::CoreCallbackState;
410
411 // Whether the Future has been retrieved (a one-time operation).
412 bool retrieved_;
413
414 using Core = futures::detail::Core<T>;
415
416 // Throws PromiseInvalid if there is no shared state object; else returns it
417 // by ref.
418 //
419 // Implementation methods should usually use this instead of `this->core_`.
420 // The latter should be used only when you need the possibly-null pointer.
421 Core& getCore() {
422 return getCoreImpl(core_);
423 }
424 Core const& getCore() const {
425 return getCoreImpl(core_);
426 }
427
428 template <typename CoreT>
429 static CoreT& getCoreImpl(CoreT* core) {
430 if (!core) {
431 throw_exception<PromiseInvalid>();
432 }
433 return *core;
434 }
435
436 // shared core state object
437 // usually you should use `getCore()` instead of directly accessing `core_`.
438 Core* core_;
439
440 explicit Promise(futures::detail::EmptyConstruct) noexcept;
441
442 void throwIfFulfilled() const;
443 void detach();
444};
445
446} // namespace folly
447
448#include <folly/futures/Future.h>
449#include <folly/futures/Promise-inl.h>
450