race in Future destructor
[folly.git] / folly / wangle / Future-inl.h
1 /*
2  * Copyright 2014 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 "detail.h"
20
21 namespace folly { namespace wangle {
22
23 template <typename T>
24 struct isFuture {
25   static const bool value = false;
26 };
27
28 template <typename T>
29 struct isFuture<Future<T> > {
30   static const bool value = true;
31 };
32
33 template <class T>
34 Future<T>::Future(Future<T>&& other) : obj_(other.obj_) {
35   other.obj_ = nullptr;
36 }
37
38 template <class T>
39 Future<T>& Future<T>::operator=(Future<T>&& other) {
40   std::swap(obj_, other.obj_);
41   return *this;
42 }
43
44 template <class T>
45 Future<T>::~Future() {
46   if (obj_) {
47     setContinuation([](Try<T>&&) {}); // detach
48   }
49 }
50
51 template <class T>
52 void Future<T>::throwIfInvalid() const {
53   if (!obj_)
54     throw NoState();
55 }
56
57 template <class T>
58 template <class F>
59 void Future<T>::setContinuation(F&& func) {
60   throwIfInvalid();
61   obj_->setContinuation(std::move(func));
62   obj_ = nullptr;
63 }
64
65 template <class T>
66 template <class F>
67 typename std::enable_if<
68   !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
69   Future<typename std::result_of<F(Try<T>&&)>::type> >::type
70 Future<T>::then(F&& func) {
71   typedef typename std::result_of<F(Try<T>&&)>::type B;
72
73   throwIfInvalid();
74
75   // wrap these so we can move them into the lambda
76   folly::MoveWrapper<Promise<B>> p;
77   folly::MoveWrapper<F> funcm(std::forward<F>(func));
78
79   // grab the Future now before we lose our handle on the Promise
80   auto f = p->getFuture();
81
82   /* This is a bit tricky.
83
84      We can't just close over *this in case this Future gets moved. So we
85      make a new dummy Future. We could figure out something more
86      sophisticated that avoids making a new Future object when it can, as an
87      optimization. But this is correct.
88
89      obj_ can't be moved, it is explicitly disallowed (as is copying). But
90      if there's ever a reason to allow it, this is one place that makes that
91      assumption and would need to be fixed. We use a standard shared pointer
92      for obj_ (by copying it in), which means in essence obj holds a shared
93      pointer to itself.  But this shouldn't leak because Promise will not
94      outlive the continuation, because Promise will setException() with a
95      broken Promise if it is destructed before completed. We could use a
96      weak pointer but it would have to be converted to a shared pointer when
97      func is executed (because the Future returned by func may possibly
98      persist beyond the callback, if it gets moved), and so it is an
99      optimization to just make it shared from the get-go.
100
101      We have to move in the Promise and func using the MoveWrapper
102      hack. (func could be copied but it's a big drag on perf).
103
104      Two subtle but important points about this design. FutureObject has no
105      back pointers to Future or Promise, so if Future or Promise get moved
106      (and they will be moved in performant code) we don't have to do
107      anything fancy. And because we store the continuation in the
108      FutureObject, not in the Future, we can execute the continuation even
109      after the Future has gone out of scope. This is an intentional design
110      decision. It is likely we will want to be able to cancel a continuation
111      in some circumstances, but I think it should be explicit not implicit
112      in the destruction of the Future used to create it.
113      */
114   setContinuation(
115     [p, funcm](Try<T>&& t) mutable {
116       p->fulfil([&]() {
117           return (*funcm)(std::move(t));
118         });
119     });
120
121   return std::move(f);
122 }
123
124 template <class T>
125 template <class F>
126 typename std::enable_if<
127   isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
128   Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
129 Future<T>::then(F&& func) {
130   typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
131
132   throwIfInvalid();
133
134   // wrap these so we can move them into the lambda
135   folly::MoveWrapper<Promise<B>> p;
136   folly::MoveWrapper<F> funcm(std::forward<F>(func));
137
138   // grab the Future now before we lose our handle on the Promise
139   auto f = p->getFuture();
140
141   setContinuation(
142     [p, funcm](Try<T>&& t) mutable {
143       try {
144         auto f2 = (*funcm)(std::move(t));
145         // that didn't throw, now we can steal p
146         f2.setContinuation([p](Try<B>&& b) mutable {
147             p->fulfilTry(std::move(b));
148           });
149       } catch (...) {
150         p->setException(std::current_exception());
151       }
152     });
153
154   return std::move(f);
155 }
156
157 template <class T>
158 Future<void> Future<T>::then() {
159   return then([] (Try<T>&& t) {});
160 }
161
162 template <class T>
163 typename std::add_lvalue_reference<T>::type Future<T>::value() {
164   throwIfInvalid();
165
166   return obj_->value();
167 }
168
169 template <class T>
170 typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
171   throwIfInvalid();
172
173   return obj_->value();
174 }
175
176 template <class T>
177 Try<T>& Future<T>::getTry() {
178   throwIfInvalid();
179
180   return obj_->getTry();
181 }
182
183 template <class T>
184 template <typename Executor>
185 inline Future<T> Future<T>::via(Executor* executor) {
186   throwIfInvalid();
187
188   folly::MoveWrapper<Promise<T>> p;
189   auto f = p->getFuture();
190
191   setContinuation([executor, p](Try<T>&& t) mutable {
192       folly::MoveWrapper<Try<T>> tt(std::move(t));
193       executor->add([p, tt]() mutable {
194           p->fulfilTry(std::move(*tt));
195         });
196     });
197
198   return f;
199 }
200
201 template <class T>
202 template <typename Executor>
203 inline void Future<T>::executeWith(
204     Executor* executor, Promise<T>&& cont_promise) {
205   throwIfInvalid();
206
207   folly::MoveWrapper<Promise<T>> p(std::move(cont_promise));
208
209   setContinuation([executor, p](Try<T>&& t) mutable {
210       folly::MoveWrapper<Try<T>> tt(std::move(t));
211       executor->add([p, tt]() mutable {
212           p->fulfilTry(std::move(*tt));
213         });
214     });
215 }
216
217 template <class T>
218 bool Future<T>::isReady() const {
219   throwIfInvalid();
220   return obj_->ready();
221 }
222
223 // makeFuture
224
225 template <class T>
226 Future<typename std::decay<T>::type> makeFuture(T&& t) {
227   Promise<typename std::decay<T>::type> p;
228   auto f = p.getFuture();
229   p.setValue(std::forward<T>(t));
230   return std::move(f);
231 }
232
233 inline // for multiple translation units
234 Future<void> makeFuture() {
235   Promise<void> p;
236   auto f = p.getFuture();
237   p.setValue();
238   return std::move(f);
239 }
240
241 template <class F>
242 auto makeFutureTry(
243     F&& func,
244     typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
245     -> Future<decltype(func())> {
246   Promise<decltype(func())> p;
247   auto f = p.getFuture();
248   p.fulfil(
249     [&func]() {
250       return (func)();
251     });
252   return std::move(f);
253 }
254
255 template <class F>
256 auto makeFutureTry(F const& func) -> Future<decltype(func())> {
257   F copy = func;
258   return makeFutureTry(std::move(copy));
259 }
260
261 template <class T>
262 Future<T> makeFuture(std::exception_ptr const& e) {
263   Promise<T> p;
264   auto f = p.getFuture();
265   p.setException(e);
266   return std::move(f);
267 }
268
269 template <class T, class E>
270 typename std::enable_if<std::is_base_of<std::exception, E>::value, Future<T>>::type
271 makeFuture(E const& e) {
272   Promise<T> p;
273   auto f = p.getFuture();
274   p.fulfil([&]() -> T { throw e; });
275   return std::move(f);
276 }
277
278 // when (variadic)
279
280 template <typename... Fs>
281 typename detail::VariadicContext<
282   typename std::decay<Fs>::type::value_type...>::type
283 whenAll(Fs&&... fs)
284 {
285   auto ctx =
286     new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
287   ctx->total = sizeof...(fs);
288   auto f_saved = ctx->p.getFuture();
289   detail::whenAllVariadicHelper(ctx,
290     std::forward<typename std::decay<Fs>::type>(fs)...);
291   return std::move(f_saved);
292 }
293
294 // when (iterator)
295
296 template <class InputIterator>
297 Future<
298   std::vector<
299   Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
300 whenAll(InputIterator first, InputIterator last)
301 {
302   typedef
303     typename std::iterator_traits<InputIterator>::value_type::value_type T;
304
305   auto n = std::distance(first, last);
306   if (n == 0)
307     return makeFuture<std::vector<Try<T>>>({});
308
309   auto ctx = new detail::WhenAllContext<T>();
310
311   ctx->total = n;
312   ctx->results.resize(ctx->total);
313
314   auto f_saved = ctx->p.getFuture();
315
316   for (size_t i = 0; first != last; ++first, ++i) {
317      auto& f = *first;
318      f.setContinuation([ctx, i](Try<T>&& t) {
319          ctx->results[i] = std::move(t);
320          if (++ctx->count == ctx->total) {
321            ctx->p.setValue(std::move(ctx->results));
322            delete ctx;
323          }
324        });
325   }
326
327   return std::move(f_saved);
328 }
329
330 template <class InputIterator>
331 Future<
332   std::pair<size_t,
333             Try<
334               typename
335               std::iterator_traits<InputIterator>::value_type::value_type> > >
336 whenAny(InputIterator first, InputIterator last) {
337   typedef
338     typename std::iterator_traits<InputIterator>::value_type::value_type T;
339
340   auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
341   auto f_saved = ctx->p.getFuture();
342
343   for (size_t i = 0; first != last; first++, i++) {
344     auto& f = *first;
345     f.setContinuation([i, ctx](Try<T>&& t) {
346       if (!ctx->done.exchange(true)) {
347         ctx->p.setValue(std::make_pair(i, std::move(t)));
348       }
349       ctx->decref();
350     });
351   }
352
353   return std::move(f_saved);
354 }
355
356 template <class InputIterator>
357 Future<std::vector<std::pair<size_t, Try<typename
358   std::iterator_traits<InputIterator>::value_type::value_type>>>>
359 whenN(InputIterator first, InputIterator last, size_t n) {
360   typedef typename
361     std::iterator_traits<InputIterator>::value_type::value_type T;
362   typedef std::vector<std::pair<size_t, Try<T>>> V;
363
364   struct ctx_t {
365     V v;
366     size_t completed;
367     Promise<V> p;
368   };
369   auto ctx = std::make_shared<ctx_t>();
370   ctx->completed = 0;
371
372   // for each completed Future, increase count and add to vector, until we
373   // have n completed futures at which point we fulfil our Promise with the
374   // vector
375   auto it = first;
376   size_t i = 0;
377   while (it != last) {
378     it->then([ctx, n, i](Try<T>&& t) {
379       auto& v = ctx->v;
380       auto c = ++ctx->completed;
381       if (c <= n) {
382         assert(ctx->v.size() < n);
383         v.push_back(std::make_pair(i, std::move(t)));
384         if (c == n) {
385           ctx->p.fulfilTry(Try<V>(std::move(v)));
386         }
387       }
388     });
389
390     it++;
391     i++;
392   }
393
394   if (i < n) {
395     ctx->p.setException(std::runtime_error("Not enough futures"));
396   }
397
398   return ctx->p.getFuture();
399 }
400
401 }}
402
403 // I haven't included a Future<T&> specialization because I don't forsee us
404 // using it, however it is not difficult to add when needed. Refer to
405 // Future<void> for guidance. std::future and boost::future code would also be
406 // instructive.