31 #include <type_traits>
33 #include <seastar/core/task.hh>
34 #include <seastar/core/thread_impl.hh>
35 #include <seastar/core/function_traits.hh>
36 #include <seastar/util/critical_alloc_section.hh>
37 #include <seastar/util/concepts.hh>
38 #include <seastar/util/noncopyable_function.hh>
39 #include <seastar/util/backtrace.hh>
40 #include <seastar/util/std-compat.hh>
45 std::exception_ptr inner;
46 std::exception_ptr outer;
47 nested_exception(std::exception_ptr inner, std::exception_ptr outer) noexcept;
50 [[noreturn]]
void rethrow_nested()
const;
51 virtual const char* what()
const noexcept
override;
145 #if SEASTAR_API_LEVEL < 6
146 template <
class... T>
148 template <
class T =
void>
152 template <
class SEASTAR_ELLIPSIS T>
155 template <
typename... T>
166 template <
typename... T,
typename... A>
175 template <
typename... T>
178 template <
typename... T>
183 template <
typename... T>
188 template <
typename... T>
195 void engine_exit(std::exception_ptr eptr = {});
197 void report_failed_future(
const std::exception_ptr& ex) noexcept;
199 void report_failed_future(
const future_state_base& state) noexcept;
201 void with_allow_abandoned_failed_futures(
unsigned count, noncopyable_function<
void ()> func);
220 template <
typename... T>
227 #if SEASTAR_API_LEVEL < 6
228 template <
class... T>
230 template <
class T =
void>
232 class promise_base_with_type;
237 template <
typename... T>
238 struct future_stored_type;
241 struct future_stored_type<> {
242 #if SEASTAR_API_LEVEL < 5
243 using type = std::tuple<>;
245 using type = monostate;
249 template <
typename T>
250 struct future_stored_type<T> {
251 #if SEASTAR_API_LEVEL < 5
252 using type = std::tuple<T>;
254 using type = std::conditional_t<std::is_void_v<T>, internal::monostate, T>;
258 template <
typename... T>
259 using future_stored_type_t =
typename future_stored_type<T...>::type;
262 #if SEASTAR_API_LEVEL < 5
263 using future_tuple_type_t = T;
265 using future_tuple_type_t = std::conditional_t<std::is_same_v<T, monostate>, std::tuple<>, std::tuple<T>>;
270 template <
typename T>
271 struct get0_return_type;
274 struct get0_return_type<std::tuple<>> {
276 static type get0(std::tuple<>) { }
279 template <
typename T0,
typename... T>
280 struct get0_return_type<std::tuple<T0, T...>> {
282 static type get0(std::tuple<T0, T...> v) {
return std::get<0>(std::move(v)); }
286 using maybe_wrap_ref = std::conditional_t<std::is_reference_v<T>, std::reference_wrapper<std::remove_reference_t<T>>, T>;
295 template <
typename T,
bool is_trivial_
class>
296 struct uninitialized_wrapper_base;
298 template <
typename T>
299 struct uninitialized_wrapper_base<T, false> {
300 using tuple_type = future_tuple_type_t<T>;
305 maybe_wrap_ref<T> value;
309 uninitialized_wrapper_base() noexcept = default;
310 template<typename... U>
311 std::enable_if_t<!std::is_same_v<std::tuple<std::remove_cv_t<U>...>, std::tuple<tuple_type>>,
void>
312 uninitialized_set(U&&... vs) {
313 new (&_v.value) maybe_wrap_ref<T>{T(std::forward<U>(vs)...)};
315 void uninitialized_set(tuple_type&& v) {
316 uninitialized_set(std::move(std::get<0>(v)));
318 void uninitialized_set(
const tuple_type& v) {
319 uninitialized_set(std::get<0>(v));
321 maybe_wrap_ref<T>& uninitialized_get() {
324 const maybe_wrap_ref<T>& uninitialized_get()
const {
329 template <
typename T>
struct uninitialized_wrapper_base<T, true> :
private T {
330 using tuple_type = future_tuple_type_t<T>;
331 uninitialized_wrapper_base() noexcept = default;
332 template<typename... U>
333 std::enable_if_t<!std::is_same_v<std::tuple<std::remove_cv_t<U>...>, std::tuple<tuple_type>>,
void>
334 uninitialized_set(U&&... vs) {
335 new (
this) T(std::forward<U>(vs)...);
337 void uninitialized_set(tuple_type&& v) {
338 if constexpr (std::tuple_size_v<tuple_type> != 0) {
339 uninitialized_set(std::move(std::get<0>(v)));
342 void uninitialized_set(
const tuple_type& v) {
343 if constexpr (std::tuple_size_v<tuple_type> != 0) {
344 uninitialized_set(std::get<0>(v));
347 T& uninitialized_get() {
350 const T& uninitialized_get()
const {
355 template <
typename T>
356 constexpr
bool can_inherit =
357 #ifdef _LIBCPP_VERSION
364 std::is_same<std::tuple<>, T>::value ||
366 (std::is_trivially_destructible<T>::value && std::is_trivially_constructible<T>::value &&
367 std::is_class<T>::value && !std::is_final<T>::value);
371 template <
typename T>
372 struct uninitialized_wrapper
373 :
public uninitialized_wrapper_base<T, can_inherit<T>> {};
375 template <
typename T>
376 struct is_trivially_move_constructible_and_destructible {
377 static constexpr
bool value = std::is_trivially_move_constructible<T>::value && std::is_trivially_destructible<T>::value;
381 struct all_true : std::false_type {};
384 struct all_true<> : std::true_type {};
387 struct all_true<true, v...> :
public all_true<v...> {};
390 struct is_tuple_effectively_trivially_move_constructible_and_destructible_helper;
392 template <
typename... T>
393 struct is_tuple_effectively_trivially_move_constructible_and_destructible_helper<std::tuple<T...>> {
394 static constexpr
bool value = all_true<is_trivially_move_constructible_and_destructible<T>::value...>::value;
397 template <
typename T>
398 static constexpr
bool is_tuple_effectively_trivially_move_constructible_and_destructible =
399 is_tuple_effectively_trivially_move_constructible_and_destructible_helper<T>::value;
431 static_assert(
sizeof(std::exception_ptr) ==
sizeof(
void*),
"exception_ptr not a pointer");
432 enum class state : uintptr_t {
442 result_unavailable = 2,
447 any() noexcept { st = state::future; }
448 any(state s) noexcept { st = s; }
449 void set_exception(std::exception_ptr&& e) noexcept {
450 new (&ex) std::exception_ptr(std::move(e));
451 assert(st >= state::exception_min);
453 any(std::exception_ptr&& e) noexcept {
454 set_exception(std::move(e));
457 bool valid()
const noexcept {
return st != state::invalid && st != state::result_unavailable; }
458 bool available()
const noexcept {
return st == state::result || st >= state::exception_min; }
459 bool failed()
const noexcept {
return __builtin_expect(st >= state::exception_min,
false); }
460 void check_failure() noexcept;
462 std::exception_ptr take_exception() noexcept {
463 std::exception_ptr ret(std::move(ex));
476 void move_it(
any&& x) noexcept {
485 memmove(
static_cast<void*
>(
this), &x,
sizeof(
any));
486 x.st = state::invalid;
488 if (x.st < state::exception_min) {
490 x.st = state::invalid;
492 new (&ex) std::exception_ptr(x.take_exception());
497 move_it(std::move(x));
499 any& operator=(
any&& x) noexcept {
504 move_it(std::move(x));
507 bool has_result()
const noexcept {
508 return st == state::result || st == state::result_unavailable;
511 std::exception_ptr ex;
517 future_state_base(future_state_base&& x) noexcept : _u(std::move(x._u)) { }
529 void rethrow_exception() &&;
530 void rethrow_exception() const&;
534 bool valid() const noexcept {
return _u.valid(); }
535 bool available() const noexcept {
return _u.available(); }
536 bool failed() const noexcept {
return _u.failed(); }
538 void ignore() noexcept;
540 void set_exception(std::exception_ptr&& ex) noexcept {
541 assert(_u.st == state::future);
542 _u.set_exception(std::move(ex));
544 future_state_base& operator=(future_state_base&& x) noexcept =
default;
545 void set_exception(future_state_base&& state) noexcept {
546 assert(_u.st == state::future);
547 *
this = std::move(state);
549 std::exception_ptr get_exception() && noexcept {
550 assert(_u.st >= state::exception_min);
552 return _u.take_exception();
554 const std::exception_ptr& get_exception() const& noexcept {
555 assert(_u.st >= state::exception_min);
558 template <
typename U>
559 friend struct future_state;
560 template <
typename... U>
562 template <typename SEASTAR_ELLIPSIS U>
564 template <typename T>
565 friend struct futurize;
568 void report_failed_future(future_state_base::any&& state) noexcept;
570 inline
void future_state_base::any::check_failure() noexcept {
572 report_failed_future(std::move(*
this));
581 template <
typename T>
582 struct future_state :
public future_state_base,
private internal::uninitialized_wrapper<T> {
583 static constexpr
bool copy_noexcept = std::is_nothrow_copy_constructible<T>::value;
584 #if SEASTAR_API_LEVEL < 5
585 static constexpr
bool has_trivial_move_and_destroy = internal::is_tuple_effectively_trivially_move_constructible_and_destructible<T>;
587 static constexpr
bool has_trivial_move_and_destroy = internal::is_trivially_move_constructible_and_destructible<T>::value;
589 static_assert(std::is_nothrow_move_constructible<T>::value,
590 "Types must be no-throw move constructible");
591 static_assert(std::is_nothrow_destructible<T>::value,
592 "Types must be no-throw destructible");
593 future_state() noexcept = default;
594 void move_it(future_state&& x) noexcept {
595 if constexpr (has_trivial_move_and_destroy) {
596 #pragma GCC diagnostic push
601 #pragma GCC diagnostic ignored "-Wuninitialized"
602 memmove(
reinterpret_cast<char*
>(&this->uninitialized_get()),
603 &x.uninitialized_get(),
604 internal::used_size<internal::maybe_wrap_ref<T>>::value);
605 #pragma GCC diagnostic pop
606 }
else if (_u.has_result()) {
607 this->uninitialized_set(std::move(x.uninitialized_get()));
608 std::destroy_at(&x.uninitialized_get());
612 [[gnu::always_inline]]
613 future_state(future_state&& x) noexcept : future_state_base(std::move(x)) {
614 move_it(std::move(x));
617 void clear() noexcept {
618 if (_u.has_result()) {
619 std::destroy_at(&this->uninitialized_get());
624 __attribute__((always_inline))
625 ~future_state() noexcept {
628 future_state& operator=(future_state&& x) noexcept {
630 future_state_base::operator=(std::move(x));
633 move_it(std::move(x));
636 template <
typename... A>
637 future_state(ready_future_marker, A&&... a) noexcept : future_state_base(state::result) {
639 this->uninitialized_set(std::forward<A>(a)...);
641 new (
this) future_state(current_exception_future_marker());
644 template <
typename... A>
645 void set(A&&... a) noexcept {
646 assert(_u.st == state::future);
647 new (
this) future_state(ready_future_marker(), std::forward<A>(a)...);
649 future_state(exception_future_marker, std::exception_ptr&& ex) noexcept : future_state_base(std::move(ex)) { }
650 future_state(exception_future_marker, future_state_base&& state) noexcept : future_state_base(std::move(state)) { }
651 future_state(current_exception_future_marker m) noexcept : future_state_base(m) { }
652 future_state(nested_exception_marker m, future_state_base&& old) noexcept : future_state_base(m, std::move(old)) { }
653 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)) { }
654 T&& get_value() && noexcept {
655 assert(_u.st == state::result);
656 return static_cast<T&&
>(this->uninitialized_get());
658 T&& take_value() && noexcept {
659 assert(_u.st == state::result);
660 _u.st = state::result_unavailable;
661 return static_cast<T&&
>(this->uninitialized_get());
663 template<
typename U = T>
664 const std::enable_if_t<std::is_copy_constructible<U>::value, U>& get_value() const& noexcept(copy_noexcept) {
665 assert(_u.st == state::result);
666 return this->uninitialized_get();
670 if (_u.st >= state::exception_min) {
671 std::move(*this).rethrow_exception();
673 _u.st = state::result_unavailable;
674 return static_cast<T&&
>(this->uninitialized_get());
678 if (_u.st >= state::exception_min) {
679 std::move(*this).rethrow_exception();
681 return static_cast<T&&
>(this->uninitialized_get());
683 const T& get() const& {
685 if (_u.st >= state::exception_min) {
688 return this->uninitialized_get();
690 using get0_return_type =
typename internal::get0_return_type<internal::future_tuple_type_t<T>>::type;
691 static get0_return_type get0(T&& x) {
692 return internal::get0_return_type<T>::get0(std::move(x));
695 get0_return_type get0() {
696 #if SEASTAR_API_LEVEL < 5
697 return get0(std::move(*this).get());
699 return std::move(*this).get();
704 #if SEASTAR_API_LEVEL < 6
705 template <
typename... T>
707 template <
typename T =
void>
709 class continuation_base :
public task {
711 using future_state = seastar::future_state<internal::future_stored_type_t<T SEASTAR_ELLIPSIS>>;
713 using future_type = future<T SEASTAR_ELLIPSIS>;
714 using promise_type = promise<T SEASTAR_ELLIPSIS>;
716 continuation_base() noexcept = default;
717 void set_state(future_state&& state) noexcept {
718 _state = std::move(state);
724 virtual task* waiting_task() noexcept
override {
return nullptr; }
725 friend class internal::promise_base_with_type<T SEASTAR_ELLIPSIS>;
726 friend class promise<T SEASTAR_ELLIPSIS>;
727 friend class future<T SEASTAR_ELLIPSIS>;
731 template <
typename Future>
732 struct continuation_base_from_future;
734 template <
typename... T>
735 struct continuation_base_from_future<future<T...>> {
736 using type = continuation_base<T...>;
739 template <
typename Future>
740 using continuation_base_from_future_t =
typename continuation_base_from_future<Future>::type;
742 #if SEASTAR_API_LEVEL < 6
743 template <
typename Promise,
typename... T>
745 template <
typename Promise,
typename T =
void>
747 class continuation_base_with_promise :
public continuation_base<T SEASTAR_ELLIPSIS> {
748 friend class internal::promise_base_with_type<T SEASTAR_ELLIPSIS>;
750 continuation_base_with_promise(Promise&& pr) noexcept : _pr(std::move(pr)) {
751 task::make_backtrace();
753 virtual task* waiting_task() noexcept override;
757 #if SEASTAR_API_LEVEL < 6
758 template <
typename Promise,
typename Func,
typename Wrapper,
typename... T>
760 template <
typename Promise,
typename Func,
typename Wrapper,
typename T =
void>
762 struct continuation final : continuation_base_with_promise<Promise, T SEASTAR_ELLIPSIS> {
773 continuation(Promise&& pr, Func&& func, Wrapper&& wrapper) noexcept
774 : continuation_base_with_promise<Promise, T SEASTAR_ELLIPSIS>(std::move(pr))
775 , _func(std::move(func))
776 , _wrapper(std::move(wrapper)) {}
777 virtual void run_and_dispose() noexcept
override {
779 _wrapper(std::move(this->_pr), _func, std::move(this->_state));
781 this->_pr.set_to_current_exception();
786 [[no_unique_address]] Wrapper _wrapper;
789 #if SEASTAR_API_LEVEL < 4
798 template <
typename... T>
799 struct when_all_succeed_tuple : std::tuple<T...> {
800 using std::tuple<T...>::tuple;
801 when_all_succeed_tuple(std::tuple<T...>&& t)
802 noexcept(std::is_nothrow_move_constructible<std::tuple<T...>>::value)
803 : std::tuple<T...>(std::move(t)) {}
810 template <
typename... T>
813 template <
typename... T,
typename U>
814 void set_callback(future<T...>&& fut, U* callback) noexcept;
820 enum class urgent { no, yes };
821 future_base* _future =
nullptr;
826 future_state_base* _state;
828 task* _task =
nullptr;
830 promise_base(
const promise_base&) =
delete;
831 promise_base(future_state_base* state) noexcept : _state(state) {}
832 promise_base(future_base* future, future_state_base* state) noexcept;
833 void move_it(promise_base&& x) noexcept;
834 promise_base(promise_base&& x) noexcept;
836 void clear() noexcept;
840 ~promise_base() noexcept {
844 void operator=(
const promise_base&) =
delete;
845 promise_base& operator=(promise_base&& x) noexcept;
847 template<urgent Urgent>
848 void make_ready() noexcept;
851 void set_exception_impl(T&& val) noexcept {
853 _state->set_exception(std::move(val));
854 make_ready<urgent::no>();
863 report_failed_future(val);
867 void set_exception(future_state_base&& state) noexcept {
868 set_exception_impl(std::move(state));
871 void set_exception(std::exception_ptr&& ex) noexcept {
872 set_exception_impl(std::move(ex));
875 void set_exception(
const std::exception_ptr& ex) noexcept {
876 set_exception(std::exception_ptr(ex));
879 template<
typename Exception>
880 std::enable_if_t<!std::is_same<std::remove_reference_t<Exception>, std::exception_ptr>::value,
void> set_exception(Exception&& e) noexcept {
881 set_exception(std::make_exception_ptr(std::forward<Exception>(e)));
884 friend class future_base;
892 void set_to_current_exception() noexcept;
895 task* waiting_task() const noexcept {
return _task; }
904 template <
typename SEASTAR_ELLIPSIS T>
905 class promise_base_with_type :
protected internal::promise_base {
907 using future_state = seastar::future_state<future_stored_type_t<T SEASTAR_ELLIPSIS>>;
908 future_state* get_state() noexcept {
909 return static_cast<future_state*
>(_state);
911 static constexpr
bool copy_noexcept = future_state::copy_noexcept;
913 promise_base_with_type(future_state_base* state) noexcept : promise_base(state) { }
914 promise_base_with_type(future<T SEASTAR_ELLIPSIS>* future) noexcept : promise_base(future, &future->_state) { }
915 promise_base_with_type(promise_base_with_type&& x) noexcept =
default;
916 promise_base_with_type(
const promise_base_with_type&) =
delete;
917 promise_base_with_type& operator=(promise_base_with_type&& x) noexcept =
default;
918 void operator=(
const promise_base_with_type&) =
delete;
920 void set_urgent_state(future_state&& state) noexcept {
921 auto* ptr = get_state();
928 assert(ptr->_u.st == future_state_base::state::future);
929 new (ptr) future_state(std::move(state));
930 make_ready<urgent::yes>();
934 template <
typename... A>
935 void set_value(A&&... a) noexcept {
936 if (
auto *s = get_state()) {
937 s->set(std::forward<A>(a)...);
938 make_ready<urgent::no>();
946 void set_to_current_exception() noexcept {
947 internal::promise_base::set_to_current_exception();
951 using internal::promise_base::waiting_task;
955 template <
typename SEASTAR_ELLIPSIS U>
968 template <
typename SEASTAR_ELLIPSIS T>
969 class promise :
private internal::promise_base_with_type<T SEASTAR_ELLIPSIS> {
970 using future_state =
typename internal::promise_base_with_type<T SEASTAR_ELLIPSIS>::future_state;
971 future_state _local_state;
977 promise() noexcept : internal::promise_base_with_type<T SEASTAR_ELLIPSIS>(&_local_state) {}
981 promise(
promise&& x) noexcept : internal::promise_base_with_type<T SEASTAR_ELLIPSIS>(std::move(x)) {
982 move_it(std::move(x));
986 internal::promise_base_with_type<T SEASTAR_ELLIPSIS>::operator=(std::move(x));
989 move_it(std::move(x));
992 void operator=(
const promise&) =
delete;
999 internal::promise_base::set_to_current_exception();
1003 using internal::promise_base::waiting_task;
1024 template <typename... A>
1025 void set_value(A&&... a) noexcept {
1026 internal::promise_base_with_type<T SEASTAR_ELLIPSIS>::set_value(std::forward<A>(a)...);
1034 internal::promise_base::set_exception(std::move(ex));
1037 void set_exception(
const std::exception_ptr& ex) noexcept {
1038 internal::promise_base::set_exception(ex);
1045 template<
typename Exception>
1046 std::enable_if_t<!std::is_same<std::remove_reference_t<Exception>, std::exception_ptr>::value,
void>
set_exception(Exception&& e) noexcept {
1047 internal::promise_base::set_exception(std::forward<Exception>(e));
1050 using internal::promise_base_with_type<T SEASTAR_ELLIPSIS>::set_urgent_state;
1052 template <
typename SEASTAR_ELLIPSIS U>
1056 #if SEASTAR_API_LEVEL < 6
1063 class promise<void> :
public promise<> {};
1077 template <
typename... T>
struct is_future : std::false_type {};
1081 template <
typename... T>
struct is_future<
future<T...>> : std::true_type {};
1089 template <
typename T>
1094 template <typename T>
1095 concept Future = is_future<T>::value;
1097 template <
typename Func,
typename... T>
1098 concept CanInvoke = std::invocable<Func, T...>;
1101 template <
typename Func,
typename... T>
1102 concept CanApply = CanInvoke<Func, T...>;
1104 template <
typename Func,
typename... T>
1105 concept CanApplyTuple
1107 && requires (Func func, std::tuple<T...> wrapped_val) {
1108 { std::apply(func, std::get<0>(std::move(wrapped_val))) };
1111 template <
typename Func,
typename Return,
typename... T>
1112 concept InvokeReturns = requires (Func f, T... args) {
1113 { f(std::forward<T>(args)...) } -> std::same_as<Return>;
1117 template <
typename Func,
typename Return,
typename... T>
1118 concept ApplyReturns = InvokeReturns<Func, Return, T...>;
1120 template <
typename Func,
typename... T>
1121 concept InvokeReturnsAnyFuture = Future<std::invoke_result_t<Func, T...>>;
1124 template <
typename Func,
typename... T>
1125 concept ApplyReturnsAnyFuture = InvokeReturnsAnyFuture<Func, T...>;
1132 template <typename T>
1133 using futurize_t =
typename futurize<T>::type;
1137 template<
typename Func,
typename... Args>
1138 auto futurize_invoke(Func&& func, Args&&... args) noexcept;
1140 template<
typename Func,
typename... Args>
1141 auto futurize_apply(Func&& func, std::tuple<Args...>&& args) noexcept;
1145 namespace internal {
1148 promise_base* _promise;
1149 future_base() noexcept : _promise(
nullptr) {}
1150 future_base(promise_base* promise, future_state_base* state) noexcept : _promise(promise) {
1151 _promise->_future =
this;
1152 _promise->_state = state;
1155 void move_it(future_base&& x, future_state_base* state) noexcept {
1156 _promise = x._promise;
1157 if (
auto* p = _promise) {
1164 future_base(future_base&& x, future_state_base* state) noexcept {
1165 move_it(std::move(x), state);
1168 void clear() noexcept {
1174 ~future_base() noexcept {
1178 promise_base* detach_promise() noexcept {
1179 _promise->_state =
nullptr;
1180 _promise->_future =
nullptr;
1181 return std::exchange(_promise,
nullptr);
1184 void schedule(task* tws, future_state_base* state) noexcept {
1185 promise_base* p = detach_promise();
1190 void do_wait() noexcept;
1192 #ifdef SEASTAR_COROUTINES_ENABLED
1193 void set_coroutine(task& coroutine) noexcept;
1196 friend class promise_base;
1199 template <
typename Func,
typename... T>
1200 struct future_result {
1201 using type = std::invoke_result_t<Func, T...>;
1202 using future_type = futurize_t<type>;
1203 using func_type = future_type (T&&...);
1206 template <
typename Func>
1207 struct future_result<Func, void> {
1208 using type = std::invoke_result_t<Func>;
1209 using future_type = futurize_t<type>;
1210 using func_type = future_type ();
1213 template <
typename Func,
typename SEASTAR_ELLIPSIS T>
1214 using future_result_t =
typename future_result<Func, T SEASTAR_ELLIPSIS>::type;
1216 template <
typename Func,
typename T>
1217 auto future_invoke(Func&& func, T&& v) {
1218 if constexpr (std::is_same_v<T, monostate>) {
1219 return std::invoke(std::forward<Func>(func));
1221 return std::invoke(std::forward<Func>(func), std::forward<T>(v));
1229 template <
typename Future>
1230 struct call_then_impl;
1234 template <
typename... T>
1235 struct call_then_impl<future<T...>> {
1236 template <
typename Func>
1237 using result_type =
typename future_result<Func, T...>::future_type;
1239 template <
typename Func>
1240 using func_type =
typename future_result<Func, T...>::func_type;
1242 template <
typename Func>
1243 static result_type<Func> run(future<T...>& fut, Func&& func) noexcept {
1244 return fut.then_impl(std::forward<Func>(func));
1248 #if SEASTAR_API_LEVEL < 4
1251 template <
typename... T>
1252 struct call_then_impl<future<when_all_succeed_tuple<T...>>> {
1253 template <
typename Func>
1254 using result_type = futurize_t<std::invoke_result_t<Func, T&&...>>;
1256 template <
typename Func>
1257 using func_type = result_type<Func> (T&&...);
1259 using was_tuple = when_all_succeed_tuple<T...>;
1260 using std_tuple = std::tuple<T...>;
1262 template <
typename Func>
1263 static auto run(future<was_tuple>& fut, Func&& func) noexcept {
1266 return fut.then_impl([func = std::forward<Func>(func)] (was_tuple&& t)
mutable {
1267 return std::apply(func,
static_cast<std_tuple&&
>(std::move(t)));
1274 template <
typename Func,
typename... Args>
1275 using call_then_impl_result_type =
typename call_then_impl<future<Args...>>::template result_type<Func>;
1278 template <typename Func, typename... Args>
1279 concept CanInvokeWhenAllSucceed = requires {
1280 typename call_then_impl_result_type<Func, Args...>;
1284 template <typename Func, typename... T>
1285 struct result_of_apply {
1289 template <
typename Func,
typename... T>
1290 struct result_of_apply<Func, std::tuple<T...>> : std::invoke_result<Func, T...> {
1294 template <
typename Func,
typename... T>
1295 using result_of_apply_t =
typename result_of_apply<Func, T...>::type;
1299 template <
typename Promise,
typename SEASTAR_ELLIPSIS T>
1300 task* continuation_base_with_promise<Promise, T SEASTAR_ELLIPSIS>::waiting_task() noexcept {
1301 return _pr.waiting_task();
1346 template <
typename SEASTAR_ELLIPSIS T>
1347 class [[nodiscard]]
future :
private internal::future_base {
1348 using future_state = seastar::future_state<internal::future_stored_type_t<T SEASTAR_ELLIPSIS>>;
1349 future_state _state;
1350 static constexpr
bool copy_noexcept = future_state::copy_noexcept;
1351 using call_then_impl = internal::call_then_impl<future>;
1363 template <
typename... A>
1370 [[gnu::always_inline]]
1371 explicit future(future_state&& state) noexcept
1372 : _state(std::move(state)) {
1374 internal::promise_base_with_type<T SEASTAR_ELLIPSIS> get_promise() noexcept {
1376 return internal::promise_base_with_type<T SEASTAR_ELLIPSIS>(
this);
1378 internal::promise_base_with_type<T SEASTAR_ELLIPSIS>* detach_promise() noexcept {
1379 return static_cast<internal::promise_base_with_type<T SEASTAR_ELLIPSIS>*
>(future_base::detach_promise());
1381 void schedule(continuation_base<T SEASTAR_ELLIPSIS>* tws) noexcept {
1382 future_base::schedule(tws, &tws->_state);
1384 template <
typename Pr,
typename Func,
typename Wrapper>
1385 void schedule(Pr&& pr, Func&& func, Wrapper&& wrapper) noexcept {
1391 auto tws =
new continuation<Pr, Func, Wrapper, T SEASTAR_ELLIPSIS>(std::move(pr), std::move(func), std::move(wrapper));
1394 #ifdef SEASTAR_DEBUG
1395 if (_state.available()) {
1396 tws->set_state(get_available_state_ref());
1397 ::seastar::schedule(tws);
1402 _state._u.st = future_state_base::state::invalid;
1405 [[gnu::always_inline]]
1406 future_state&& get_available_state_ref() noexcept {
1410 return std::move(_state);
1421 template<
typename... U>
1425 using value_type = internal::future_stored_type_t<T SEASTAR_ELLIPSIS>;
1426 using tuple_type = internal::future_tuple_type_t<value_type>;
1430 [[gnu::always_inline]]
1431 future(
future&& x) noexcept : future_base(std::move(x), &_state), _state(std::move(x._state)) { }
1435 move_it(std::move(x), &_state);
1436 _state = std::move(x._state);
1439 void operator=(
const future&) =
delete;
1449 [[gnu::always_inline]]
1452 return get_available_state_ref().take();
1455 [[gnu::always_inline]]
1456 std::exception_ptr get_exception() noexcept {
1457 return get_available_state_ref().get_exception();
1470 #if SEASTAR_API_LEVEL < 5
1471 return future_state::get0(get());
1483 if (_state.available()) {
1492 [[gnu::always_inline]]
1494 return _state.available();
1500 [[gnu::always_inline]]
1502 return _state.failed();
1520 template <
typename Func,
typename Result = futurize_t<
typename call_then_impl::
template result_type<Func>>>
1521 SEASTAR_CONCEPT( requires std::invocable<Func, T SEASTAR_ELLIPSIS> || internal::CanInvokeWhenAllSucceed<Func, T SEASTAR_ELLIPSIS>)
1529 #ifndef SEASTAR_TYPE_ERASE_MORE
1530 return call_then_impl::run(*
this, std::move(func));
1532 using func_type =
typename call_then_impl::template func_type<Func>;
1537 return futurize_invoke(func, std::forward<decltype(args)>(args)...);
1540 return call_then_impl::run(*
this, std::move(ncf));
1563 template <
typename Func,
typename Result = futurize_t<
internal::result_of_apply_t<Func, T SEASTAR_ELLIPSIS>>>
1564 SEASTAR_CONCEPT( requires ::seastar::CanApplyTuple<Func, T SEASTAR_ELLIPSIS>)
1567 return then([func = std::forward<Func>(func)] (T&& SEASTAR_ELLIPSIS tuple)
mutable {
1569 return std::apply(func, std::move(tuple) SEASTAR_ELLIPSIS);
1576 template <
typename Func,
typename Result>
1577 Result then_impl_nrvo(Func&& func) noexcept {
1580 using pr_type = decltype(fut.get_promise());
1581 schedule(fut.get_promise(), std::move(func), [](pr_type&& pr, Func& func, future_state&& state) {
1582 if (state.failed()) {
1583 pr.set_exception(static_cast<future_state_base&&>(std::move(state)));
1585 futurator::satisfy_with_result_of(std::move(pr), [&func, &state] {
1586 #if SEASTAR_API_LEVEL < 5
1587 return std::apply(func, std::move(state).get_value());
1592 return internal::future_invoke(func, std::move(state).get_value());
1600 template <
typename Func,
typename Result = futurize_t<
internal::future_result_t<Func, T SEASTAR_ELLIPSIS>>>
1602 then_impl(Func&& func) noexcept {
1603 #ifndef SEASTAR_DEBUG
1604 using futurator = futurize<internal::future_result_t<Func, T SEASTAR_ELLIPSIS>>;
1607 }
else if (available()) {
1608 #if SEASTAR_API_LEVEL < 5
1609 return futurator::apply(std::forward<Func>(func), get_available_state_ref().take_value());
1611 return futurator::invoke(std::forward<Func>(func), get_available_state_ref().take_value());
1615 return then_impl_nrvo<Func, Result>(std::forward<Func>(func));
1634 template <
typename Func,
typename FuncResult = std::invoke_result_t<Func, future>>
1635 SEASTAR_CONCEPT( requires std::invocable<Func, future> )
1636 futurize_t<FuncResult>
1638 return then_wrapped_maybe_erase<false, FuncResult>(std::forward<Func>(func));
1641 template <
typename Func,
typename FuncResult = std::invoke_result_t<Func, future&&>>
1642 SEASTAR_CONCEPT( requires std::invocable<Func, future&&> )
1643 futurize_t<FuncResult>
1644 then_wrapped(Func&& func) && noexcept {
1645 return then_wrapped_maybe_erase<true, FuncResult>(std::forward<Func>(func));
1650 template <
bool AsSelf,
typename FuncResult,
typename Func>
1651 futurize_t<FuncResult>
1652 then_wrapped_maybe_erase(Func&& func) noexcept {
1653 #ifndef SEASTAR_TYPE_ERASE_MORE
1654 return then_wrapped_common<AsSelf, FuncResult>(std::forward<Func>(func));
1656 using futurator = futurize<FuncResult>;
1657 using WrapFuncResult =
typename futurator::type;
1658 noncopyable_function<WrapFuncResult (future&&)> ncf;
1660 memory::scoped_critical_alloc_section _;
1661 ncf = noncopyable_function<WrapFuncResult(future &&)>([func = std::forward<Func>(func)](future&& f)
mutable {
1662 return futurator::invoke(func, std::move(f));
1665 return then_wrapped_common<AsSelf, WrapFuncResult>(std::move(ncf));
1670 template <
typename FuncResult,
typename Func>
1671 futurize_t<FuncResult>
1672 then_wrapped_nrvo(Func&& func) noexcept {
1673 using futurator = futurize<FuncResult>;
1674 typename futurator::type fut(future_for_get_promise_marker{});
1675 using pr_type = decltype(fut.get_promise());
1676 schedule(fut.get_promise(), std::move(func), [](pr_type&& pr, Func& func, future_state&& state) {
1677 futurator::satisfy_with_result_of(std::move(pr), [&func, &state] {
1678 return func(future(std::move(state)));
1685 template <
bool AsSelf,
typename FuncResult,
typename Func>
1686 futurize_t<FuncResult>
1687 then_wrapped_common(Func&& func) noexcept {
1688 #ifndef SEASTAR_DEBUG
1689 using futurator = futurize<FuncResult>;
1691 if constexpr (AsSelf) {
1695 return futurator::invoke(std::forward<Func>(func), std::move(*
this));
1697 return futurator::invoke(std::forward<Func>(func), future(get_available_state_ref()));
1701 return then_wrapped_nrvo<FuncResult, Func>(std::forward<Func>(func));
1704 void forward_to(internal::promise_base_with_type<T SEASTAR_ELLIPSIS>&& pr) noexcept {
1705 if (_state.available()) {
1706 pr.set_urgent_state(std::move(_state));
1708 *detach_promise() = std::move(pr);
1724 if (_state.available()) {
1725 pr.set_urgent_state(std::move(_state));
1726 }
else if (&pr._local_state != pr._state) {
1731 *detach_promise() = std::move(pr);
1752 template <
typename Func>
1753 SEASTAR_CONCEPT( requires std::invocable<Func> )
1754 future<T SEASTAR_ELLIPSIS> finally(Func&& func) noexcept {
1755 return then_wrapped(
finally_body<Func,
is_future<std::invoke_result_t<Func>>::value>(std::forward<Func>(func)));
1759 template <
typename Func,
bool FuncReturnsFuture>
1762 template <
typename Func>
1766 finally_body(Func&& func) noexcept : _func(std::forward<Func>(func))
1770 return futurize_invoke(_func).then_wrapped([result = std::move(result)](
auto&& f_res)
mutable {
1771 if (!f_res.failed()) {
1772 return std::move(result);
1774 return result.rethrow_with_nested(std::move(f_res._state));
1780 template <
typename Func>
1784 finally_body(Func&& func) noexcept : _func(std::forward<Func>(func))
1790 return std::move(result);
1792 return result.rethrow_with_nested();
1802 return then_wrapped([] (
auto&& f) {
1806 engine_exit(std::current_exception());
1818 return then([] (
auto&&...) {});
1834 template <
typename Func>
1836 || (std::tuple_size_v<tuple_type> == 0 && ::seastar::InvokeReturns<Func, void, std::exception_ptr>)
1837 || (std::tuple_size_v<tuple_type> == 1 && ::seastar::InvokeReturns<Func, T, std::exception_ptr>)
1838 || (std::tuple_size_v<tuple_type> > 1 && ::seastar::InvokeReturns<Func, tuple_type, std::exception_ptr>)
1840 future<T SEASTAR_ELLIPSIS> handle_exception(Func&& func) noexcept {
1841 return then_wrapped([func = std::forward<Func>(func)]
1843 if (!fut.failed()) {
1844 return make_ready_future<T SEASTAR_ELLIPSIS>(fut.get());
1846 return futurize_invoke(func, fut.get_exception());
1861 template <
typename Func>
1864 static_assert(trait::arity == 1,
"func can take only one parameter");
1865 using ex_type =
typename trait::template arg<0>::type;
1866 return then_wrapped([func = std::forward<Func>(func)]
1869 return make_ready_future<T SEASTAR_ELLIPSIS>(fut.get());
1870 }
catch(ex_type& ex) {
1871 return futurize_invoke(func, ex);
1885 #ifdef SEASTAR_COROUTINES_ENABLED
1886 using future_base::set_coroutine;
1889 void set_callback(continuation_base<T SEASTAR_ELLIPSIS>* callback) noexcept {
1890 if (_state.available()) {
1891 callback->set_state(get_available_state_ref());
1892 ::seastar::schedule(callback);
1901 template <
typename SEASTAR_ELLIPSIS U>
1902 friend class future;
1903 template <
typename SEASTAR_ELLIPSIS U>
1904 friend class promise;
1905 template <
typename U>
1906 friend struct futurize;
1907 template <
typename SEASTAR_ELLIPSIS U>
1908 friend class internal::promise_base_with_type;
1909 template <
typename... U,
typename... A>
1911 template <
typename... U>
1913 template <
typename... U,
typename Exception>
1915 template <
typename... U>
1917 template <
typename... U>
1919 template <typename... U, typename V>
1920 friend
void internal::set_callback(future<U...>&&, V*) noexcept;
1921 template <typename Future>
1922 friend struct internal::call_then_impl;
1927 namespace internal {
1928 template <
typename T>
1929 struct futurize_base {
1931 using type = future<T>;
1933 using promise_type = promise<T>;
1934 using promise_base_with_type = internal::promise_base_with_type<T>;
1937 static inline type convert(T&& value) {
return make_ready_future<T>(std::move(value)); }
1938 static inline type convert(type&& value) {
return std::move(value); }
1941 template <
typename Arg>
1946 struct futurize_base<void> {
1949 using promise_base_with_type = internal::promise_base_with_type<>;
1951 static inline type convert(type&& value) {
1952 return std::move(value);
1954 template <
typename Arg>
1958 template <
typename T>
1959 struct futurize_base<future<T>> :
public futurize_base<T> {};
1962 struct futurize_base<future<>> :
public futurize_base<void> {};
1965 template <
typename T>
1967 using base = internal::futurize_base<T>;
1970 using promise_base_with_type =
typename base::promise_base_with_type;
1973 using tuple_type =
typename type::tuple_type;
1974 using base::convert;
1979 template<
typename Func,
typename... FuncArgs>
1980 static inline type apply(Func&& func, std::tuple<FuncArgs...>&& args) noexcept;
1984 template<
typename Func,
typename... FuncArgs>
1985 static inline type invoke(Func&& func, FuncArgs&&... args) noexcept;
1987 template<
typename Func>
1988 static inline type invoke(Func&& func, internal::monostate) noexcept {
1989 return invoke(std::forward<Func>(func));
1993 template<
typename Func,
typename... FuncArgs>
1994 [[deprecated(
"Use invoke for varargs")]]
1995 static inline type apply(Func&& func, FuncArgs&&... args) noexcept {
1996 return invoke(std::forward<Func>(func), std::forward<FuncArgs>(args)...);
1999 static type current_exception_as_future() noexcept {
2012 #if SEASTAR_API_LEVEL >= 5
2026 template<
typename Func>
2027 SEASTAR_CONCEPT( requires std::invocable<Func> )
2028 static void satisfy_with_result_of(promise_base_with_type&&, Func&& func);
2030 template <
typename SEASTAR_ELLIPSIS U>
2034 inline internal::promise_base::promise_base(future_base* future, future_state_base* state) noexcept
2035 : _future(future), _state(state) {
2036 _future->_promise =
this;
2039 template <
typename SEASTAR_ELLIPSIS T>
2041 future<T SEASTAR_ELLIPSIS>
2043 assert(!this->_future && this->_state && !this->_task);
2047 template <
typename SEASTAR_ELLIPSIS T>
2050 if (this->_state == &x._local_state) {
2051 this->_state = &_local_state;
2052 new (&_local_state) future_state(std::move(x._local_state));
2056 template <
typename... T,
typename... A>
2062 template <
typename... T>
2068 template <
typename... T>
2071 return future<T...>(exception_future_marker(), std::move(state));
2074 template <
typename... T>
2079 void log_exception_trace() noexcept;
2087 template <typename... T, typename Exception>
2090 log_exception_trace();
2094 template <
typename... T,
typename Exception>
2095 future<T...> make_exception_future_with_backtrace(Exception&& ex) noexcept {
2096 return make_exception_future<T...>(make_backtraced_exception_ptr<Exception>(std::forward<Exception>(ex)));
2103 template<
typename T>
2104 template<
typename Func,
typename... FuncArgs>
2105 typename futurize<T>::type
futurize<T>::apply(Func&& func, std::tuple<FuncArgs...>&& args) noexcept {
2107 using ret_t = decltype(std::apply(std::forward<Func>(func), std::move(args)));
2108 if constexpr (std::is_void_v<ret_t>) {
2109 std::apply(std::forward<Func>(func), std::move(args));
2110 return make_ready_future<>();
2111 }
else if constexpr (is_future<ret_t>::value){
2112 return std::apply(std::forward<Func>(func), std::move(args));
2114 return convert(std::apply(std::forward<Func>(func), std::move(args)));
2121 template<
typename T>
2122 template<
typename Func>
2123 SEASTAR_CONCEPT( requires std::invocable<Func> )
2124 void futurize<T>::satisfy_with_result_of(promise_base_with_type&& pr, Func&& func) {
2125 using ret_t = decltype(func());
2126 if constexpr (std::is_void_v<ret_t>) {
2129 }
else if constexpr (is_future<ret_t>::value) {
2130 func().forward_to(std::move(pr));
2132 pr.set_value(func());
2136 template<
typename T>
2137 template<
typename Func,
typename... FuncArgs>
2138 typename futurize<T>::type
futurize<T>::invoke(Func&& func, FuncArgs&&... args) noexcept {
2140 using ret_t = decltype(func(std::forward<FuncArgs>(args)...));
2141 if constexpr (std::is_void_v<ret_t>) {
2142 func(std::forward<FuncArgs>(args)...);
2143 return make_ready_future<>();
2144 }
else if constexpr (is_future<ret_t>::value) {
2145 return func(std::forward<FuncArgs>(args)...);
2147 return convert(func(std::forward<FuncArgs>(args)...));
2154 template <
typename T>
2155 template <
typename Arg>
2161 return make_exception_future<T>(std::forward<Arg>(arg));
2164 template <
typename Arg>
2170 return make_exception_future<>(std::forward<Arg>(arg));
2173 template<
typename Func,
typename... Args>
2174 auto futurize_invoke(Func&& func, Args&&... args) noexcept {
2175 using futurator = futurize<std::invoke_result_t<Func, Args&&...>>;
2176 return futurator::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
2179 template<
typename Func,
typename... Args>
2180 [[deprecated(
"Use futurize_invoke for varargs")]]
2181 auto futurize_apply(Func&& func, Args&&... args) noexcept {
2182 return futurize_invoke(std::forward<Func>(func), std::forward<Args>(args)...);
2185 template<
typename Func,
typename... Args>
2186 auto futurize_apply(Func&& func, std::tuple<Args...>&& args) noexcept {
2187 using futurator = futurize<std::invoke_result_t<Func, Args&&...>>;
2188 return futurator::apply(std::forward<Func>(func), std::move(args));
2191 namespace internal {
2193 template <
typename... T,
typename U>
2195 void set_callback(future<T...>&& fut, U* callback) noexcept {
2198 return std::move(fut).set_callback(callback);
A representation of a possibly not-yet-computed value.
Definition: future.hh:1347
void wait() noexcept
Definition: future.hh:1482
Result then(Func &&func) noexcept
Schedule a block of code to run when the future is ready.
Definition: future.hh:1523
bool failed() const noexcept
Checks whether the future has failed.
Definition: future.hh:1501
bool available() const noexcept
Checks whether the future is available.
Definition: future.hh:1493
typename future_state::get0_return_type get0_return_type
Definition: future.hh:1468
internal::future_stored_type_t< T > value_type
The data type carried by the future.
Definition: future.hh:1425
future< T > handle_exception_type(Func &&func) noexcept
Handle the exception of a certain type carried by this future.
Definition: future.hh:1862
void forward_to(promise< T > &&pr) noexcept
Satisfy some promise object with this future as a result.
Definition: future.hh:1723
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:1637
Result then_unpack(Func &&func) noexcept
Schedule a block of code to run when the future is ready, unpacking tuples.
Definition: future.hh:1566
future(future &&x) noexcept
Moves the future into a new object.
Definition: future.hh:1431
value_type && get()
gets the value returned by the computation
Definition: future.hh:1450
future discard_result() noexcept
Discards the value carried by this future.
Definition: future.hh:1815
future or_terminate() noexcept
Terminate the program if this future fails.
Definition: future.hh:1801
void ignore_ready_future() noexcept
Ignore any result hold by this future.
Definition: future.hh:1881
Definition: future.hh:1760
promise - allows a future value to be made available at a later time.
Definition: future.hh:969
void set_to_current_exception() noexcept
Definition: future.hh:998
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:1046
void set_exception(std::exception_ptr &&ex) noexcept
Marks the promise as failed.
Definition: future.hh:1033
promise() noexcept
Constructs an empty promise.
Definition: future.hh:977
Like future except the result can be waited for by many fibers.
Definition: shared_future.hh:102
future< T... > make_exception_future(std::exception_ptr &&value) noexcept
Creates a future in an available, failed state.
Definition: future.hh:2064
future< T > get_future() noexcept
Gets the promise's associated future.
Definition: future.hh:2042
future< T... > make_exception_future(Exception &&ex) noexcept
Creates a future in an available, failed state.
Definition: future.hh:2089
future< T... > make_ready_future(A &&... value) noexcept
Creates a future in an available, value state.
Definition: future.hh:2058
future< T... > current_exception_as_future() noexcept
Returns std::current_exception() wrapped in a future.
Definition: future.hh:2075
void move_it(promise &&x) noexcept
Moves a promise object.
Definition: future.hh:2049
Definition: future.hh:577
Definition: future.hh:578
Definition: future.hh:576
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:211
Definition: future.hh:430
friend future< U... > current_exception_as_future() noexcept
Returns std::current_exception() wrapped in a future.
Definition: future.hh:2075
Definition: future.hh:522
Definition: future.hh:524
Converts a type to a future type, if it isn't already.
Definition: future.hh:1966
static type apply(Func &&func, FuncArgs &&... args) noexcept
Deprecated alias of invoke.
Definition: future.hh:1995
static type from_tuple(tuple_type &&value)
Convert the tuple representation into a future.
Definition: future.hh:2004
static type from_tuple(value_type &&value)
Convert the tuple representation into a future.
Definition: future.hh:2014
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:2018
static type from_tuple(const tuple_type &value)
Convert the tuple representation into a future.
Definition: future.hh:2008
typename type::value_type value_type
The value tuple type associated with type.
Definition: future.hh:1972
static type invoke(Func &&func, FuncArgs &&... args) noexcept
Check whether a type is a future.
Definition: future.hh:1077
Definition: future.hh:446