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 #pragma GCC diagnostic push
599  // This function may copy uninitialized memory, such as when
600  // creating an uninitialized promise and calling get_future()
601  // on it. Gcc 12 started to catch some simple cases of this
602  // at compile time, so we need to tell it that it's fine.
603 #pragma GCC diagnostic ignored "-Wuninitialized"
604  memmove(reinterpret_cast<char*>(&this->uninitialized_get()),
605  &x.uninitialized_get(),
606  internal::used_size<internal::maybe_wrap_ref<T>>::value);
607 #pragma GCC diagnostic pop
608  } else if (_u.has_result()) {
609  this->uninitialized_set(std::move(x.uninitialized_get()));
610  std::destroy_at(&x.uninitialized_get());
611  }
612  }
613 
614  [[gnu::always_inline]]
615  future_state(future_state&& x) noexcept : future_state_base(std::move(x)) {
616  move_it(std::move(x));
617  }
618 
619  void clear() noexcept {
620  if (_u.has_result()) {
621  std::destroy_at(&this->uninitialized_get());
622  } else {
623  _u.check_failure();
624  }
625  }
626  __attribute__((always_inline))
627  ~future_state() noexcept {
628  clear();
629  }
630  future_state& operator=(future_state&& x) noexcept {
631  clear();
632  future_state_base::operator=(std::move(x));
633  // If &x == this, _u.st is now state::invalid and so it is
634  // safe to call move_it.
635  move_it(std::move(x));
636  return *this;
637  }
638  template <typename... A>
639  future_state(ready_future_marker, A&&... a) noexcept : future_state_base(state::result) {
640  try {
641  this->uninitialized_set(std::forward<A>(a)...);
642  } catch (...) {
643  new (this) future_state(current_exception_future_marker());
644  }
645  }
646  template <typename... A>
647  void set(A&&... a) noexcept {
648  assert(_u.st == state::future);
649  new (this) future_state(ready_future_marker(), std::forward<A>(a)...);
650  }
651  future_state(exception_future_marker, std::exception_ptr&& ex) noexcept : future_state_base(std::move(ex)) { }
652  future_state(exception_future_marker, future_state_base&& state) noexcept : future_state_base(std::move(state)) { }
653  future_state(current_exception_future_marker m) noexcept : future_state_base(m) { }
654  future_state(nested_exception_marker m, future_state_base&& old) noexcept : future_state_base(m, std::move(old)) { }
655  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)) { }
656  T&& get_value() && noexcept {
657  assert(_u.st == state::result);
658  return static_cast<T&&>(this->uninitialized_get());
659  }
660  T&& take_value() && noexcept {
661  assert(_u.st == state::result);
662  _u.st = state::result_unavailable;
663  return static_cast<T&&>(this->uninitialized_get());
664  }
665  template<typename U = T>
666  const std::enable_if_t<std::is_copy_constructible<U>::value, U>& get_value() const& noexcept(copy_noexcept) {
667  assert(_u.st == state::result);
668  return this->uninitialized_get();
669  }
670  T&& take() && {
671  assert(available());
672  if (_u.st >= state::exception_min) {
673  std::move(*this).rethrow_exception();
674  }
675  _u.st = state::result_unavailable;
676  return static_cast<T&&>(this->uninitialized_get());
677  }
678  T&& get() && {
679  assert(available());
680  if (_u.st >= state::exception_min) {
681  std::move(*this).rethrow_exception();
682  }
683  return static_cast<T&&>(this->uninitialized_get());
684  }
685  const T& get() const& {
686  assert(available());
687  if (_u.st >= state::exception_min) {
688  rethrow_exception();
689  }
690  return this->uninitialized_get();
691  }
692  using get0_return_type = typename internal::get0_return_type<internal::future_tuple_type_t<T>>::type;
693  static get0_return_type get0(T&& x) {
694  return internal::get0_return_type<T>::get0(std::move(x));
695  }
696 
697  get0_return_type get0() {
698 #if SEASTAR_API_LEVEL < 5
699  return get0(std::move(*this).get());
700 #else
701  return std::move(*this).get();
702 #endif
703  }
704 };
705 
706 #if SEASTAR_API_LEVEL < 6
707 template <typename... T>
708 #else
709 template <typename T = void>
710 #endif
711 class continuation_base : public task {
712 protected:
713  using future_state = seastar::future_state<internal::future_stored_type_t<T SEASTAR_ELLIPSIS>>;
714  future_state _state;
715  using future_type = future<T SEASTAR_ELLIPSIS>;
716  using promise_type = promise<T SEASTAR_ELLIPSIS>;
717 public:
718  continuation_base() noexcept = default;
719  void set_state(future_state&& state) noexcept {
720  _state = std::move(state);
721  }
722  // This override of waiting_task() is needed here because there are cases
723  // when backtrace is obtained from the destructor of this class and objects
724  // of derived classes are already destroyed at that time. If we didn't
725  // have this override we would get a "pure virtual function call" exception.
726  virtual task* waiting_task() noexcept override { return nullptr; }
727  friend class internal::promise_base_with_type<T SEASTAR_ELLIPSIS>;
728  friend class promise<T SEASTAR_ELLIPSIS>;
729  friend class future<T SEASTAR_ELLIPSIS>;
730 };
731 
732 // Given a future type, find the corresponding continuation_base.
733 template <typename Future>
734 struct continuation_base_from_future;
735 
736 template <typename... T>
737 struct continuation_base_from_future<future<T...>> {
738  using type = continuation_base<T...>;
739 };
740 
741 template <typename Future>
742 using continuation_base_from_future_t = typename continuation_base_from_future<Future>::type;
743 
744 #if SEASTAR_API_LEVEL < 6
745 template <typename Promise, typename... T>
746 #else
747 template <typename Promise, typename T = void>
748 #endif
749 class continuation_base_with_promise : public continuation_base<T SEASTAR_ELLIPSIS> {
750  friend class internal::promise_base_with_type<T SEASTAR_ELLIPSIS>;
751 protected:
752  continuation_base_with_promise(Promise&& pr) noexcept : _pr(std::move(pr)) {
753  task::make_backtrace();
754  }
755  virtual task* waiting_task() noexcept override;
756  Promise _pr;
757 };
758 
759 #if SEASTAR_API_LEVEL < 6
760 template <typename Promise, typename Func, typename Wrapper, typename... T>
761 #else
762 template <typename Promise, typename Func, typename Wrapper, typename T = void>
763 #endif
764 struct continuation final : continuation_base_with_promise<Promise, T SEASTAR_ELLIPSIS> {
765  // Func is the original function passed to then/then_wrapped. The
766  // Wrapper is a helper function that implements the specific logic
767  // needed by then/then_wrapped. We call the wrapper passing it the
768  // original function, promise and state.
769  // Note that if Func's move constructor throws, this will call
770  // std::unexpected. We could try to require Func to be nothrow
771  // move constructible, but that will cause a lot of churn. Since
772  // we can't support a failure to create a continuation, calling
773  // std::unexpected as close to the failure as possible is the best
774  // we can do.
775  continuation(Promise&& pr, Func&& func, Wrapper&& wrapper) noexcept
776  : continuation_base_with_promise<Promise, T SEASTAR_ELLIPSIS>(std::move(pr))
777  , _func(std::move(func))
778  , _wrapper(std::move(wrapper)) {}
779  virtual void run_and_dispose() noexcept override {
780  try {
781  _wrapper(std::move(this->_pr), _func, std::move(this->_state));
782  } catch (...) {
783  this->_pr.set_to_current_exception();
784  }
785  delete this;
786  }
787  Func _func;
788  [[no_unique_address]] Wrapper _wrapper;
789 };
790 
791 #if SEASTAR_API_LEVEL < 4
792 
793 // This is an internal future<> payload for seastar::when_all_succeed(). It is used
794 // to return a variadic future (when two or more of its input futures were non-void),
795 // but with variadic futures deprecated and soon gone this is no longer possible.
796 //
797 // Instead, we use this tuple type, and future::then() knows to unpack it.
798 //
799 // The whole thing is temporary for a transition period.
800 template <typename... T>
801 struct when_all_succeed_tuple : std::tuple<T...> {
802  using std::tuple<T...>::tuple;
803  when_all_succeed_tuple(std::tuple<T...>&& t)
804  noexcept(std::is_nothrow_move_constructible<std::tuple<T...>>::value)
805  : std::tuple<T...>(std::move(t)) {}
806 };
807 
808 #endif
809 
810 namespace internal {
811 
812 template <typename... T>
813 future<T...> make_exception_future(future_state_base&& state) noexcept;
814 
815 template <typename... T, typename U>
816 void set_callback(future<T...>&& fut, U* callback) noexcept;
817 
818 class future_base;
819 
820 class promise_base {
821 protected:
822  enum class urgent { no, yes };
823  future_base* _future = nullptr;
824 
825  // This points to the future_state that is currently being
826  // used. See comment above the future_state struct definition for
827  // details.
828  future_state_base* _state;
829 
830  task* _task = nullptr;
831 
832  promise_base(const promise_base&) = delete;
833  promise_base(future_state_base* state) noexcept : _state(state) {}
834  promise_base(future_base* future, future_state_base* state) noexcept;
835  void move_it(promise_base&& x) noexcept;
836  promise_base(promise_base&& x) noexcept;
837 
838  void clear() noexcept;
839 
840  // We never need to destruct this polymorphicly, so we can make it
841  // protected instead of virtual
842  ~promise_base() noexcept {
843  clear();
844  }
845 
846  void operator=(const promise_base&) = delete;
847  promise_base& operator=(promise_base&& x) noexcept;
848 
849  template<urgent Urgent>
850  void make_ready() noexcept;
851 
852  template<typename T>
853  void set_exception_impl(T&& val) noexcept {
854  if (_state) {
855  _state->set_exception(std::move(val));
856  make_ready<urgent::no>();
857  } else {
858  // We get here if promise::get_future is called and the
859  // returned future is destroyed without creating a
860  // continuation.
861  // In older versions of seastar we would store a local
862  // copy of ex and warn in the promise destructor.
863  // Since there isn't any way for the user to clear
864  // the exception, we issue the warning from here.
865  report_failed_future(val);
866  }
867  }
868 
869  void set_exception(future_state_base&& state) noexcept {
870  set_exception_impl(std::move(state));
871  }
872 
873  void set_exception(std::exception_ptr&& ex) noexcept {
874  set_exception_impl(std::move(ex));
875  }
876 
877  void set_exception(const std::exception_ptr& ex) noexcept {
878  set_exception(std::exception_ptr(ex));
879  }
880 
881  template<typename Exception>
882  std::enable_if_t<!std::is_same<std::remove_reference_t<Exception>, std::exception_ptr>::value, void> set_exception(Exception&& e) noexcept {
883  set_exception(std::make_exception_ptr(std::forward<Exception>(e)));
884  }
885 
886  friend class future_base;
887  template <typename SEASTAR_ELLIPSIS U> friend class seastar::future;
888 
889 public:
894  void set_to_current_exception() noexcept;
895 
897  task* waiting_task() const noexcept { return _task; }
898 };
899 
906 template <typename SEASTAR_ELLIPSIS T>
907 class promise_base_with_type : protected internal::promise_base {
908 protected:
909  using future_state = seastar::future_state<future_stored_type_t<T SEASTAR_ELLIPSIS>>;
910  future_state* get_state() noexcept {
911  return static_cast<future_state*>(_state);
912  }
913  static constexpr bool copy_noexcept = future_state::copy_noexcept;
914 public:
915  promise_base_with_type(future_state_base* state) noexcept : promise_base(state) { }
916  promise_base_with_type(future<T SEASTAR_ELLIPSIS>* future) noexcept : promise_base(future, &future->_state) { }
917  promise_base_with_type(promise_base_with_type&& x) noexcept = default;
918  promise_base_with_type(const promise_base_with_type&) = delete;
919  promise_base_with_type& operator=(promise_base_with_type&& x) noexcept = default;
920  void operator=(const promise_base_with_type&) = delete;
921 
922  void set_urgent_state(future_state&& state) noexcept {
923  auto* ptr = get_state();
924  // The state can be null if the corresponding future has been
925  // destroyed without producing a continuation.
926  if (ptr) {
927  // FIXME: This is a fairly expensive assert. It would be a
928  // good candidate for being disabled in release builds if
929  // we had such an assert.
930  assert(ptr->_u.st == future_state_base::state::future);
931  new (ptr) future_state(std::move(state));
932  make_ready<urgent::yes>();
933  }
934  }
935 
936  template <typename... A>
937  void set_value(A&&... a) noexcept {
938  if (auto *s = get_state()) {
939  s->set(std::forward<A>(a)...);
940  make_ready<urgent::no>();
941  }
942  }
943 
948  void set_to_current_exception() noexcept {
949  internal::promise_base::set_to_current_exception();
950  }
951 
953  using internal::promise_base::waiting_task;
954 
955 private:
956 
957  template <typename SEASTAR_ELLIPSIS U>
958  friend class seastar::future;
959 
960  friend future_state;
961 };
962 }
964 
970 template <typename SEASTAR_ELLIPSIS T>
971 class promise : private internal::promise_base_with_type<T SEASTAR_ELLIPSIS> {
972  using future_state = typename internal::promise_base_with_type<T SEASTAR_ELLIPSIS>::future_state;
973  future_state _local_state;
974 
975 public:
979  promise() noexcept : internal::promise_base_with_type<T SEASTAR_ELLIPSIS>(&_local_state) {}
980 
982  void move_it(promise&& x) noexcept;
983  promise(promise&& x) noexcept : internal::promise_base_with_type<T SEASTAR_ELLIPSIS>(std::move(x)) {
984  move_it(std::move(x));
985  }
986  promise(const promise&) = delete;
987  promise& operator=(promise&& x) noexcept {
988  internal::promise_base_with_type<T SEASTAR_ELLIPSIS>::operator=(std::move(x));
989  // If this is a self-move, _state is now nullptr and it is
990  // safe to call move_it.
991  move_it(std::move(x));
992  return *this;
993  }
994  void operator=(const promise&) = delete;
995 
1000  void set_to_current_exception() noexcept {
1001  internal::promise_base::set_to_current_exception();
1002  }
1003 
1005  using internal::promise_base::waiting_task;
1006 
1014 
1026  template <typename... A>
1027  void set_value(A&&... a) noexcept {
1028  internal::promise_base_with_type<T SEASTAR_ELLIPSIS>::set_value(std::forward<A>(a)...);
1029  }
1030 
1035  void set_exception(std::exception_ptr&& ex) noexcept {
1036  internal::promise_base::set_exception(std::move(ex));
1037  }
1038 
1039  void set_exception(const std::exception_ptr& ex) noexcept {
1040  internal::promise_base::set_exception(ex);
1041  }
1042 
1047  template<typename Exception>
1048  std::enable_if_t<!std::is_same<std::remove_reference_t<Exception>, std::exception_ptr>::value, void> set_exception(Exception&& e) noexcept {
1049  internal::promise_base::set_exception(std::forward<Exception>(e));
1050  }
1051 
1052  using internal::promise_base_with_type<T SEASTAR_ELLIPSIS>::set_urgent_state;
1053 
1054  template <typename SEASTAR_ELLIPSIS U>
1055  friend class future;
1056 };
1057 
1058 #if SEASTAR_API_LEVEL < 6
1064 template<>
1065 class promise<void> : public promise<> {};
1066 #endif
1067 
1069 
1072 
1073 
1079 template <typename... T> struct is_future : std::false_type {};
1080 
1083 template <typename... T> struct is_future<future<T...>> : std::true_type {};
1084 
1086 
1087 
1091 template <typename T>
1092 struct futurize;
1093 
1094 SEASTAR_CONCEPT(
1095 
1096 template <typename T>
1097 concept Future = is_future<T>::value;
1098 
1099 template <typename Func, typename... T>
1100 concept CanInvoke = std::invocable<Func, T...>;
1101 
1102 // Deprecated alias
1103 template <typename Func, typename... T>
1104 concept CanApply = CanInvoke<Func, T...>;
1105 
1106 template <typename Func, typename... T>
1107 concept CanApplyTuple
1108  = sizeof...(T) == 1
1109  && requires (Func func, std::tuple<T...> wrapped_val) {
1110  { std::apply(func, std::get<0>(std::move(wrapped_val))) };
1111  };
1112 
1113 template <typename Func, typename Return, typename... T>
1114 concept InvokeReturns = requires (Func f, T... args) {
1115  { f(std::forward<T>(args)...) } -> std::same_as<Return>;
1116 };
1117 
1118 // Deprecated alias
1119 template <typename Func, typename Return, typename... T>
1120 concept ApplyReturns = InvokeReturns<Func, Return, T...>;
1121 
1122 template <typename Func, typename... T>
1123 concept InvokeReturnsAnyFuture = Future<std::invoke_result_t<Func, T...>>;
1124 
1125 // Deprecated alias
1126 template <typename Func, typename... T>
1127 concept ApplyReturnsAnyFuture = InvokeReturnsAnyFuture<Func, T...>;
1128 
1129 )
1130 
1132 
1133 // Converts a type to a future type, if it isn't already.
1134 template <typename T>
1135 using futurize_t = typename futurize<T>::type;
1136 
1138 
1139 template<typename Func, typename... Args>
1140 auto futurize_invoke(Func&& func, Args&&... args) noexcept;
1141 
1142 template<typename Func, typename... Args>
1143 auto futurize_apply(Func&& func, std::tuple<Args...>&& args) noexcept;
1144 
1147 namespace internal {
1148 class future_base {
1149 protected:
1150  promise_base* _promise;
1151  future_base() noexcept : _promise(nullptr) {}
1152  future_base(promise_base* promise, future_state_base* state) noexcept : _promise(promise) {
1153  _promise->_future = this;
1154  _promise->_state = state;
1155  }
1156 
1157  void move_it(future_base&& x, future_state_base* state) noexcept {
1158  _promise = x._promise;
1159  if (auto* p = _promise) {
1160  x.detach_promise();
1161  p->_future = this;
1162  p->_state = state;
1163  }
1164  }
1165 
1166  future_base(future_base&& x, future_state_base* state) noexcept {
1167  move_it(std::move(x), state);
1168  }
1169 
1170  void clear() noexcept {
1171  if (_promise) {
1172  detach_promise();
1173  }
1174  }
1175 
1176  ~future_base() noexcept {
1177  clear();
1178  }
1179 
1180  promise_base* detach_promise() noexcept {
1181  _promise->_state = nullptr;
1182  _promise->_future = nullptr;
1183  return std::exchange(_promise, nullptr);
1184  }
1185 
1186  void schedule(task* tws, future_state_base* state) noexcept {
1187  promise_base* p = detach_promise();
1188  p->_state = state;
1189  p->_task = tws;
1190  }
1191 
1192  void do_wait() noexcept;
1193 
1194 #ifdef SEASTAR_COROUTINES_ENABLED
1195  void set_coroutine(task& coroutine) noexcept;
1196 #endif
1197 
1198  friend class promise_base;
1199 };
1200 
1201 template <typename Func, typename... T>
1202 struct future_result {
1203  using type = std::invoke_result_t<Func, T...>;
1204  using future_type = futurize_t<type>;
1205  using func_type = future_type (T&&...);
1206 };
1207 
1208 template <typename Func>
1209 struct future_result<Func, void> {
1210  using type = std::invoke_result_t<Func>;
1211  using future_type = futurize_t<type>;
1212  using func_type = future_type ();
1213 };
1214 
1215 template <typename Func, typename SEASTAR_ELLIPSIS T>
1216 using future_result_t = typename future_result<Func, T SEASTAR_ELLIPSIS>::type;
1217 
1218 template <typename Func, typename T>
1219 auto future_invoke(Func&& func, T&& v) {
1220  if constexpr (std::is_same_v<T, monostate>) {
1221  return std::invoke(std::forward<Func>(func));
1222  } else {
1223  return std::invoke(std::forward<Func>(func), std::forward<T>(v));
1224  }
1225 }
1226 
1227 // This is a customization point for future::then()'s implementation.
1228 // It behaves differently when the future value type is a when_all_succeed_tuple
1229 // instantiation, indicating we need to unpack the tuple into multiple lambda
1230 // arguments.
1231 template <typename Future>
1232 struct call_then_impl;
1233 
1234 // Generic case - the input is not a future<when_all_succeed_tuple<...>>, so
1235 // we just forward everything to future::then_impl.
1236 template <typename... T>
1237 struct call_then_impl<future<T...>> {
1238  template <typename Func>
1239  using result_type = typename future_result<Func, T...>::future_type;
1240 
1241  template <typename Func>
1242  using func_type = typename future_result<Func, T...>::func_type;
1243 
1244  template <typename Func>
1245  static result_type<Func> run(future<T...>& fut, Func&& func) noexcept {
1246  return fut.then_impl(std::forward<Func>(func));
1247  }
1248 };
1249 
1250 #if SEASTAR_API_LEVEL < 4
1251 
1252 // Special case: we unpack the tuple before calling the function
1253 template <typename... T>
1254 struct call_then_impl<future<when_all_succeed_tuple<T...>>> {
1255  template <typename Func>
1256  using result_type = futurize_t<std::invoke_result_t<Func, T&&...>>;
1257 
1258  template <typename Func>
1259  using func_type = result_type<Func> (T&&...);
1260 
1261  using was_tuple = when_all_succeed_tuple<T...>;
1262  using std_tuple = std::tuple<T...>;
1263 
1264  template <typename Func>
1265  static auto run(future<was_tuple>& fut, Func&& func) noexcept {
1266  // constructing func in the lambda can throw, but there's nothing we can do
1267  // about it, similar to #84.
1268  return fut.then_impl([func = std::forward<Func>(func)] (was_tuple&& t) mutable {
1269  return std::apply(func, static_cast<std_tuple&&>(std::move(t)));
1270  });
1271  }
1272 };
1273 
1274 #endif
1275 
1276 template <typename Func, typename... Args>
1277 using call_then_impl_result_type = typename call_then_impl<future<Args...>>::template result_type<Func>;
1278 
1279 SEASTAR_CONCEPT(
1280 template <typename Func, typename... Args>
1281 concept CanInvokeWhenAllSucceed = requires {
1282  typename call_then_impl_result_type<Func, Args...>;
1283 };
1284 )
1285 
1286 template <typename Func, typename... T>
1287 struct result_of_apply {
1288  // no "type" member if not a function call signature or not a tuple
1289 };
1290 
1291 template <typename Func, typename... T>
1292 struct result_of_apply<Func, std::tuple<T...>> : std::invoke_result<Func, T...> {
1293  // Let std::invoke_result_t determine the result if the input is a tuple
1294 };
1295 
1296 template <typename Func, typename... T>
1297 using result_of_apply_t = typename result_of_apply<Func, T...>::type;
1298 
1299 }
1300 
1301 template <typename Promise, typename SEASTAR_ELLIPSIS T>
1302 task* continuation_base_with_promise<Promise, T SEASTAR_ELLIPSIS>::waiting_task() noexcept {
1303  return _pr.waiting_task();
1304 }
1305 
1348 template <typename SEASTAR_ELLIPSIS T>
1349 class SEASTAR_NODISCARD future : private internal::future_base {
1350  using future_state = seastar::future_state<internal::future_stored_type_t<T SEASTAR_ELLIPSIS>>;
1351  future_state _state;
1352  static constexpr bool copy_noexcept = future_state::copy_noexcept;
1353  using call_then_impl = internal::call_then_impl<future>;
1354 
1355 private:
1356  // This constructor creates a future that is not ready but has no
1357  // associated promise yet. The use case is to have a less flexible
1358  // but more efficient future/promise pair where we know that
1359  // promise::set_value cannot possibly be called without a matching
1360  // future and so that promise doesn't need to store a
1361  // future_state.
1363 
1364  future(promise<T SEASTAR_ELLIPSIS>* pr) noexcept : future_base(pr, &_state), _state(std::move(pr->_local_state)) { }
1365  template <typename... A>
1366  future(ready_future_marker m, A&&... a) noexcept : _state(m, std::forward<A>(a)...) { }
1368  future(future_state_base::nested_exception_marker m, future_state_base&& old) noexcept : _state(m, std::move(old)) {}
1369  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)) {}
1370  future(exception_future_marker m, std::exception_ptr&& ex) noexcept : _state(m, std::move(ex)) { }
1371  future(exception_future_marker m, future_state_base&& state) noexcept : _state(m, std::move(state)) { }
1372  [[gnu::always_inline]]
1373  explicit future(future_state&& state) noexcept
1374  : _state(std::move(state)) {
1375  }
1376  internal::promise_base_with_type<T SEASTAR_ELLIPSIS> get_promise() noexcept {
1377  assert(!_promise);
1378  return internal::promise_base_with_type<T SEASTAR_ELLIPSIS>(this);
1379  }
1380  internal::promise_base_with_type<T SEASTAR_ELLIPSIS>* detach_promise() noexcept {
1381  return static_cast<internal::promise_base_with_type<T SEASTAR_ELLIPSIS>*>(future_base::detach_promise());
1382  }
1383  void schedule(continuation_base<T SEASTAR_ELLIPSIS>* tws) noexcept {
1384  future_base::schedule(tws, &tws->_state);
1385  }
1386  template <typename Pr, typename Func, typename Wrapper>
1387  void schedule(Pr&& pr, Func&& func, Wrapper&& wrapper) noexcept {
1388  // If this new throws a std::bad_alloc there is nothing that
1389  // can be done about it. The corresponding future is not ready
1390  // and we cannot break the chain. Since this function is
1391  // noexcept, it will call std::terminate if new throws.
1393  auto tws = new continuation<Pr, Func, Wrapper, T SEASTAR_ELLIPSIS>(std::move(pr), std::move(func), std::move(wrapper));
1394  // In a debug build we schedule ready futures, but not in
1395  // other build modes.
1396 #ifdef SEASTAR_DEBUG
1397  if (_state.available()) {
1398  tws->set_state(std::move(_state));
1399  ::seastar::schedule(tws);
1400  return;
1401  }
1402 #endif
1403  schedule(tws);
1404  _state._u.st = future_state_base::state::invalid;
1405  }
1406 
1407  [[gnu::always_inline]]
1408  future_state&& get_available_state_ref() noexcept {
1409  if (_promise) {
1410  detach_promise();
1411  }
1412  return std::move(_state);
1413  }
1414 
1415  future<T SEASTAR_ELLIPSIS> rethrow_with_nested(future_state_base&& n) noexcept {
1416  return future<T SEASTAR_ELLIPSIS>(future_state_base::nested_exception_marker(), std::move(n), std::move(_state));
1417  }
1418 
1419  future<T SEASTAR_ELLIPSIS> rethrow_with_nested() noexcept {
1421  }
1422 
1423  template<typename... U>
1424  friend class shared_future;
1425 public:
1427  using value_type = internal::future_stored_type_t<T SEASTAR_ELLIPSIS>;
1428  using tuple_type = internal::future_tuple_type_t<value_type>;
1432  [[gnu::always_inline]]
1433  future(future&& x) noexcept : future_base(std::move(x), &_state), _state(std::move(x._state)) { }
1434  future(const future&) = delete;
1435  future& operator=(future&& x) noexcept {
1436  clear();
1437  move_it(std::move(x), &_state);
1438  _state = std::move(x._state);
1439  return *this;
1440  }
1441  void operator=(const future&) = delete;
1451  [[gnu::always_inline]]
1453  wait();
1454  return get_available_state_ref().take();
1455  }
1456 
1457  [[gnu::always_inline]]
1458  std::exception_ptr get_exception() noexcept {
1459  return get_available_state_ref().get_exception();
1460  }
1461 
1470  using get0_return_type = typename future_state::get0_return_type;
1471  get0_return_type get0() {
1472 #if SEASTAR_API_LEVEL < 5
1473  return future_state::get0(get());
1474 #else
1475  return (get0_return_type)get();
1476 #endif
1477  }
1478 
1484  void wait() noexcept {
1485  if (_state.available()) {
1486  return;
1487  }
1488  do_wait();
1489  }
1490 
1494  [[gnu::always_inline]]
1495  bool available() const noexcept {
1496  return _state.available();
1497  }
1498 
1502  [[gnu::always_inline]]
1503  bool failed() const noexcept {
1504  return _state.failed();
1505  }
1506 
1522  template <typename Func, typename Result = futurize_t<typename call_then_impl::template result_type<Func>>>
1523  SEASTAR_CONCEPT( requires std::invocable<Func, T SEASTAR_ELLIPSIS> || internal::CanInvokeWhenAllSucceed<Func, T SEASTAR_ELLIPSIS>)
1524  Result
1525  then(Func&& func) noexcept {
1526  // The implementation of then() is customized via the call_then_impl helper
1527  // template, in order to special case the results of when_all_succeed().
1528  // when_all_succeed() used to return a variadic future, which is deprecated, so
1529  // now it returns a when_all_succeed_tuple, which we intercept in call_then_impl,
1530  // and treat it as a variadic future.
1531 #ifndef SEASTAR_TYPE_ERASE_MORE
1532  return call_then_impl::run(*this, std::move(func));
1533 #else
1534  using func_type = typename call_then_impl::template func_type<Func>;
1536  {
1538  ncf = noncopyable_function<func_type>([func = std::forward<Func>(func)](auto&&... args) mutable {
1539  return futurize_invoke(func, std::forward<decltype(args)>(args)...);
1540  });
1541  }
1542  return call_then_impl::run(*this, std::move(ncf));
1543 #endif
1544  }
1545 
1565  template <typename Func, typename Result = futurize_t<internal::result_of_apply_t<Func, T SEASTAR_ELLIPSIS>>>
1566  SEASTAR_CONCEPT( requires ::seastar::CanApplyTuple<Func, T SEASTAR_ELLIPSIS>)
1567  Result
1568  then_unpack(Func&& func) noexcept {
1569  return then([func = std::forward<Func>(func)] (T&& SEASTAR_ELLIPSIS tuple) mutable {
1570  // sizeof...(tuple) is required to be 1
1571  return std::apply(func, std::move(tuple) SEASTAR_ELLIPSIS);
1572  });
1573  }
1574 
1575 private:
1576 
1577  // Keep this simple so that Named Return Value Optimization is used.
1578  template <typename Func, typename Result>
1579  Result then_impl_nrvo(Func&& func) noexcept {
1581  typename futurator::type fut(future_for_get_promise_marker{});
1582  using pr_type = decltype(fut.get_promise());
1583  schedule(fut.get_promise(), std::move(func), [](pr_type&& pr, Func& func, future_state&& state) {
1584  if (state.failed()) {
1585  pr.set_exception(static_cast<future_state_base&&>(std::move(state)));
1586  } else {
1587  futurator::satisfy_with_result_of(std::move(pr), [&func, &state] {
1588 #if SEASTAR_API_LEVEL < 5
1589  return std::apply(func, std::move(state).get_value());
1590 #else
1591  // clang thinks that "state" is not used, below, for future<>.
1592  // Make it think it is used to avoid an unused-lambda-capture warning.
1593  (void)state;
1594  return internal::future_invoke(func, std::move(state).get_value());
1595 #endif
1596  });
1597  }
1598  });
1599  return fut;
1600  }
1601 
1602  template <typename Func, typename Result = futurize_t<internal::future_result_t<Func, T SEASTAR_ELLIPSIS>>>
1603  Result
1604  then_impl(Func&& func) noexcept {
1605 #ifndef SEASTAR_DEBUG
1606  using futurator = futurize<internal::future_result_t<Func, T SEASTAR_ELLIPSIS>>;
1607  if (failed()) {
1608  return futurator::make_exception_future(static_cast<future_state_base&&>(get_available_state_ref()));
1609  } else if (available()) {
1610 #if SEASTAR_API_LEVEL < 5
1611  return futurator::apply(std::forward<Func>(func), get_available_state_ref().take_value());
1612 #else
1613  return futurator::invoke(std::forward<Func>(func), get_available_state_ref().take_value());
1614 #endif
1615  }
1616 #endif
1617  return then_impl_nrvo<Func, Result>(std::forward<Func>(func));
1618  }
1619 
1620 public:
1636  template <typename Func, typename FuncResult = std::invoke_result_t<Func, future>>
1637  SEASTAR_CONCEPT( requires std::invocable<Func, future> )
1638  futurize_t<FuncResult>
1639  then_wrapped(Func&& func) & noexcept {
1640  return then_wrapped_maybe_erase<false, FuncResult>(std::forward<Func>(func));
1641  }
1642 
1643  template <typename Func, typename FuncResult = std::invoke_result_t<Func, future&&>>
1644  SEASTAR_CONCEPT( requires std::invocable<Func, future&&> )
1645  futurize_t<FuncResult>
1646  then_wrapped(Func&& func) && noexcept {
1647  return then_wrapped_maybe_erase<true, FuncResult>(std::forward<Func>(func));
1648  }
1649 
1650 private:
1651 
1652  template <bool AsSelf, typename FuncResult, typename Func>
1653  futurize_t<FuncResult>
1654  then_wrapped_maybe_erase(Func&& func) noexcept {
1655 #ifndef SEASTAR_TYPE_ERASE_MORE
1656  return then_wrapped_common<AsSelf, FuncResult>(std::forward<Func>(func));
1657 #else
1658  using futurator = futurize<FuncResult>;
1659  using WrapFuncResult = typename futurator::type;
1660  noncopyable_function<WrapFuncResult (future&&)> ncf;
1661  {
1662  memory::scoped_critical_alloc_section _;
1663  ncf = noncopyable_function<WrapFuncResult(future &&)>([func = std::forward<Func>(func)](future&& f) mutable {
1664  return futurator::invoke(func, std::move(f));
1665  });
1666  }
1667  return then_wrapped_common<AsSelf, WrapFuncResult>(std::move(ncf));
1668 #endif
1669  }
1670 
1671  // Keep this simple so that Named Return Value Optimization is used.
1672  template <typename FuncResult, typename Func>
1673  futurize_t<FuncResult>
1674  then_wrapped_nrvo(Func&& func) noexcept {
1675  using futurator = futurize<FuncResult>;
1676  typename futurator::type fut(future_for_get_promise_marker{});
1677  using pr_type = decltype(fut.get_promise());
1678  schedule(fut.get_promise(), std::move(func), [](pr_type&& pr, Func& func, future_state&& state) {
1679  futurator::satisfy_with_result_of(std::move(pr), [&func, &state] {
1680  return func(future(std::move(state)));
1681  });
1682  });
1683  return fut;
1684  }
1685 
1686 
1687  template <bool AsSelf, typename FuncResult, typename Func>
1688  futurize_t<FuncResult>
1689  then_wrapped_common(Func&& func) noexcept {
1690 #ifndef SEASTAR_DEBUG
1691  using futurator = futurize<FuncResult>;
1692  if (available()) {
1693  if constexpr (AsSelf) {
1694  if (_promise) {
1695  detach_promise();
1696  }
1697  return futurator::invoke(std::forward<Func>(func), std::move(*this));
1698  } else {
1699  return futurator::invoke(std::forward<Func>(func), future(get_available_state_ref()));
1700  }
1701  }
1702 #endif
1703  return then_wrapped_nrvo<FuncResult, Func>(std::forward<Func>(func));
1704  }
1705 
1706  void forward_to(internal::promise_base_with_type<T SEASTAR_ELLIPSIS>&& pr) noexcept {
1707  if (_state.available()) {
1708  pr.set_urgent_state(std::move(_state));
1709  } else {
1710  *detach_promise() = std::move(pr);
1711  }
1712  }
1713 
1714 public:
1726  if (_state.available()) {
1727  pr.set_urgent_state(std::move(_state));
1728  } else if (&pr._local_state != pr._state) {
1729  // The only case when _state points to _local_state is
1730  // when get_future was never called. Given that pr will
1731  // soon be destroyed, we know get_future will never be
1732  // called and we can just ignore this request.
1733  *detach_promise() = std::move(pr);
1734  }
1735  }
1736 
1737 
1738 
1754  template <typename Func>
1755  SEASTAR_CONCEPT( requires std::invocable<Func> )
1756  future<T SEASTAR_ELLIPSIS> finally(Func&& func) noexcept {
1757  return then_wrapped(finally_body<Func, is_future<std::invoke_result_t<Func>>::value>(std::forward<Func>(func)));
1758  }
1759 
1760 
1761  template <typename Func, bool FuncReturnsFuture>
1763 
1764  template <typename Func>
1765  struct finally_body<Func, true> {
1766  Func _func;
1767 
1768  finally_body(Func&& func) noexcept : _func(std::forward<Func>(func))
1769  { }
1770 
1771  future<T SEASTAR_ELLIPSIS> operator()(future<T SEASTAR_ELLIPSIS>&& result) noexcept {
1772  return futurize_invoke(_func).then_wrapped([result = std::move(result)](auto&& f_res) mutable {
1773  if (!f_res.failed()) {
1774  return std::move(result);
1775  } else {
1776  return result.rethrow_with_nested(std::move(f_res._state));
1777  }
1778  });
1779  }
1780  };
1781 
1782  template <typename Func>
1783  struct finally_body<Func, false> {
1784  Func _func;
1785 
1786  finally_body(Func&& func) noexcept : _func(std::forward<Func>(func))
1787  { }
1788 
1789  future<T SEASTAR_ELLIPSIS> operator()(future<T SEASTAR_ELLIPSIS>&& result) noexcept {
1790  try {
1791  _func();
1792  return std::move(result);
1793  } catch (...) {
1794  return result.rethrow_with_nested();
1795  }
1796  };
1797  };
1798 
1803  future<> or_terminate() noexcept {
1804  return then_wrapped([] (auto&& f) {
1805  try {
1806  f.get();
1807  } catch (...) {
1808  engine_exit(std::current_exception());
1809  }
1810  });
1811  }
1812 
1818  // We need the generic variadic lambda, below, because then() behaves differently
1819  // when value_type is when_all_succeed_tuple
1820  return then([] (auto&&...) {});
1821  }
1822 
1836  template <typename Func>
1837  SEASTAR_CONCEPT( requires ::seastar::InvokeReturns<Func, future<T SEASTAR_ELLIPSIS>, std::exception_ptr>
1838  || (std::tuple_size_v<tuple_type> == 0 && ::seastar::InvokeReturns<Func, void, std::exception_ptr>)
1839  || (std::tuple_size_v<tuple_type> == 1 && ::seastar::InvokeReturns<Func, T, std::exception_ptr>)
1840  || (std::tuple_size_v<tuple_type> > 1 && ::seastar::InvokeReturns<Func, tuple_type, std::exception_ptr>)
1841  )
1842  future<T SEASTAR_ELLIPSIS> handle_exception(Func&& func) noexcept {
1843  return then_wrapped([func = std::forward<Func>(func)]
1844  (auto&& fut) mutable -> future<T SEASTAR_ELLIPSIS> {
1845  if (!fut.failed()) {
1846  return make_ready_future<T SEASTAR_ELLIPSIS>(fut.get());
1847  } else {
1848  return futurize_invoke(func, fut.get_exception());
1849  }
1850  });
1851  }
1852 
1863  template <typename Func>
1865  using trait = function_traits<Func>;
1866  static_assert(trait::arity == 1, "func can take only one parameter");
1867  using ex_type = typename trait::template arg<0>::type;
1868  return then_wrapped([func = std::forward<Func>(func)]
1869  (auto&& fut) mutable -> future<T SEASTAR_ELLIPSIS> {
1870  try {
1871  return make_ready_future<T SEASTAR_ELLIPSIS>(fut.get());
1872  } catch(ex_type& ex) {
1873  return futurize_invoke(func, ex);
1874  }
1875  });
1876  }
1877 
1883  void ignore_ready_future() noexcept {
1884  _state.ignore();
1885  }
1886 
1887 #ifdef SEASTAR_COROUTINES_ENABLED
1888  using future_base::set_coroutine;
1889 #endif
1890 private:
1891  void set_callback(continuation_base<T SEASTAR_ELLIPSIS>* callback) noexcept {
1892  if (_state.available()) {
1893  callback->set_state(get_available_state_ref());
1894  ::seastar::schedule(callback);
1895  } else {
1896  assert(_promise);
1897  schedule(callback);
1898  }
1899 
1900  }
1901 
1903  template <typename SEASTAR_ELLIPSIS U>
1904  friend class future;
1905  template <typename SEASTAR_ELLIPSIS U>
1906  friend class promise;
1907  template <typename U>
1908  friend struct futurize;
1909  template <typename SEASTAR_ELLIPSIS U>
1910  friend class internal::promise_base_with_type;
1911  template <typename... U, typename... A>
1912  friend future<U...> make_ready_future(A&&... value) noexcept;
1913  template <typename... U>
1914  friend future<U...> make_exception_future(std::exception_ptr&& ex) noexcept;
1915  template <typename... U, typename Exception>
1916  friend future<U...> make_exception_future(Exception&& ex) noexcept;
1917  template <typename... U>
1918  friend future<U...> internal::make_exception_future(future_state_base&& state) noexcept;
1919  template <typename... U>
1920  friend future<U...> current_exception_as_future() noexcept;
1921  template <typename... U, typename V>
1922  friend void internal::set_callback(future<U...>&&, V*) noexcept;
1923  template <typename Future>
1924  friend struct internal::call_then_impl;
1926 };
1927 
1928 
1929 namespace internal {
1930 template <typename T>
1931 struct futurize_base {
1933  using type = future<T>;
1935  using promise_type = promise<T>;
1936  using promise_base_with_type = internal::promise_base_with_type<T>;
1937 
1939  static inline type convert(T&& value) { return make_ready_future<T>(std::move(value)); }
1940  static inline type convert(type&& value) { return std::move(value); }
1941 
1943  template <typename Arg>
1944  static inline type make_exception_future(Arg&& arg) noexcept;
1945 };
1946 
1947 template <>
1948 struct futurize_base<void> {
1949  using type = future<>;
1950  using promise_type = promise<>;
1951  using promise_base_with_type = internal::promise_base_with_type<>;
1952 
1953  static inline type convert(type&& value) {
1954  return std::move(value);
1955  }
1956  template <typename Arg>
1957  static inline type make_exception_future(Arg&& arg) noexcept;
1958 };
1959 
1960 template <typename T>
1961 struct futurize_base<future<T>> : public futurize_base<T> {};
1962 
1963 template <>
1964 struct futurize_base<future<>> : public futurize_base<void> {};
1965 }
1966 
1967 template <typename T>
1968 struct futurize : public internal::futurize_base<T> {
1969  using base = internal::futurize_base<T>;
1970  using type = typename base::type;
1971  using promise_type = typename base::promise_type;
1972  using promise_base_with_type = typename base::promise_base_with_type;
1974  using value_type = typename type::value_type;
1975  using tuple_type = typename type::tuple_type;
1976  using base::convert;
1978 
1981  template<typename Func, typename... FuncArgs>
1982  static inline type apply(Func&& func, std::tuple<FuncArgs...>&& args) noexcept;
1983 
1986  template<typename Func, typename... FuncArgs>
1987  static inline type invoke(Func&& func, FuncArgs&&... args) noexcept;
1988 
1989  template<typename Func>
1990  static inline type invoke(Func&& func, internal::monostate) noexcept {
1991  return invoke(std::forward<Func>(func));
1992  }
1993 
1995  template<typename Func, typename... FuncArgs>
1996  [[deprecated("Use invoke for varargs")]]
1997  static inline type apply(Func&& func, FuncArgs&&... args) noexcept {
1998  return invoke(std::forward<Func>(func), std::forward<FuncArgs>(args)...);
1999  }
2000 
2001  static type current_exception_as_future() noexcept {
2003  }
2004 
2006  static type from_tuple(tuple_type&& value) {
2007  return type(ready_future_marker(), std::move(value));
2008  }
2010  static type from_tuple(const tuple_type& value) {
2011  return type(ready_future_marker(), value);
2012  }
2013 
2014 #if SEASTAR_API_LEVEL >= 5
2016  static type from_tuple(value_type&& value) {
2017  return type(ready_future_marker(), std::move(value));
2018  }
2020  static type from_tuple(const value_type& value) {
2021  return type(ready_future_marker(), value);
2022  }
2023 #endif
2024 private:
2028  template<typename Func>
2029  SEASTAR_CONCEPT( requires std::invocable<Func> )
2030  static void satisfy_with_result_of(promise_base_with_type&&, Func&& func);
2031 
2032  template <typename SEASTAR_ELLIPSIS U>
2033  friend class future;
2034 };
2035 
2036 inline internal::promise_base::promise_base(future_base* future, future_state_base* state) noexcept
2037  : _future(future), _state(state) {
2038  _future->_promise = this;
2039 }
2040 
2041 template <typename SEASTAR_ELLIPSIS T>
2042 inline
2043 future<T SEASTAR_ELLIPSIS>
2045  assert(!this->_future && this->_state && !this->_task);
2046  return future<T SEASTAR_ELLIPSIS>(this);
2047 }
2048 
2049 template <typename SEASTAR_ELLIPSIS T>
2050 inline
2052  if (this->_state == &x._local_state) {
2053  this->_state = &_local_state;
2054  new (&_local_state) future_state(std::move(x._local_state));
2055  }
2056 }
2057 
2058 template <typename... T, typename... A>
2059 inline
2060 future<T...> make_ready_future(A&&... value) noexcept {
2061  return future<T...>(ready_future_marker(), std::forward<A>(value)...);
2062 }
2063 
2064 template <typename... T>
2065 inline
2066 future<T...> make_exception_future(std::exception_ptr&& ex) noexcept {
2067  return future<T...>(exception_future_marker(), std::move(ex));
2068 }
2069 
2070 template <typename... T>
2071 inline
2072 future<T...> internal::make_exception_future(future_state_base&& state) noexcept {
2073  return future<T...>(exception_future_marker(), std::move(state));
2074 }
2075 
2076 template <typename... T>
2079 }
2080 
2081 void log_exception_trace() noexcept;
2082 
2089 template <typename... T, typename Exception>
2090 inline
2091 future<T...> make_exception_future(Exception&& ex) noexcept {
2092  log_exception_trace();
2093  return make_exception_future<T...>(std::make_exception_ptr(std::forward<Exception>(ex)));
2094 }
2095 
2096 template <typename... T, typename Exception>
2097 future<T...> make_exception_future_with_backtrace(Exception&& ex) noexcept {
2098  return make_exception_future<T...>(make_backtraced_exception_ptr<Exception>(std::forward<Exception>(ex)));
2099 }
2100 
2102 
2104 
2105 template<typename T>
2106 template<typename Func, typename... FuncArgs>
2107 typename futurize<T>::type futurize<T>::apply(Func&& func, std::tuple<FuncArgs...>&& args) noexcept {
2108  try {
2109  using ret_t = decltype(std::apply(std::forward<Func>(func), std::move(args)));
2110  if constexpr (std::is_void_v<ret_t>) {
2111  std::apply(std::forward<Func>(func), std::move(args));
2112  return make_ready_future<>();
2113  } else if constexpr (is_future<ret_t>::value){
2114  return std::apply(std::forward<Func>(func), std::move(args));
2115  } else {
2116  return convert(std::apply(std::forward<Func>(func), std::move(args)));
2117  }
2118  } catch (...) {
2119  return current_exception_as_future();
2120  }
2121 }
2122 
2123 template<typename T>
2124 template<typename Func>
2125 SEASTAR_CONCEPT( requires std::invocable<Func> )
2126 void futurize<T>::satisfy_with_result_of(promise_base_with_type&& pr, Func&& func) {
2127  using ret_t = decltype(func());
2128  if constexpr (std::is_void_v<ret_t>) {
2129  func();
2130  pr.set_value();
2131  } else if constexpr (is_future<ret_t>::value) {
2132  func().forward_to(std::move(pr));
2133  } else {
2134  pr.set_value(func());
2135  }
2136 }
2137 
2138 template<typename T>
2139 template<typename Func, typename... FuncArgs>
2140 typename futurize<T>::type futurize<T>::invoke(Func&& func, FuncArgs&&... args) noexcept {
2141  try {
2142  using ret_t = decltype(func(std::forward<FuncArgs>(args)...));
2143  if constexpr (std::is_void_v<ret_t>) {
2144  func(std::forward<FuncArgs>(args)...);
2145  return make_ready_future<>();
2146  } else if constexpr (is_future<ret_t>::value) {
2147  return func(std::forward<FuncArgs>(args)...);
2148  } else {
2149  return convert(func(std::forward<FuncArgs>(args)...));
2150  }
2151  } catch (...) {
2152  return current_exception_as_future();
2153  }
2154 }
2155 
2156 template <typename T>
2157 template <typename Arg>
2158 inline
2159 future<T>
2163  return make_exception_future<T>(std::forward<Arg>(arg));
2164 }
2165 
2166 template <typename Arg>
2167 inline
2168 future<>
2172  return make_exception_future<>(std::forward<Arg>(arg));
2173 }
2174 
2175 template<typename Func, typename... Args>
2176 auto futurize_invoke(Func&& func, Args&&... args) noexcept {
2177  using futurator = futurize<std::invoke_result_t<Func, Args&&...>>;
2178  return futurator::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
2179 }
2180 
2181 template<typename Func, typename... Args>
2182 [[deprecated("Use futurize_invoke for varargs")]]
2183 auto futurize_apply(Func&& func, Args&&... args) noexcept {
2184  return futurize_invoke(std::forward<Func>(func), std::forward<Args>(args)...);
2185 }
2186 
2187 template<typename Func, typename... Args>
2188 auto futurize_apply(Func&& func, std::tuple<Args...>&& args) noexcept {
2189  using futurator = futurize<std::invoke_result_t<Func, Args&&...>>;
2190  return futurator::apply(std::forward<Func>(func), std::move(args));
2191 }
2192 
2193 namespace internal {
2194 
2195 template <typename... T, typename U>
2196 inline
2197 void set_callback(future<T...>&& fut, U* callback) noexcept {
2198  // It would be better to use continuation_base<T...> for U, but
2199  // then a derived class of continuation_base<T...> won't be matched
2200  return std::move(fut).set_callback(callback);
2201 }
2202 
2203 }
2204 
2205 
2207 
2208 }
A representation of a possibly not-yet-computed value.
Definition: future.hh:1349
void wait() noexcept
Definition: future.hh:1484
Result then(Func &&func) noexcept
Schedule a block of code to run when the future is ready.
Definition: future.hh:1525
bool failed() const noexcept
Checks whether the future has failed.
Definition: future.hh:1503
bool available() const noexcept
Checks whether the future is available.
Definition: future.hh:1495
typename future_state::get0_return_type get0_return_type
Definition: future.hh:1470
internal::future_stored_type_t< T > value_type
The data type carried by the future.
Definition: future.hh:1427
future< T > handle_exception_type(Func &&func) noexcept
Handle the exception of a certain type carried by this future.
Definition: future.hh:1864
void forward_to(promise< T > &&pr) noexcept
Satisfy some promise object with this future as a result.
Definition: future.hh:1725
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:1639
Result then_unpack(Func &&func) noexcept
Schedule a block of code to run when the future is ready, unpacking tuples.
Definition: future.hh:1568
future(future &&x) noexcept
Moves the future into a new object.
Definition: future.hh:1433
value_type && get()
gets the value returned by the computation
Definition: future.hh:1452
future discard_result() noexcept
Discards the value carried by this future.
Definition: future.hh:1817
future or_terminate() noexcept
Terminate the program if this future fails.
Definition: future.hh:1803
void ignore_ready_future() noexcept
Ignore any result hold by this future.
Definition: future.hh:1883
Definition: future.hh:1762
promise - allows a future value to be made available at a later time.
Definition: future.hh:971
void set_to_current_exception() noexcept
Definition: future.hh:1000
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:1048
void set_exception(std::exception_ptr &&ex) noexcept
Marks the promise as failed.
Definition: future.hh:1035
promise() noexcept
Constructs an empty promise.
Definition: future.hh:979
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:2066
future< T > get_future() noexcept
Gets the promise's associated future.
Definition: future.hh:2044
future< T... > make_exception_future(Exception &&ex) noexcept
Creates a future in an available, failed state.
Definition: future.hh:2091
future< T... > make_ready_future(A &&... value) noexcept
Creates a future in an available, value state.
Definition: future.hh:2060
future< T... > current_exception_as_future() noexcept
Returns std::current_exception() wrapped in a future.
Definition: future.hh:2077
void move_it(promise &&x) noexcept
Moves a promise object.
Definition: future.hh:2051
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:2077
Converts a type to a future type, if it isn't already.
Definition: future.hh:1968
static type apply(Func &&func, FuncArgs &&... args) noexcept
Deprecated alias of invoke.
Definition: future.hh:1997
static type from_tuple(tuple_type &&value)
Convert the tuple representation into a future.
Definition: future.hh:2006
static type from_tuple(value_type &&value)
Convert the tuple representation into a future.
Definition: future.hh:2016
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:2020
static type from_tuple(const tuple_type &value)
Convert the tuple representation into a future.
Definition: future.hh:2010
typename type::value_type value_type
The value tuple type associated with type.
Definition: future.hh:1974
static type invoke(Func &&func, FuncArgs &&... args) noexcept
Check whether a type is a future.
Definition: future.hh:1079
Definition: future.hh:46
Definition: future.hh:448