Seastar
High performance C++ framework for concurrent servers
future.hh
1 /*
2  * This file is open source software, licensed to you under the terms
3  * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4  * distributed with this work for additional information regarding copyright
5  * ownership. You may not use this file except in compliance with the License.
6  *
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing,
12  * software distributed under the License is distributed on an
13  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14  * KIND, either express or implied. See the License for the
15  * specific language governing permissions and limitations
16  * under the License.
17  */
18 /*
19  * Copyright (C) 2015 Cloudius Systems, Ltd.
20  */
21 
22 #pragma once
23 
24 #include <seastar/core/task.hh>
25 #include <seastar/core/thread_impl.hh>
26 #include <stdexcept>
27 #include <atomic>
28 #include <memory>
29 #include <type_traits>
30 #include <assert.h>
31 #include <cstdlib>
32 #include <seastar/core/function_traits.hh>
33 #include <seastar/util/critical_alloc_section.hh>
34 #include <seastar/util/attribute-compat.hh>
35 #include <seastar/util/concepts.hh>
36 #include <seastar/util/noncopyable_function.hh>
37 #include <seastar/util/backtrace.hh>
38 #include <seastar/util/std-compat.hh>
39 
40 #if __cplusplus > 201703L
41 #include <concepts>
42 #endif
43 
44 namespace seastar {
45 
46 struct nested_exception : public std::exception {
47  std::exception_ptr inner;
48  std::exception_ptr outer;
49  nested_exception(std::exception_ptr inner, std::exception_ptr outer) noexcept;
51  nested_exception(const nested_exception&) noexcept;
52  [[noreturn]] void rethrow_nested() const;
53  virtual const char* what() const noexcept override;
54 };
55 
79 
136 
142 
143 
146 
147 #if SEASTAR_API_LEVEL < 6
148 template <class... T>
149 #else
150 template <class T = void>
151 #endif
152 class promise;
153 
154 template <class SEASTAR_ELLIPSIS T>
155 class future;
156 
157 template <typename... T>
158 class shared_future;
159 
160 struct future_state_base;
161 
168 template <typename... T, typename... A>
169 future<T...> make_ready_future(A&&... value) noexcept;
170 
177 template <typename... T>
178 future<T...> make_exception_future(std::exception_ptr&& value) noexcept;
179 
180 template <typename... T>
181 future<T...> make_exception_future(const std::exception_ptr& ex) noexcept {
182  return make_exception_future<T...>(std::exception_ptr(ex));
183 }
184 
185 template <typename... T>
186 future<T...> make_exception_future(std::exception_ptr& ex) noexcept {
187  return make_exception_future<T...>(static_cast<const std::exception_ptr&>(ex));
188 }
189 
190 template <typename... T>
191 future<T...> make_exception_future(const std::exception_ptr&& ex) noexcept {
192  // as ex is const, we cannot move it, but can copy it.
193  return make_exception_future<T...>(std::exception_ptr(ex));
194 }
195 
197 void engine_exit(std::exception_ptr eptr = {});
198 
199 void report_failed_future(const std::exception_ptr& ex) noexcept;
200 
201 void report_failed_future(const future_state_base& state) noexcept;
202 
203 void with_allow_abandoned_failed_futures(unsigned count, noncopyable_function<void ()> func);
204 
206 
213 struct broken_promise : std::logic_error {
214  broken_promise();
215 };
216 
222 template <typename... T>
223 future<T...> current_exception_as_future() noexcept;
224 
225 extern template
227 
228 namespace internal {
229 #if SEASTAR_API_LEVEL < 6
230 template <class... T>
231 #else
232 template <class T = void>
233 #endif
234 class promise_base_with_type;
235 class promise_base;
236 
237 struct monostate {};
238 
239 template <typename... T>
240 struct future_stored_type;
241 
242 template <>
243 struct future_stored_type<> {
244 #if SEASTAR_API_LEVEL < 5
245  using type = std::tuple<>;
246 #else
247  using type = monostate;
248 #endif
249 };
250 
251 template <typename T>
252 struct future_stored_type<T> {
253 #if SEASTAR_API_LEVEL < 5
254  using type = std::tuple<T>;
255 #else
256  using type = std::conditional_t<std::is_void_v<T>, internal::monostate, T>;
257 #endif
258 };
259 
260 template <typename... T>
261 using future_stored_type_t = typename future_stored_type<T...>::type;
262 
263 template<typename T>
264 #if SEASTAR_API_LEVEL < 5
265 using future_tuple_type_t = T;
266 #else
267 using future_tuple_type_t = std::conditional_t<std::is_same_v<T, monostate>, std::tuple<>, std::tuple<T>>;
268 #endif
269 
270 // It doesn't seem to be possible to use std::tuple_element_t with an empty tuple. There is an static_assert in it that
271 // fails the build even if it is in the non enabled side of std::conditional.
272 template <typename T>
273 struct get0_return_type;
274 
275 template <>
276 struct get0_return_type<std::tuple<>> {
277  using type = void;
278  static type get0(std::tuple<>) { }
279 };
280 
281 template <typename T0, typename... T>
282 struct get0_return_type<std::tuple<T0, T...>> {
283  using type = T0;
284  static type get0(std::tuple<T0, T...> v) { return std::get<0>(std::move(v)); }
285 };
286 
287 template<typename T>
288 using maybe_wrap_ref = std::conditional_t<std::is_reference_v<T>, std::reference_wrapper<std::remove_reference_t<T>>, T>;
289 
297 template <typename T, bool is_trivial_class>
298 struct uninitialized_wrapper_base;
299 
300 template <typename T>
301 struct uninitialized_wrapper_base<T, false> {
302  using tuple_type = future_tuple_type_t<T>;
303  union any {
304  any() noexcept {}
305  ~any() {}
306  // T can be a reference, so wrap it.
307  maybe_wrap_ref<T> value;
308  } _v;
309 
310 public:
311  uninitialized_wrapper_base() noexcept = default;
312  template<typename... U>
313  std::enable_if_t<!std::is_same_v<std::tuple<std::remove_cv_t<U>...>, std::tuple<tuple_type>>, void>
314  uninitialized_set(U&&... vs) {
315  new (&_v.value) maybe_wrap_ref<T>{T(std::forward<U>(vs)...)};
316  }
317  void uninitialized_set(tuple_type&& v) {
318  uninitialized_set(std::move(std::get<0>(v)));
319  }
320  void uninitialized_set(const tuple_type& v) {
321  uninitialized_set(std::get<0>(v));
322  }
323  maybe_wrap_ref<T>& uninitialized_get() {
324  return _v.value;
325  }
326  const maybe_wrap_ref<T>& uninitialized_get() const {
327  return _v.value;
328  }
329 };
330 
331 template <typename T> struct uninitialized_wrapper_base<T, true> : private T {
332  using tuple_type = future_tuple_type_t<T>;
333  uninitialized_wrapper_base() noexcept = default;
334  template<typename... U>
335  std::enable_if_t<!std::is_same_v<std::tuple<std::remove_cv_t<U>...>, std::tuple<tuple_type>>, void>
336  uninitialized_set(U&&... vs) {
337  new (this) T(std::forward<U>(vs)...);
338  }
339  void uninitialized_set(tuple_type&& v) {
340  if constexpr (std::tuple_size_v<tuple_type> != 0) {
341  uninitialized_set(std::move(std::get<0>(v)));
342  }
343  }
344  void uninitialized_set(const tuple_type& v) {
345  if constexpr (std::tuple_size_v<tuple_type> != 0) {
346  uninitialized_set(std::get<0>(v));
347  }
348  }
349  T& uninitialized_get() {
350  return *this;
351  }
352  const T& uninitialized_get() const {
353  return *this;
354  }
355 };
356 
357 template <typename T>
358 constexpr bool can_inherit =
359 #ifdef _LIBCPP_VERSION
360 // We expect std::tuple<> to be trivially constructible and
361 // destructible. That is not the case with libc++
362 // (https://bugs.llvm.org/show_bug.cgi?id=41714). We could avoid this
363 // optimization when using libc++ and relax the asserts, but
364 // inspection suggests that std::tuple<> is trivial, it is just not
365 // marked as such.
366  std::is_same<std::tuple<>, T>::value ||
367 #endif
368  (std::is_trivially_destructible<T>::value && std::is_trivially_constructible<T>::value &&
369  std::is_class<T>::value && !std::is_final<T>::value);
370 
371 // The objective is to avoid extra space for empty types like std::tuple<>. We could use std::is_empty_v, but it is
372 // better to check that both the constructor and destructor can be skipped.
373 template <typename T>
374 struct uninitialized_wrapper
375  : public uninitialized_wrapper_base<T, can_inherit<T>> {};
376 
377 template <typename T>
378 struct is_trivially_move_constructible_and_destructible {
379  static constexpr bool value = std::is_trivially_move_constructible<T>::value && std::is_trivially_destructible<T>::value;
380 };
381 
382 template <bool... v>
383 struct all_true : std::false_type {};
384 
385 template <>
386 struct all_true<> : std::true_type {};
387 
388 template <bool... v>
389 struct all_true<true, v...> : public all_true<v...> {};
390 
391 template<typename T>
392 struct is_tuple_effectively_trivially_move_constructible_and_destructible_helper;
393 
394 template <typename... T>
395 struct is_tuple_effectively_trivially_move_constructible_and_destructible_helper<std::tuple<T...>> {
396  static constexpr bool value = all_true<is_trivially_move_constructible_and_destructible<T>::value...>::value;
397 };
398 
399 template <typename T>
400 static constexpr bool is_tuple_effectively_trivially_move_constructible_and_destructible =
401  is_tuple_effectively_trivially_move_constructible_and_destructible_helper<T>::value;
402 
403 }
404 
405 //
406 // A future/promise pair maintain one logical value (a future_state).
407 // There are up to three places that can store it, but only one is
408 // active at any time.
409 //
410 // - in the promise _local_state member variable
411 //
412 // This is necessary because a promise is created first and there
413 // would be nowhere else to put the value.
414 //
415 // - in the future _state variable
416 //
417 // This is used anytime a future exists and then has not been called
418 // yet. This guarantees a simple access to the value for any code
419 // that already has a future.
420 //
421 // - in the task associated with the .then() clause (after .then() is called,
422 // if a value was not set)
423 //
424 //
425 // The promise maintains a pointer to the state, which is modified as
426 // the state moves to a new location due to events (such as .then() or
427 // get_future being called) or due to the promise or future being
428 // moved around.
429 //
430 
431 // non templated base class to reduce code duplication
433  static_assert(sizeof(std::exception_ptr) == sizeof(void*), "exception_ptr not a pointer");
434  enum class state : uintptr_t {
435  invalid = 0,
436  future = 1,
437  // the substate is intended to decouple the run-time prevention
438  // for duplicative result extraction (calling e.g. then() twice
439  // ends up in abandoned()) from the wrapped object's destruction
440  // handling which is orchestrated by future_state. Instead of
441  // creating a temporary future_state just for the sake of setting
442  // the "invalid" in the source instance, result_unavailable can
443  // be set to ensure future_state_base::available() returns false.
444  result_unavailable = 2,
445  result = 3,
446  exception_min = 4, // or anything greater
447  };
448  union any {
449  any() noexcept { st = state::future; }
450  any(state s) noexcept { st = s; }
451  void set_exception(std::exception_ptr&& e) noexcept {
452  new (&ex) std::exception_ptr(std::move(e));
453  assert(st >= state::exception_min);
454  }
455  any(std::exception_ptr&& e) noexcept {
456  set_exception(std::move(e));
457  }
458  // From a users' perspective, a result_unavailable is not valid
459  bool valid() const noexcept { return st != state::invalid && st != state::result_unavailable; }
460  bool available() const noexcept { return st == state::result || st >= state::exception_min; }
461  bool failed() const noexcept { return __builtin_expect(st >= state::exception_min, false); }
462  void check_failure() noexcept;
463  ~any() noexcept { }
464  std::exception_ptr take_exception() noexcept {
465  std::exception_ptr ret(std::move(ex));
466  // Unfortunately in libstdc++ ~exception_ptr is defined out of line. We know that it does nothing for
467  // moved out values, so we omit calling it. This is critical for the code quality produced for this
468  // function. Without the out of line call, gcc can figure out that both sides of the if produce
469  // identical code and merges them.if
470  // We don't make any assumptions about other c++ libraries.
471  // There is request with gcc to define it inline: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90295
472 #ifndef __GLIBCXX__
473  ex.~exception_ptr();
474 #endif
475  st = state::invalid;
476  return ret;
477  }
478  void move_it(any&& x) noexcept {
479 #ifdef __GLIBCXX__
480  // Unfortunally gcc cannot fully optimize the regular
481  // implementation:
482  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95014
483  // Given what we know about the libstdc++ implementation
484  // (see the comment in take_exception), we can just
485  // memmove and zero x. We use memmove to guarantee
486  // vaild results if &x == this.
487  memmove(static_cast<void*>(this), &x, sizeof(any));
488  x.st = state::invalid;
489 #else
490  if (x.st < state::exception_min) {
491  st = x.st;
492  x.st = state::invalid;
493  } else {
494  new (&ex) std::exception_ptr(x.take_exception());
495  }
496 #endif
497  }
498  any(any&& x) noexcept {
499  move_it(std::move(x));
500  }
501  any& operator=(any&& x) noexcept {
502  check_failure();
503  // If this is a self move assignment, check_failure
504  // guarantees that we don't have an exception and calling
505  // move_it is safe.
506  move_it(std::move(x));
507  return *this;
508  }
509  bool has_result() const noexcept {
510  return st == state::result || st == state::result_unavailable;
511  }
512  state st;
513  std::exception_ptr ex;
514  } _u;
515 
516  future_state_base() noexcept = default;
517  future_state_base(state st) noexcept : _u(st) { }
518  future_state_base(std::exception_ptr&& ex) noexcept : _u(std::move(ex)) { }
519  future_state_base(future_state_base&& x) noexcept : _u(std::move(x._u)) { }
520 
521  // We never need to destruct this polymorphicly, so we can make it
522  // protected instead of virtual.
523 protected:
529  ~future_state_base() noexcept = default;
530 
531  void rethrow_exception() &&;
532  void rethrow_exception() const&;
533 
534 public:
535 
536  bool valid() const noexcept { return _u.valid(); }
537  bool available() const noexcept { return _u.available(); }
538  bool failed() const noexcept { return _u.failed(); }
539 
540  void ignore() noexcept;
541 
542  void set_exception(std::exception_ptr&& ex) noexcept {
543  assert(_u.st == state::future);
544  _u.set_exception(std::move(ex));
545  }
546  future_state_base& operator=(future_state_base&& x) noexcept = default;
547  void set_exception(future_state_base&& state) noexcept {
548  assert(_u.st == state::future);
549  *this = std::move(state);
550  }
551  std::exception_ptr get_exception() && noexcept {
552  assert(_u.st >= state::exception_min);
553  // Move ex out so future::~future() knows we've handled it
554  return _u.take_exception();
555  }
556  const std::exception_ptr& get_exception() const& noexcept {
557  assert(_u.st >= state::exception_min);
558  return _u.ex;
559  }
560  template <typename U>
561  friend struct future_state;
562  template <typename... U>
563  friend future<U...> current_exception_as_future() noexcept;
564  template <typename SEASTAR_ELLIPSIS U>
565  friend class future;
566  template <typename T>
567  friend struct futurize;
568 };
569 
570 void report_failed_future(future_state_base::any&& state) noexcept;
571 
572 inline void future_state_base::any::check_failure() noexcept {
573  if (failed()) {
574  report_failed_future(std::move(*this));
575  }
576 }
577 
581 
583 template <typename T>
584 struct future_state : public future_state_base, private internal::uninitialized_wrapper<T> {
585  static constexpr bool copy_noexcept = std::is_nothrow_copy_constructible<T>::value;
586 #if SEASTAR_API_LEVEL < 5
587  static constexpr bool has_trivial_move_and_destroy = internal::is_tuple_effectively_trivially_move_constructible_and_destructible<T>;
588 #else
589  static constexpr bool has_trivial_move_and_destroy = internal::is_trivially_move_constructible_and_destructible<T>::value;
590 #endif
591  static_assert(std::is_nothrow_move_constructible<T>::value,
592  "Types must be no-throw move constructible");
593  static_assert(std::is_nothrow_destructible<T>::value,
594  "Types must be no-throw destructible");
595  future_state() noexcept = default;
596  void move_it(future_state&& x) noexcept {
597  if constexpr (has_trivial_move_and_destroy) {
598  memmove(reinterpret_cast<char*>(&this->uninitialized_get()),
599  &x.uninitialized_get(),
600  internal::used_size<internal::maybe_wrap_ref<T>>::value);
601  } else if (_u.has_result()) {
602  this->uninitialized_set(std::move(x.uninitialized_get()));
603  std::destroy_at(&x.uninitialized_get());
604  }
605  }
606 
607  [[gnu::always_inline]]
608  future_state(future_state&& x) noexcept : future_state_base(std::move(x)) {
609  move_it(std::move(x));
610  }
611 
612  void clear() noexcept {
613  if (_u.has_result()) {
614  std::destroy_at(&this->uninitialized_get());
615  } else {
616  _u.check_failure();
617  }
618  }
619  __attribute__((always_inline))
620  ~future_state() noexcept {
621  clear();
622  }
623  future_state& operator=(future_state&& x) noexcept {
624  clear();
625  future_state_base::operator=(std::move(x));
626  // If &x == this, _u.st is now state::invalid and so it is
627  // safe to call move_it.
628  move_it(std::move(x));
629  return *this;
630  }
631  template <typename... A>
632  future_state(ready_future_marker, A&&... a) noexcept : future_state_base(state::result) {
633  try {
634  this->uninitialized_set(std::forward<A>(a)...);
635  } catch (...) {
636  new (this) future_state(current_exception_future_marker());
637  }
638  }
639  template <typename... A>
640  void set(A&&... a) noexcept {
641  assert(_u.st == state::future);
642  new (this) future_state(ready_future_marker(), std::forward<A>(a)...);
643  }
644  future_state(exception_future_marker, std::exception_ptr&& ex) noexcept : future_state_base(std::move(ex)) { }
645  future_state(exception_future_marker, future_state_base&& state) noexcept : future_state_base(std::move(state)) { }
646  future_state(current_exception_future_marker m) noexcept : future_state_base(m) { }
647  future_state(nested_exception_marker m, future_state_base&& old) noexcept : future_state_base(m, std::move(old)) { }
648  future_state(nested_exception_marker m, future_state_base&& n, future_state_base&& old) noexcept : future_state_base(m, std::move(n), std::move(old)) { }
649  T&& get_value() && noexcept {
650  assert(_u.st == state::result);
651  return static_cast<T&&>(this->uninitialized_get());
652  }
653  T&& take_value() && noexcept {
654  assert(_u.st == state::result);
655  _u.st = state::result_unavailable;
656  return static_cast<T&&>(this->uninitialized_get());
657  }
658  template<typename U = T>
659  const std::enable_if_t<std::is_copy_constructible<U>::value, U>& get_value() const& noexcept(copy_noexcept) {
660  assert(_u.st == state::result);
661  return this->uninitialized_get();
662  }
663  T&& take() && {
664  assert(available());
665  if (_u.st >= state::exception_min) {
666  std::move(*this).rethrow_exception();
667  }
668  _u.st = state::result_unavailable;
669  return static_cast<T&&>(this->uninitialized_get());
670  }
671  T&& get() && {
672  assert(available());
673  if (_u.st >= state::exception_min) {
674  std::move(*this).rethrow_exception();
675  }
676  return static_cast<T&&>(this->uninitialized_get());
677  }
678  const T& get() const& {
679  assert(available());
680  if (_u.st >= state::exception_min) {
681  rethrow_exception();
682  }
683  return this->uninitialized_get();
684  }
685  using get0_return_type = typename internal::get0_return_type<internal::future_tuple_type_t<T>>::type;
686  static get0_return_type get0(T&& x) {
687  return internal::get0_return_type<T>::get0(std::move(x));
688  }
689 
690  get0_return_type get0() {
691 #if SEASTAR_API_LEVEL < 5
692  return get0(std::move(*this).get());
693 #else
694  return std::move(*this).get();
695 #endif
696  }
697 };
698 
699 #if SEASTAR_API_LEVEL < 6
700 template <typename... T>
701 #else
702 template <typename T = void>
703 #endif
704 class continuation_base : public task {
705 protected:
706  using future_state = seastar::future_state<internal::future_stored_type_t<T SEASTAR_ELLIPSIS>>;
707  future_state _state;
708  using future_type = future<T SEASTAR_ELLIPSIS>;
709  using promise_type = promise<T SEASTAR_ELLIPSIS>;
710 public:
711  continuation_base() noexcept = default;
712  void set_state(future_state&& state) noexcept {
713  _state = std::move(state);
714  }
715  // This override of waiting_task() is needed here because there are cases
716  // when backtrace is obtained from the destructor of this class and objects
717  // of derived classes are already destroyed at that time. If we didn't
718  // have this override we would get a "pure virtual function call" exception.
719  virtual task* waiting_task() noexcept override { return nullptr; }
720  friend class internal::promise_base_with_type<T SEASTAR_ELLIPSIS>;
721  friend class promise<T SEASTAR_ELLIPSIS>;
722  friend class future<T SEASTAR_ELLIPSIS>;
723 };
724 
725 // Given a future type, find the corresponding continuation_base.
726 template <typename Future>
727 struct continuation_base_from_future;
728 
729 template <typename... T>
730 struct continuation_base_from_future<future<T...>> {
731  using type = continuation_base<T...>;
732 };
733 
734 template <typename Future>
735 using continuation_base_from_future_t = typename continuation_base_from_future<Future>::type;
736 
737 #if SEASTAR_API_LEVEL < 6
738 template <typename Promise, typename... T>
739 #else
740 template <typename Promise, typename T = void>
741 #endif
742 class continuation_base_with_promise : public continuation_base<T SEASTAR_ELLIPSIS> {
743  friend class internal::promise_base_with_type<T SEASTAR_ELLIPSIS>;
744 protected:
745  continuation_base_with_promise(Promise&& pr) noexcept : _pr(std::move(pr)) {
746  task::make_backtrace();
747  }
748  virtual task* waiting_task() noexcept override;
749  Promise _pr;
750 };
751 
752 #if SEASTAR_API_LEVEL < 6
753 template <typename Promise, typename Func, typename Wrapper, typename... T>
754 #else
755 template <typename Promise, typename Func, typename Wrapper, typename T = void>
756 #endif
757 struct continuation final : continuation_base_with_promise<Promise, T SEASTAR_ELLIPSIS> {
758  // Func is the original function passed to then/then_wrapped. The
759  // Wrapper is a helper function that implements the specific logic
760  // needed by then/then_wrapped. We call the wrapper passing it the
761  // original function, promise and state.
762  // Note that if Func's move constructor throws, this will call
763  // std::unexpected. We could try to require Func to be nothrow
764  // move constructible, but that will cause a lot of churn. Since
765  // we can't support a failure to create a continuation, calling
766  // std::unexpected as close to the failure as possible is the best
767  // we can do.
768  continuation(Promise&& pr, Func&& func, Wrapper&& wrapper) noexcept
769  : continuation_base_with_promise<Promise, T SEASTAR_ELLIPSIS>(std::move(pr))
770  , _func(std::move(func))
771  , _wrapper(std::move(wrapper)) {}
772  virtual void run_and_dispose() noexcept override {
773  try {
774  _wrapper(std::move(this->_pr), _func, std::move(this->_state));
775  } catch (...) {
776  this->_pr.set_to_current_exception();
777  }
778  delete this;
779  }
780  Func _func;
781  [[no_unique_address]] Wrapper _wrapper;
782 };
783 
784 #if SEASTAR_API_LEVEL < 4
785 
786 // This is an internal future<> payload for seastar::when_all_succeed(). It is used
787 // to return a variadic future (when two or more of its input futures were non-void),
788 // but with variadic futures deprecated and soon gone this is no longer possible.
789 //
790 // Instead, we use this tuple type, and future::then() knows to unpack it.
791 //
792 // The whole thing is temporary for a transition period.
793 template <typename... T>
794 struct when_all_succeed_tuple : std::tuple<T...> {
795  using std::tuple<T...>::tuple;
796  when_all_succeed_tuple(std::tuple<T...>&& t)
797  noexcept(std::is_nothrow_move_constructible<std::tuple<T...>>::value)
798  : std::tuple<T...>(std::move(t)) {}
799 };
800 
801 #endif
802 
803 namespace internal {
804 
805 template <typename... T>
806 future<T...> make_exception_future(future_state_base&& state) noexcept;
807 
808 template <typename... T, typename U>
809 void set_callback(future<T...>&& fut, U* callback) noexcept;
810 
811 class future_base;
812 
813 class promise_base {
814 protected:
815  enum class urgent { no, yes };
816  future_base* _future = nullptr;
817 
818  // This points to the future_state that is currently being
819  // used. See comment above the future_state struct definition for
820  // details.
821  future_state_base* _state;
822 
823  task* _task = nullptr;
824 
825  promise_base(const promise_base&) = delete;
826  promise_base(future_state_base* state) noexcept : _state(state) {}
827  promise_base(future_base* future, future_state_base* state) noexcept;
828  void move_it(promise_base&& x) noexcept;
829  promise_base(promise_base&& x) noexcept;
830 
831  void clear() noexcept;
832 
833  // We never need to destruct this polymorphicly, so we can make it
834  // protected instead of virtual
835  ~promise_base() noexcept {
836  clear();
837  }
838 
839  void operator=(const promise_base&) = delete;
840  promise_base& operator=(promise_base&& x) noexcept;
841 
842  template<urgent Urgent>
843  void make_ready() noexcept;
844 
845  template<typename T>
846  void set_exception_impl(T&& val) noexcept {
847  if (_state) {
848  _state->set_exception(std::move(val));
849  make_ready<urgent::no>();
850  } else {
851  // We get here if promise::get_future is called and the
852  // returned future is destroyed without creating a
853  // continuation.
854  // In older versions of seastar we would store a local
855  // copy of ex and warn in the promise destructor.
856  // Since there isn't any way for the user to clear
857  // the exception, we issue the warning from here.
858  report_failed_future(val);
859  }
860  }
861 
862  void set_exception(future_state_base&& state) noexcept {
863  set_exception_impl(std::move(state));
864  }
865 
866  void set_exception(std::exception_ptr&& ex) noexcept {
867  set_exception_impl(std::move(ex));
868  }
869 
870  void set_exception(const std::exception_ptr& ex) noexcept {
871  set_exception(std::exception_ptr(ex));
872  }
873 
874  template<typename Exception>
875  std::enable_if_t<!std::is_same<std::remove_reference_t<Exception>, std::exception_ptr>::value, void> set_exception(Exception&& e) noexcept {
876  set_exception(make_exception_ptr(std::forward<Exception>(e)));
877  }
878 
879  friend class future_base;
880  template <typename SEASTAR_ELLIPSIS U> friend class seastar::future;
881 
882 public:
887  void set_to_current_exception() noexcept;
888 
890  task* waiting_task() const noexcept { return _task; }
891 };
892 
899 template <typename SEASTAR_ELLIPSIS T>
900 class promise_base_with_type : protected internal::promise_base {
901 protected:
902  using future_state = seastar::future_state<future_stored_type_t<T SEASTAR_ELLIPSIS>>;
903  future_state* get_state() noexcept {
904  return static_cast<future_state*>(_state);
905  }
906  static constexpr bool copy_noexcept = future_state::copy_noexcept;
907 public:
908  promise_base_with_type(future_state_base* state) noexcept : promise_base(state) { }
909  promise_base_with_type(future<T SEASTAR_ELLIPSIS>* future) noexcept : promise_base(future, &future->_state) { }
910  promise_base_with_type(promise_base_with_type&& x) noexcept = default;
911  promise_base_with_type(const promise_base_with_type&) = delete;
912  promise_base_with_type& operator=(promise_base_with_type&& x) noexcept = default;
913  void operator=(const promise_base_with_type&) = delete;
914 
915  void set_urgent_state(future_state&& state) noexcept {
916  auto* ptr = get_state();
917  // The state can be null if the corresponding future has been
918  // destroyed without producing a continuation.
919  if (ptr) {
920  // FIXME: This is a fairly expensive assert. It would be a
921  // good candidate for being disabled in release builds if
922  // we had such an assert.
923  assert(ptr->_u.st == future_state_base::state::future);
924  new (ptr) future_state(std::move(state));
925  make_ready<urgent::yes>();
926  }
927  }
928 
929  template <typename... A>
930  void set_value(A&&... a) noexcept {
931  if (auto *s = get_state()) {
932  s->set(std::forward<A>(a)...);
933  make_ready<urgent::no>();
934  }
935  }
936 
941  void set_to_current_exception() noexcept {
942  internal::promise_base::set_to_current_exception();
943  }
944 
946  using internal::promise_base::waiting_task;
947 
948 private:
949 
950  template <typename SEASTAR_ELLIPSIS U>
951  friend class seastar::future;
952 
953  friend future_state;
954 };
955 }
957 
963 template <typename SEASTAR_ELLIPSIS T>
964 class promise : private internal::promise_base_with_type<T SEASTAR_ELLIPSIS> {
965  using future_state = typename internal::promise_base_with_type<T SEASTAR_ELLIPSIS>::future_state;
966  future_state _local_state;
967 
968 public:
972  promise() noexcept : internal::promise_base_with_type<T SEASTAR_ELLIPSIS>(&_local_state) {}
973 
975  void move_it(promise&& x) noexcept;
976  promise(promise&& x) noexcept : internal::promise_base_with_type<T SEASTAR_ELLIPSIS>(std::move(x)) {
977  move_it(std::move(x));
978  }
979  promise(const promise&) = delete;
980  promise& operator=(promise&& x) noexcept {
981  internal::promise_base_with_type<T SEASTAR_ELLIPSIS>::operator=(std::move(x));
982  // If this is a self-move, _state is now nullptr and it is
983  // safe to call move_it.
984  move_it(std::move(x));
985  return *this;
986  }
987  void operator=(const promise&) = delete;
988 
993  void set_to_current_exception() noexcept {
994  internal::promise_base::set_to_current_exception();
995  }
996 
998  using internal::promise_base::waiting_task;
999 
1007 
1019  template <typename... A>
1020  void set_value(A&&... a) noexcept {
1021  internal::promise_base_with_type<T SEASTAR_ELLIPSIS>::set_value(std::forward<A>(a)...);
1022  }
1023 
1028  void set_exception(std::exception_ptr&& ex) noexcept {
1029  internal::promise_base::set_exception(std::move(ex));
1030  }
1031 
1032  void set_exception(const std::exception_ptr& ex) noexcept {
1033  internal::promise_base::set_exception(ex);
1034  }
1035 
1040  template<typename Exception>
1041  std::enable_if_t<!std::is_same<std::remove_reference_t<Exception>, std::exception_ptr>::value, void> set_exception(Exception&& e) noexcept {
1042  internal::promise_base::set_exception(std::forward<Exception>(e));
1043  }
1044 
1045  using internal::promise_base_with_type<T SEASTAR_ELLIPSIS>::set_urgent_state;
1046 
1047  template <typename SEASTAR_ELLIPSIS U>
1048  friend class future;
1049 };
1050 
1051 #if SEASTAR_API_LEVEL < 6
1057 template<>
1058 class promise<void> : public promise<> {};
1059 #endif
1060 
1062 
1065 
1066 
1072 template <typename... T> struct is_future : std::false_type {};
1073 
1076 template <typename... T> struct is_future<future<T...>> : std::true_type {};
1077 
1079 
1080 
1084 template <typename T>
1085 struct futurize;
1086 
1087 SEASTAR_CONCEPT(
1088 
1089 template <typename T>
1090 concept Future = is_future<T>::value;
1091 
1092 template <typename Func, typename... T>
1093 concept CanInvoke = std::invocable<Func, T...>;
1094 
1095 // Deprecated alias
1096 template <typename Func, typename... T>
1097 concept CanApply = CanInvoke<Func, T...>;
1098 
1099 template <typename Func, typename... T>
1100 concept CanApplyTuple
1101  = sizeof...(T) == 1
1102  && requires (Func func, std::tuple<T...> wrapped_val) {
1103  { std::apply(func, std::get<0>(std::move(wrapped_val))) };
1104  };
1105 
1106 template <typename Func, typename Return, typename... T>
1107 concept InvokeReturns = requires (Func f, T... args) {
1108  { f(std::forward<T>(args)...) } -> std::same_as<Return>;
1109 };
1110 
1111 // Deprecated alias
1112 template <typename Func, typename Return, typename... T>
1113 concept ApplyReturns = InvokeReturns<Func, Return, T...>;
1114 
1115 template <typename Func, typename... T>
1116 concept InvokeReturnsAnyFuture = requires (Func f, T... args) {
1117  requires is_future<decltype(f(std::forward<T>(args)...))>::value;
1118 };
1119 
1120 // Deprecated alias
1121 template <typename Func, typename... T>
1122 concept ApplyReturnsAnyFuture = InvokeReturnsAnyFuture<Func, T...>;
1123 
1124 )
1125 
1127 
1128 // Converts a type to a future type, if it isn't already.
1129 template <typename T>
1130 using futurize_t = typename futurize<T>::type;
1131 
1133 
1134 template<typename Func, typename... Args>
1135 auto futurize_invoke(Func&& func, Args&&... args) noexcept;
1136 
1137 template<typename Func, typename... Args>
1138 auto futurize_apply(Func&& func, std::tuple<Args...>&& args) noexcept;
1139 
1142 namespace internal {
1143 class future_base {
1144 protected:
1145  promise_base* _promise;
1146  future_base() noexcept : _promise(nullptr) {}
1147  future_base(promise_base* promise, future_state_base* state) noexcept : _promise(promise) {
1148  _promise->_future = this;
1149  _promise->_state = state;
1150  }
1151 
1152  void move_it(future_base&& x, future_state_base* state) noexcept {
1153  _promise = x._promise;
1154  if (auto* p = _promise) {
1155  x.detach_promise();
1156  p->_future = this;
1157  p->_state = state;
1158  }
1159  }
1160 
1161  future_base(future_base&& x, future_state_base* state) noexcept {
1162  move_it(std::move(x), state);
1163  }
1164 
1165  void clear() noexcept {
1166  if (_promise) {
1167  detach_promise();
1168  }
1169  }
1170 
1171  ~future_base() noexcept {
1172  clear();
1173  }
1174 
1175  promise_base* detach_promise() noexcept {
1176  _promise->_state = nullptr;
1177  _promise->_future = nullptr;
1178  return std::exchange(_promise, nullptr);
1179  }
1180 
1181  void schedule(task* tws, future_state_base* state) noexcept {
1182  promise_base* p = detach_promise();
1183  p->_state = state;
1184  p->_task = tws;
1185  }
1186 
1187  void do_wait() noexcept;
1188 
1189 #ifdef SEASTAR_COROUTINES_ENABLED
1190  void set_coroutine(task& coroutine) noexcept;
1191 #endif
1192 
1193  friend class promise_base;
1194 };
1195 
1196 template <typename Func, typename... T>
1197 struct future_result {
1198  using type = std::invoke_result_t<Func, T...>;
1199  using future_type = futurize_t<type>;
1200  using func_type = future_type (T&&...);
1201 };
1202 
1203 template <typename Func>
1204 struct future_result<Func, void> {
1205  using type = std::invoke_result_t<Func>;
1206  using future_type = futurize_t<type>;
1207  using func_type = future_type ();
1208 };
1209 
1210 template <typename Func, typename SEASTAR_ELLIPSIS T>
1211 using future_result_t = typename future_result<Func, T SEASTAR_ELLIPSIS>::type;
1212 
1213 template <typename Func, typename T>
1214 auto future_invoke(Func&& func, T&& v) {
1215  if constexpr (std::is_same_v<T, monostate>) {
1216  return std::invoke(std::forward<Func>(func));
1217  } else {
1218  return std::invoke(std::forward<Func>(func), std::forward<T>(v));
1219  }
1220 }
1221 
1222 // This is a customization point for future::then()'s implementation.
1223 // It behaves differently when the future value type is a when_all_succeed_tuple
1224 // instantiation, indicating we need to unpack the tuple into multiple lambda
1225 // arguments.
1226 template <typename Future>
1227 struct call_then_impl;
1228 
1229 // Generic case - the input is not a future<when_all_succeed_tuple<...>>, so
1230 // we just forward everything to future::then_impl.
1231 template <typename... T>
1232 struct call_then_impl<future<T...>> {
1233  template <typename Func>
1234  using result_type = typename future_result<Func, T...>::future_type;
1235 
1236  template <typename Func>
1237  using func_type = typename future_result<Func, T...>::func_type;
1238 
1239  template <typename Func>
1240  static result_type<Func> run(future<T...>& fut, Func&& func) noexcept {
1241  return fut.then_impl(std::forward<Func>(func));
1242  }
1243 };
1244 
1245 #if SEASTAR_API_LEVEL < 4
1246 
1247 // Special case: we unpack the tuple before calling the function
1248 template <typename... T>
1249 struct call_then_impl<future<when_all_succeed_tuple<T...>>> {
1250  template <typename Func>
1251  using result_type = futurize_t<std::invoke_result_t<Func, T&&...>>;
1252 
1253  template <typename Func>
1254  using func_type = result_type<Func> (T&&...);
1255 
1256  using was_tuple = when_all_succeed_tuple<T...>;
1257  using std_tuple = std::tuple<T...>;
1258 
1259  template <typename Func>
1260  static auto run(future<was_tuple>& fut, Func&& func) noexcept {
1261  // constructing func in the lambda can throw, but there's nothing we can do
1262  // about it, similar to #84.
1263  return fut.then_impl([func = std::forward<Func>(func)] (was_tuple&& t) mutable {
1264  return std::apply(func, static_cast<std_tuple&&>(std::move(t)));
1265  });
1266  }
1267 };
1268 
1269 #endif
1270 
1271 template <typename Func, typename... Args>
1272 using call_then_impl_result_type = typename call_then_impl<future<Args...>>::template result_type<Func>;
1273 
1274 SEASTAR_CONCEPT(
1275 template <typename Func, typename... Args>
1276 concept CanInvokeWhenAllSucceed = requires {
1277  typename call_then_impl_result_type<Func, Args...>;
1278 };
1279 )
1280 
1281 template <typename Func, typename... T>
1282 struct result_of_apply {
1283  // no "type" member if not a function call signature or not a tuple
1284 };
1285 
1286 template <typename Func, typename... T>
1287 struct result_of_apply<Func, std::tuple<T...>> : std::invoke_result<Func, T...> {
1288  // Let std::invoke_result_t determine the result if the input is a tuple
1289 };
1290 
1291 template <typename Func, typename... T>
1292 using result_of_apply_t = typename result_of_apply<Func, T...>::type;
1293 
1294 }
1295 
1296 template <typename Promise, typename SEASTAR_ELLIPSIS T>
1297 task* continuation_base_with_promise<Promise, T SEASTAR_ELLIPSIS>::waiting_task() noexcept {
1298  return _pr.waiting_task();
1299 }
1300 
1343 template <typename SEASTAR_ELLIPSIS T>
1344 class SEASTAR_NODISCARD future : private internal::future_base {
1345  using future_state = seastar::future_state<internal::future_stored_type_t<T SEASTAR_ELLIPSIS>>;
1346  future_state _state;
1347  static constexpr bool copy_noexcept = future_state::copy_noexcept;
1348  using call_then_impl = internal::call_then_impl<future>;
1349 
1350 private:
1351  // This constructor creates a future that is not ready but has no
1352  // associated promise yet. The use case is to have a less flexible
1353  // but more efficient future/promise pair where we know that
1354  // promise::set_value cannot possibly be called without a matching
1355  // future and so that promise doesn't need to store a
1356  // future_state.
1358 
1359  future(promise<T SEASTAR_ELLIPSIS>* pr) noexcept : future_base(pr, &_state), _state(std::move(pr->_local_state)) { }
1360  template <typename... A>
1361  future(ready_future_marker m, A&&... a) noexcept : _state(m, std::forward<A>(a)...) { }
1363  future(future_state_base::nested_exception_marker m, future_state_base&& old) noexcept : _state(m, std::move(old)) {}
1364  future(future_state_base::nested_exception_marker m, future_state_base&& n, future_state_base&& old) noexcept : _state(m, std::move(n), std::move(old)) {}
1365  future(exception_future_marker m, std::exception_ptr&& ex) noexcept : _state(m, std::move(ex)) { }
1366  future(exception_future_marker m, future_state_base&& state) noexcept : _state(m, std::move(state)) { }
1367  [[gnu::always_inline]]
1368  explicit future(future_state&& state) noexcept
1369  : _state(std::move(state)) {
1370  }
1371  internal::promise_base_with_type<T SEASTAR_ELLIPSIS> get_promise() noexcept {
1372  assert(!_promise);
1373  return internal::promise_base_with_type<T SEASTAR_ELLIPSIS>(this);
1374  }
1375  internal::promise_base_with_type<T SEASTAR_ELLIPSIS>* detach_promise() noexcept {
1376  return static_cast<internal::promise_base_with_type<T SEASTAR_ELLIPSIS>*>(future_base::detach_promise());
1377  }
1378  void schedule(continuation_base<T SEASTAR_ELLIPSIS>* tws) noexcept {
1379  future_base::schedule(tws, &tws->_state);
1380  }
1381  template <typename Pr, typename Func, typename Wrapper>
1382  void schedule(Pr&& pr, Func&& func, Wrapper&& wrapper) noexcept {
1383  // If this new throws a std::bad_alloc there is nothing that
1384  // can be done about it. The corresponding future is not ready
1385  // and we cannot break the chain. Since this function is
1386  // noexcept, it will call std::terminate if new throws.
1388  auto tws = new continuation<Pr, Func, Wrapper, T SEASTAR_ELLIPSIS>(std::move(pr), std::move(func), std::move(wrapper));
1389  // In a debug build we schedule ready futures, but not in
1390  // other build modes.
1391 #ifdef SEASTAR_DEBUG
1392  if (_state.available()) {
1393  tws->set_state(std::move(_state));
1394  ::seastar::schedule(tws);
1395  return;
1396  }
1397 #endif
1398  schedule(tws);
1399  _state._u.st = future_state_base::state::invalid;
1400  }
1401 
1402  [[gnu::always_inline]]
1403  future_state&& get_available_state_ref() noexcept {
1404  if (_promise) {
1405  detach_promise();
1406  }
1407  return std::move(_state);
1408  }
1409 
1410  future<T SEASTAR_ELLIPSIS> rethrow_with_nested(future_state_base&& n) noexcept {
1411  return future<T SEASTAR_ELLIPSIS>(future_state_base::nested_exception_marker(), std::move(n), std::move(_state));
1412  }
1413 
1414  future<T SEASTAR_ELLIPSIS> rethrow_with_nested() noexcept {
1416  }
1417 
1418  template<typename... U>
1419  friend class shared_future;
1420 public:
1422  using value_type = internal::future_stored_type_t<T SEASTAR_ELLIPSIS>;
1423  using tuple_type = internal::future_tuple_type_t<value_type>;
1427  [[gnu::always_inline]]
1428  future(future&& x) noexcept : future_base(std::move(x), &_state), _state(std::move(x._state)) { }
1429  future(const future&) = delete;
1430  future& operator=(future&& x) noexcept {
1431  clear();
1432  move_it(std::move(x), &_state);
1433  _state = std::move(x._state);
1434  return *this;
1435  }
1436  void operator=(const future&) = delete;
1446  [[gnu::always_inline]]
1448  wait();
1449  return get_available_state_ref().take();
1450  }
1451 
1452  [[gnu::always_inline]]
1453  std::exception_ptr get_exception() noexcept {
1454  return get_available_state_ref().get_exception();
1455  }
1456 
1465  using get0_return_type = typename future_state::get0_return_type;
1466  get0_return_type get0() {
1467 #if SEASTAR_API_LEVEL < 5
1468  return future_state::get0(get());
1469 #else
1470  return (get0_return_type)get();
1471 #endif
1472  }
1473 
1479  void wait() noexcept {
1480  if (_state.available()) {
1481  return;
1482  }
1483  do_wait();
1484  }
1485 
1489  [[gnu::always_inline]]
1490  bool available() const noexcept {
1491  return _state.available();
1492  }
1493 
1497  [[gnu::always_inline]]
1498  bool failed() const noexcept {
1499  return _state.failed();
1500  }
1501 
1517  template <typename Func, typename Result = futurize_t<typename call_then_impl::template result_type<Func>>>
1518  SEASTAR_CONCEPT( requires std::invocable<Func, T SEASTAR_ELLIPSIS> || internal::CanInvokeWhenAllSucceed<Func, T SEASTAR_ELLIPSIS>)
1519  Result
1520  then(Func&& func) noexcept {
1521  // The implementation of then() is customized via the call_then_impl helper
1522  // template, in order to special case the results of when_all_succeed().
1523  // when_all_succeed() used to return a variadic future, which is deprecated, so
1524  // now it returns a when_all_succeed_tuple, which we intercept in call_then_impl,
1525  // and treat it as a variadic future.
1526 #ifndef SEASTAR_TYPE_ERASE_MORE
1527  return call_then_impl::run(*this, std::move(func));
1528 #else
1529  using func_type = typename call_then_impl::template func_type<Func>;
1531  {
1533  ncf = noncopyable_function<func_type>([func = std::forward<Func>(func)](auto&&... args) mutable {
1534  return futurize_invoke(func, std::forward<decltype(args)>(args)...);
1535  });
1536  }
1537  return call_then_impl::run(*this, std::move(ncf));
1538 #endif
1539  }
1540 
1560  template <typename Func, typename Result = futurize_t<internal::result_of_apply_t<Func, T SEASTAR_ELLIPSIS>>>
1561  SEASTAR_CONCEPT( requires ::seastar::CanApplyTuple<Func, T SEASTAR_ELLIPSIS>)
1562  Result
1563  then_unpack(Func&& func) noexcept {
1564  return then([func = std::forward<Func>(func)] (T&& SEASTAR_ELLIPSIS tuple) mutable {
1565  // sizeof...(tuple) is required to be 1
1566  return std::apply(func, std::move(tuple) SEASTAR_ELLIPSIS);
1567  });
1568  }
1569 
1570 private:
1571 
1572  // Keep this simple so that Named Return Value Optimization is used.
1573  template <typename Func, typename Result>
1574  Result then_impl_nrvo(Func&& func) noexcept {
1576  typename futurator::type fut(future_for_get_promise_marker{});
1577  using pr_type = decltype(fut.get_promise());
1578  schedule(fut.get_promise(), std::move(func), [](pr_type&& pr, Func& func, future_state&& state) {
1579  if (state.failed()) {
1580  pr.set_exception(static_cast<future_state_base&&>(std::move(state)));
1581  } else {
1582  futurator::satisfy_with_result_of(std::move(pr), [&func, &state] {
1583 #if SEASTAR_API_LEVEL < 5
1584  return std::apply(func, std::move(state).get_value());
1585 #else
1586  // clang thinks that "state" is not used, below, for future<>.
1587  // Make it think it is used to avoid an unused-lambda-capture warning.
1588  (void)state;
1589  return internal::future_invoke(func, std::move(state).get_value());
1590 #endif
1591  });
1592  }
1593  });
1594  return fut;
1595  }
1596 
1597  template <typename Func, typename Result = futurize_t<internal::future_result_t<Func, T SEASTAR_ELLIPSIS>>>
1598  Result
1599  then_impl(Func&& func) noexcept {
1600 #ifndef SEASTAR_DEBUG
1601  using futurator = futurize<internal::future_result_t<Func, T SEASTAR_ELLIPSIS>>;
1602  if (failed()) {
1603  return futurator::make_exception_future(static_cast<future_state_base&&>(get_available_state_ref()));
1604  } else if (available()) {
1605 #if SEASTAR_API_LEVEL < 5
1606  return futurator::apply(std::forward<Func>(func), get_available_state_ref().take_value());
1607 #else
1608  return futurator::invoke(std::forward<Func>(func), get_available_state_ref().take_value());
1609 #endif
1610  }
1611 #endif
1612  return then_impl_nrvo<Func, Result>(std::forward<Func>(func));
1613  }
1614 
1615 public:
1631  template <typename Func, typename FuncResult = std::invoke_result_t<Func, future>>
1632  SEASTAR_CONCEPT( requires std::invocable<Func, future> )
1633  futurize_t<FuncResult>
1634  then_wrapped(Func&& func) & noexcept {
1635  return then_wrapped_maybe_erase<false, FuncResult>(std::forward<Func>(func));
1636  }
1637 
1638  template <typename Func, typename FuncResult = std::invoke_result_t<Func, future&&>>
1639  SEASTAR_CONCEPT( requires std::invocable<Func, future&&> )
1640  futurize_t<FuncResult>
1641  then_wrapped(Func&& func) && noexcept {
1642  return then_wrapped_maybe_erase<true, FuncResult>(std::forward<Func>(func));
1643  }
1644 
1645 private:
1646 
1647  template <bool AsSelf, typename FuncResult, typename Func>
1648  futurize_t<FuncResult>
1649  then_wrapped_maybe_erase(Func&& func) noexcept {
1650 #ifndef SEASTAR_TYPE_ERASE_MORE
1651  return then_wrapped_common<AsSelf, FuncResult>(std::forward<Func>(func));
1652 #else
1653  using futurator = futurize<FuncResult>;
1654  using WrapFuncResult = typename futurator::type;
1655  noncopyable_function<WrapFuncResult (future&&)> ncf;
1656  {
1657  memory::scoped_critical_alloc_section _;
1658  ncf = noncopyable_function<WrapFuncResult(future &&)>([func = std::forward<Func>(func)](future&& f) mutable {
1659  return futurator::invoke(func, std::move(f));
1660  });
1661  }
1662  return then_wrapped_common<AsSelf, WrapFuncResult>(std::move(ncf));
1663 #endif
1664  }
1665 
1666  // Keep this simple so that Named Return Value Optimization is used.
1667  template <typename FuncResult, typename Func>
1668  futurize_t<FuncResult>
1669  then_wrapped_nrvo(Func&& func) noexcept {
1670  using futurator = futurize<FuncResult>;
1671  typename futurator::type fut(future_for_get_promise_marker{});
1672  using pr_type = decltype(fut.get_promise());
1673  schedule(fut.get_promise(), std::move(func), [](pr_type&& pr, Func& func, future_state&& state) {
1674  futurator::satisfy_with_result_of(std::move(pr), [&func, &state] {
1675  return func(future(std::move(state)));
1676  });
1677  });
1678  return fut;
1679  }
1680 
1681 
1682  template <bool AsSelf, typename FuncResult, typename Func>
1683  futurize_t<FuncResult>
1684  then_wrapped_common(Func&& func) noexcept {
1685 #ifndef SEASTAR_DEBUG
1686  using futurator = futurize<FuncResult>;
1687  if (available()) {
1688  if constexpr (AsSelf) {
1689  if (_promise) {
1690  detach_promise();
1691  }
1692  return futurator::invoke(std::forward<Func>(func), std::move(*this));
1693  } else {
1694  return futurator::invoke(std::forward<Func>(func), future(get_available_state_ref()));
1695  }
1696  }
1697 #endif
1698  return then_wrapped_nrvo<FuncResult, Func>(std::forward<Func>(func));
1699  }
1700 
1701  void forward_to(internal::promise_base_with_type<T SEASTAR_ELLIPSIS>&& pr) noexcept {
1702  if (_state.available()) {
1703  pr.set_urgent_state(std::move(_state));
1704  } else {
1705  *detach_promise() = std::move(pr);
1706  }
1707  }
1708 
1709 public:
1721  if (_state.available()) {
1722  pr.set_urgent_state(std::move(_state));
1723  } else if (&pr._local_state != pr._state) {
1724  // The only case when _state points to _local_state is
1725  // when get_future was never called. Given that pr will
1726  // soon be destroyed, we know get_future will never be
1727  // called and we can just ignore this request.
1728  *detach_promise() = std::move(pr);
1729  }
1730  }
1731 
1732 
1733 
1749  template <typename Func>
1750  SEASTAR_CONCEPT( requires std::invocable<Func> )
1751  future<T SEASTAR_ELLIPSIS> finally(Func&& func) noexcept {
1752  return then_wrapped(finally_body<Func, is_future<std::invoke_result_t<Func>>::value>(std::forward<Func>(func)));
1753  }
1754 
1755 
1756  template <typename Func, bool FuncReturnsFuture>
1758 
1759  template <typename Func>
1760  struct finally_body<Func, true> {
1761  Func _func;
1762 
1763  finally_body(Func&& func) noexcept : _func(std::forward<Func>(func))
1764  { }
1765 
1766  future<T SEASTAR_ELLIPSIS> operator()(future<T SEASTAR_ELLIPSIS>&& result) noexcept {
1767  return futurize_invoke(_func).then_wrapped([result = std::move(result)](auto&& f_res) mutable {
1768  if (!f_res.failed()) {
1769  return std::move(result);
1770  } else {
1771  return result.rethrow_with_nested(std::move(f_res._state));
1772  }
1773  });
1774  }
1775  };
1776 
1777  template <typename Func>
1778  struct finally_body<Func, false> {
1779  Func _func;
1780 
1781  finally_body(Func&& func) noexcept : _func(std::forward<Func>(func))
1782  { }
1783 
1784  future<T SEASTAR_ELLIPSIS> operator()(future<T SEASTAR_ELLIPSIS>&& result) noexcept {
1785  try {
1786  _func();
1787  return std::move(result);
1788  } catch (...) {
1789  return result.rethrow_with_nested();
1790  }
1791  };
1792  };
1793 
1798  future<> or_terminate() noexcept {
1799  return then_wrapped([] (auto&& f) {
1800  try {
1801  f.get();
1802  } catch (...) {
1803  engine_exit(std::current_exception());
1804  }
1805  });
1806  }
1807 
1813  // We need the generic variadic lambda, below, because then() behaves differently
1814  // when value_type is when_all_succeed_tuple
1815  return then([] (auto&&...) {});
1816  }
1817 
1831  template <typename Func>
1832  /* Broken?
1833  SEASTAR_CONCEPT( requires ::seastar::InvokeReturns<Func, future<T...>, std::exception_ptr>
1834  || (sizeof...(T) == 0 && ::seastar::InvokeReturns<Func, void, std::exception_ptr>)
1835  || (sizeof...(T) == 1 && ::seastar::InvokeReturns<Func, T..., std::exception_ptr>)
1836  ) */
1838  return then_wrapped([func = std::forward<Func>(func)]
1839  (auto&& fut) mutable -> future<T SEASTAR_ELLIPSIS> {
1840  if (!fut.failed()) {
1841  return make_ready_future<T SEASTAR_ELLIPSIS>(fut.get());
1842  } else {
1843  return futurize_invoke(func, fut.get_exception());
1844  }
1845  });
1846  }
1847 
1858  template <typename Func>
1860  using trait = function_traits<Func>;
1861  static_assert(trait::arity == 1, "func can take only one parameter");
1862  using ex_type = typename trait::template arg<0>::type;
1863  return then_wrapped([func = std::forward<Func>(func)]
1864  (auto&& fut) mutable -> future<T SEASTAR_ELLIPSIS> {
1865  try {
1866  return make_ready_future<T SEASTAR_ELLIPSIS>(fut.get());
1867  } catch(ex_type& ex) {
1868  return futurize_invoke(func, ex);
1869  }
1870  });
1871  }
1872 
1878  void ignore_ready_future() noexcept {
1879  _state.ignore();
1880  }
1881 
1882 #ifdef SEASTAR_COROUTINES_ENABLED
1883  using future_base::set_coroutine;
1884 #endif
1885 private:
1886  void set_callback(continuation_base<T SEASTAR_ELLIPSIS>* callback) noexcept {
1887  if (_state.available()) {
1888  callback->set_state(get_available_state_ref());
1889  ::seastar::schedule(callback);
1890  } else {
1891  assert(_promise);
1892  schedule(callback);
1893  }
1894 
1895  }
1896 
1898  template <typename SEASTAR_ELLIPSIS U>
1899  friend class future;
1900  template <typename SEASTAR_ELLIPSIS U>
1901  friend class promise;
1902  template <typename U>
1903  friend struct futurize;
1904  template <typename SEASTAR_ELLIPSIS U>
1905  friend class internal::promise_base_with_type;
1906  template <typename... U, typename... A>
1907  friend future<U...> make_ready_future(A&&... value) noexcept;
1908  template <typename... U>
1909  friend future<U...> make_exception_future(std::exception_ptr&& ex) noexcept;
1910  template <typename... U, typename Exception>
1911  friend future<U...> make_exception_future(Exception&& ex) noexcept;
1912  template <typename... U>
1913  friend future<U...> internal::make_exception_future(future_state_base&& state) noexcept;
1914  template <typename... U>
1915  friend future<U...> current_exception_as_future() noexcept;
1916  template <typename... U, typename V>
1917  friend void internal::set_callback(future<U...>&&, V*) noexcept;
1918  template <typename Future>
1919  friend struct internal::call_then_impl;
1921 };
1922 
1923 
1924 namespace internal {
1925 template <typename T>
1926 struct futurize_base {
1928  using type = future<T>;
1930  using promise_type = promise<T>;
1931  using promise_base_with_type = internal::promise_base_with_type<T>;
1932 
1934  static inline type convert(T&& value) { return make_ready_future<T>(std::move(value)); }
1935  static inline type convert(type&& value) { return std::move(value); }
1936 
1938  template <typename Arg>
1939  static inline type make_exception_future(Arg&& arg) noexcept;
1940 };
1941 
1942 template <>
1943 struct futurize_base<void> {
1944  using type = future<>;
1945  using promise_type = promise<>;
1946  using promise_base_with_type = internal::promise_base_with_type<>;
1947 
1948  static inline type convert(type&& value) {
1949  return std::move(value);
1950  }
1951  template <typename Arg>
1952  static inline type make_exception_future(Arg&& arg) noexcept;
1953 };
1954 
1955 template <typename T>
1956 struct futurize_base<future<T>> : public futurize_base<T> {};
1957 
1958 template <>
1959 struct futurize_base<future<>> : public futurize_base<void> {};
1960 }
1961 
1962 template <typename T>
1963 struct futurize : public internal::futurize_base<T> {
1964  using base = internal::futurize_base<T>;
1965  using type = typename base::type;
1966  using promise_type = typename base::promise_type;
1967  using promise_base_with_type = typename base::promise_base_with_type;
1969  using value_type = typename type::value_type;
1970  using tuple_type = typename type::tuple_type;
1971  using base::convert;
1973 
1976  template<typename Func, typename... FuncArgs>
1977  static inline type apply(Func&& func, std::tuple<FuncArgs...>&& args) noexcept;
1978 
1981  template<typename Func, typename... FuncArgs>
1982  static inline type invoke(Func&& func, FuncArgs&&... args) noexcept;
1983 
1984  template<typename Func>
1985  static inline type invoke(Func&& func, internal::monostate) noexcept {
1986  return invoke(std::forward<Func>(func));
1987  }
1988 
1990  template<typename Func, typename... FuncArgs>
1991  [[deprecated("Use invoke for varargs")]]
1992  static inline type apply(Func&& func, FuncArgs&&... args) noexcept {
1993  return invoke(std::forward<Func>(func), std::forward<FuncArgs>(args)...);
1994  }
1995 
1996  static type current_exception_as_future() noexcept {
1998  }
1999 
2001  static type from_tuple(tuple_type&& value) {
2002  return type(ready_future_marker(), std::move(value));
2003  }
2005  static type from_tuple(const tuple_type& value) {
2006  return type(ready_future_marker(), value);
2007  }
2008 
2009 #if SEASTAR_API_LEVEL >= 5
2011  static type from_tuple(value_type&& value) {
2012  return type(ready_future_marker(), std::move(value));
2013  }
2015  static type from_tuple(const value_type& value) {
2016  return type(ready_future_marker(), value);
2017  }
2018 #endif
2019 private:
2023  template<typename Func>
2024  SEASTAR_CONCEPT( requires std::invocable<Func> )
2025  static void satisfy_with_result_of(promise_base_with_type&&, Func&& func);
2026 
2027  template <typename SEASTAR_ELLIPSIS U>
2028  friend class future;
2029 };
2030 
2031 inline internal::promise_base::promise_base(future_base* future, future_state_base* state) noexcept
2032  : _future(future), _state(state) {
2033  _future->_promise = this;
2034 }
2035 
2036 template <typename SEASTAR_ELLIPSIS T>
2037 inline
2038 future<T SEASTAR_ELLIPSIS>
2040  assert(!this->_future && this->_state && !this->_task);
2041  return future<T SEASTAR_ELLIPSIS>(this);
2042 }
2043 
2044 template <typename SEASTAR_ELLIPSIS T>
2045 inline
2047  if (this->_state == &x._local_state) {
2048  this->_state = &_local_state;
2049  new (&_local_state) future_state(std::move(x._local_state));
2050  }
2051 }
2052 
2053 template <typename... T, typename... A>
2054 inline
2055 future<T...> make_ready_future(A&&... value) noexcept {
2056  return future<T...>(ready_future_marker(), std::forward<A>(value)...);
2057 }
2058 
2059 template <typename... T>
2060 inline
2061 future<T...> make_exception_future(std::exception_ptr&& ex) noexcept {
2062  return future<T...>(exception_future_marker(), std::move(ex));
2063 }
2064 
2065 template <typename... T>
2066 inline
2067 future<T...> internal::make_exception_future(future_state_base&& state) noexcept {
2068  return future<T...>(exception_future_marker(), std::move(state));
2069 }
2070 
2071 template <typename... T>
2074 }
2075 
2076 void log_exception_trace() noexcept;
2077 
2084 template <typename... T, typename Exception>
2085 inline
2086 future<T...> make_exception_future(Exception&& ex) noexcept {
2087  log_exception_trace();
2088  return make_exception_future<T...>(std::make_exception_ptr(std::forward<Exception>(ex)));
2089 }
2090 
2091 template <typename... T, typename Exception>
2092 future<T...> make_exception_future_with_backtrace(Exception&& ex) noexcept {
2093  return make_exception_future<T...>(make_backtraced_exception_ptr<Exception>(std::forward<Exception>(ex)));
2094 }
2095 
2097 
2099 
2100 template<typename T>
2101 template<typename Func, typename... FuncArgs>
2102 typename futurize<T>::type futurize<T>::apply(Func&& func, std::tuple<FuncArgs...>&& args) noexcept {
2103  try {
2104  using ret_t = decltype(std::apply(std::forward<Func>(func), std::move(args)));
2105  if constexpr (std::is_void_v<ret_t>) {
2106  std::apply(std::forward<Func>(func), std::move(args));
2107  return make_ready_future<>();
2108  } else if constexpr (is_future<ret_t>::value){
2109  return std::apply(std::forward<Func>(func), std::move(args));
2110  } else {
2111  return convert(std::apply(std::forward<Func>(func), std::move(args)));
2112  }
2113  } catch (...) {
2114  return current_exception_as_future();
2115  }
2116 }
2117 
2118 template<typename T>
2119 template<typename Func>
2120 SEASTAR_CONCEPT( requires std::invocable<Func> )
2121 void futurize<T>::satisfy_with_result_of(promise_base_with_type&& pr, Func&& func) {
2122  using ret_t = decltype(func());
2123  if constexpr (std::is_void_v<ret_t>) {
2124  func();
2125  pr.set_value();
2126  } else if constexpr (is_future<ret_t>::value) {
2127  func().forward_to(std::move(pr));
2128  } else {
2129  pr.set_value(func());
2130  }
2131 }
2132 
2133 template<typename T>
2134 template<typename Func, typename... FuncArgs>
2135 typename futurize<T>::type futurize<T>::invoke(Func&& func, FuncArgs&&... args) noexcept {
2136  try {
2137  using ret_t = decltype(func(std::forward<FuncArgs>(args)...));
2138  if constexpr (std::is_void_v<ret_t>) {
2139  func(std::forward<FuncArgs>(args)...);
2140  return make_ready_future<>();
2141  } else if constexpr (is_future<ret_t>::value) {
2142  return func(std::forward<FuncArgs>(args)...);
2143  } else {
2144  return convert(func(std::forward<FuncArgs>(args)...));
2145  }
2146  } catch (...) {
2147  return current_exception_as_future();
2148  }
2149 }
2150 
2151 template <typename T>
2152 template <typename Arg>
2153 inline
2154 future<T>
2158  return make_exception_future<T>(std::forward<Arg>(arg));
2159 }
2160 
2161 template <typename Arg>
2162 inline
2163 future<>
2167  return make_exception_future<>(std::forward<Arg>(arg));
2168 }
2169 
2170 template<typename Func, typename... Args>
2171 auto futurize_invoke(Func&& func, Args&&... args) noexcept {
2172  using futurator = futurize<std::invoke_result_t<Func, Args&&...>>;
2173  return futurator::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
2174 }
2175 
2176 template<typename Func, typename... Args>
2177 [[deprecated("Use futurize_invoke for varargs")]]
2178 auto futurize_apply(Func&& func, Args&&... args) noexcept {
2179  return futurize_invoke(std::forward<Func>(func), std::forward<Args>(args)...);
2180 }
2181 
2182 template<typename Func, typename... Args>
2183 auto futurize_apply(Func&& func, std::tuple<Args...>&& args) noexcept {
2184  using futurator = futurize<std::invoke_result_t<Func, Args&&...>>;
2185  return futurator::apply(std::forward<Func>(func), std::move(args));
2186 }
2187 
2188 namespace internal {
2189 
2190 template <typename... T, typename U>
2191 inline
2192 void set_callback(future<T...>&& fut, U* callback) noexcept {
2193  // It would be better to use continuation_base<T...> for U, but
2194  // then a derived class of continuation_base<T...> won't be matched
2195  return std::move(fut).set_callback(callback);
2196 }
2197 
2198 }
2199 
2200 
2202 
2203 }
A representation of a possibly not-yet-computed value.
Definition: future.hh:1344
void wait() noexcept
Definition: future.hh:1479
Result then(Func &&func) noexcept
Schedule a block of code to run when the future is ready.
Definition: future.hh:1520
bool failed() const noexcept
Checks whether the future has failed.
Definition: future.hh:1498
bool available() const noexcept
Checks whether the future is available.
Definition: future.hh:1490
future< T > handle_exception(Func &&func) noexcept
Handle the exception carried by this future.
Definition: future.hh:1837
typename future_state::get0_return_type get0_return_type
Definition: future.hh:1465
internal::future_stored_type_t< T > value_type
The data type carried by the future.
Definition: future.hh:1422
future< T > handle_exception_type(Func &&func) noexcept
Handle the exception of a certain type carried by this future.
Definition: future.hh:1859
void forward_to(promise< T > &&pr) noexcept
Satisfy some promise object with this future as a result.
Definition: future.hh:1720
futurize_t< FuncResult > then_wrapped(Func &&func) &noexcept
Schedule a block of code to run when the future is ready, allowing for exception handling.
Definition: future.hh:1634
Result then_unpack(Func &&func) noexcept
Schedule a block of code to run when the future is ready, unpacking tuples.
Definition: future.hh:1563
future(future &&x) noexcept
Moves the future into a new object.
Definition: future.hh:1428
value_type && get()
gets the value returned by the computation
Definition: future.hh:1447
future discard_result() noexcept
Discards the value carried by this future.
Definition: future.hh:1812
future or_terminate() noexcept
Terminate the program if this future fails.
Definition: future.hh:1798
void ignore_ready_future() noexcept
Ignore any result hold by this future.
Definition: future.hh:1878
Definition: future.hh:1757
promise - allows a future value to be made available at a later time.
Definition: future.hh:964
void set_to_current_exception() noexcept
Definition: future.hh:993
std::enable_if_t<!std::is_same< std::remove_reference_t< Exception >, std::exception_ptr >::value, void > set_exception(Exception &&e) noexcept
Marks the promise as failed.
Definition: future.hh:1041
void set_exception(std::exception_ptr &&ex) noexcept
Marks the promise as failed.
Definition: future.hh:1028
promise() noexcept
Constructs an empty promise.
Definition: future.hh:972
Like future except the result can be waited for by many fibers.
Definition: shared_future.hh:99
future< T... > make_exception_future(std::exception_ptr &&value) noexcept
Creates a future in an available, failed state.
Definition: future.hh:2061
future< T > get_future() noexcept
Gets the promise's associated future.
Definition: future.hh:2039
future< T... > make_exception_future(Exception &&ex) noexcept
Creates a future in an available, failed state.
Definition: future.hh:2086
future< T... > make_ready_future(A &&... value) noexcept
Creates a future in an available, value state.
Definition: future.hh:2055
future< T... > current_exception_as_future() noexcept
Returns std::current_exception() wrapped in a future.
Definition: future.hh:2072
void move_it(promise &&x) noexcept
Moves a promise object.
Definition: future.hh:2046
Definition: future.hh:579
Definition: future.hh:578
Definition: critical_alloc_section.hh:80
Seastar API namespace.
Definition: abort_on_ebadf.hh:24
Definition: noncopyable_function.hh:33
Definition: function_traits.hh:62
Exception type for broken promises.
Definition: future.hh:213
Definition: future.hh:432
friend future< U... > current_exception_as_future() noexcept
Returns std::current_exception() wrapped in a future.
Definition: future.hh:2072
Converts a type to a future type, if it isn't already.
Definition: future.hh:1963
static type apply(Func &&func, FuncArgs &&... args) noexcept
Deprecated alias of invoke.
Definition: future.hh:1992
static type from_tuple(tuple_type &&value)
Convert the tuple representation into a future.
Definition: future.hh:2001
static type from_tuple(value_type &&value)
Convert the tuple representation into a future.
Definition: future.hh:2011
static type apply(Func &&func, std::tuple< FuncArgs... > &&args) noexcept
static type from_tuple(const value_type &value)
Convert the tuple representation into a future.
Definition: future.hh:2015
static type from_tuple(const tuple_type &value)
Convert the tuple representation into a future.
Definition: future.hh:2005
typename type::value_type value_type
The value tuple type associated with type.
Definition: future.hh:1969
static type invoke(Func &&func, FuncArgs &&... args) noexcept
Check whether a type is a future.
Definition: future.hh:1072
Definition: future.hh:46
Definition: future.hh:448