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 | |
26 | namespace folly { |
27 | |
28 | class FOLLY_EXPORT PromiseException : public std::logic_error { |
29 | public: |
30 | using std::logic_error::logic_error; |
31 | }; |
32 | |
33 | class FOLLY_EXPORT PromiseInvalid : public PromiseException { |
34 | public: |
35 | PromiseInvalid() : PromiseException("Promise invalid" ) {} |
36 | }; |
37 | |
38 | class FOLLY_EXPORT PromiseAlreadySatisfied : public PromiseException { |
39 | public: |
40 | PromiseAlreadySatisfied() : PromiseException("Promise already satisfied" ) {} |
41 | }; |
42 | |
43 | class FOLLY_EXPORT FutureAlreadyRetrieved : public PromiseException { |
44 | public: |
45 | FutureAlreadyRetrieved() : PromiseException("Future already retrieved" ) {} |
46 | }; |
47 | |
48 | class 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 |
57 | template <class T> |
58 | class SemiFuture; |
59 | template <class T> |
60 | class Future; |
61 | |
62 | namespace futures { |
63 | namespace detail { |
64 | template <class T> |
65 | class FutureBase; |
66 | struct EmptyConstruct {}; |
67 | template <typename T, typename F> |
68 | class 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. |
142 | template <class T> |
143 | class 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 | |