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#ifndef SEASTAR_MODULE
25#include <cassert>
26#include <concepts>
27#include <cstdlib>
28#include <cstring>
29#include <functional>
30#include <memory>
31#include <stdexcept>
32#include <type_traits>
33#include <utility>
34#endif
35
36#include <seastar/core/task.hh>
37#include <seastar/core/thread_impl.hh>
38#include <seastar/core/function_traits.hh>
40#include <seastar/util/critical_alloc_section.hh>
41#include <seastar/util/noncopyable_function.hh>
42#include <seastar/util/backtrace.hh>
43#include <seastar/util/std-compat.hh>
44#include <seastar/util/modules.hh>
45
46namespace seastar {
47
48struct nested_exception : public std::exception {
49 std::exception_ptr inner;
50 std::exception_ptr outer;
51 nested_exception(std::exception_ptr inner, std::exception_ptr outer) noexcept;
53 nested_exception(const nested_exception&) noexcept;
54 [[noreturn]] void rethrow_nested() const;
55 virtual const char* what() const noexcept override;
56};
57
81
138
144
145
148SEASTAR_MODULE_EXPORT_BEGIN
149template <class T = void>
150class promise;
151
152template <class T>
153class future;
154
155template <typename... T>
156class shared_future;
157
158struct future_state_base;
159
166template <typename T = void, typename... A>
167future<T> make_ready_future(A&&... value) noexcept;
168
169
171template<typename T>
172inline
174 return make_ready_future<std::remove_cv_t<std::remove_reference_t<T>>>(
175 std::forward<T>(v));
176}
177
184template <typename T = void>
185future<T> make_exception_future(std::exception_ptr&& value) noexcept;
186
187template <typename T = void, typename Exception>
188future<T> make_exception_future(Exception&& ex) noexcept;
189
190template <typename T = void>
191future<T> make_exception_future(const std::exception_ptr& ex) noexcept {
192 return make_exception_future<T>(std::exception_ptr(ex));
193}
194
195template <typename T = void>
196future<T> make_exception_future(std::exception_ptr& ex) noexcept {
197 return make_exception_future<T>(static_cast<const std::exception_ptr&>(ex));
198}
199
200template <typename T = void>
201future<T> make_exception_future(const std::exception_ptr&& ex) noexcept {
202 // as ex is const, we cannot move it, but can copy it.
203 return make_exception_future<T>(std::exception_ptr(ex));
204}
205SEASTAR_MODULE_EXPORT_END
207void engine_exit(std::exception_ptr eptr = {});
208
209void report_failed_future(const std::exception_ptr& ex) noexcept;
210
211void report_failed_future(const future_state_base& state) noexcept;
212
214
221SEASTAR_MODULE_EXPORT
222struct broken_promise : std::logic_error {
224};
225
231SEASTAR_MODULE_EXPORT
232template <typename T = void>
234
235SEASTAR_MODULE_EXPORT
236extern template
237future<void> current_exception_as_future() noexcept;
238
239namespace internal {
240template <class T = void>
241class promise_base_with_type;
242class promise_base;
243
244struct monostate {};
245
246template <typename... T>
247struct future_stored_type;
248
249template <>
250struct future_stored_type<> {
251 using type = monostate;
252};
253
254template <typename T>
255struct future_stored_type<T> {
256 using type = std::conditional_t<std::is_void_v<T>, internal::monostate, T>;
257};
258
259template <typename... T>
260using future_stored_type_t = typename future_stored_type<T...>::type;
261
262template<typename T>
263using future_tuple_type_t = std::conditional_t<std::is_same_v<T, monostate>, std::tuple<>, std::tuple<T>>;
264
265// 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
266// fails the build even if it is in the non enabled side of std::conditional.
267template <typename T>
268struct get0_return_type;
269
270template <>
271struct get0_return_type<internal::monostate> {
272 using type = void;
273 static type get0(internal::monostate) { }
274};
275
276template <typename T>
277struct get0_return_type {
278 using type = T;
279 static T get0(T&& v) { return std::move(v); }
280};
281
282template<typename T>
283using maybe_wrap_ref = std::conditional_t<std::is_reference_v<T>, std::reference_wrapper<std::remove_reference_t<T>>, T>;
284
292template <typename T, bool is_trivial_class>
293struct uninitialized_wrapper_base;
294
295template <typename T>
296struct uninitialized_wrapper_base<T, false> {
297 using tuple_type = future_tuple_type_t<T>;
298 union any {
299 any() noexcept {}
300 ~any() {}
301 // T can be a reference, so wrap it.
302 maybe_wrap_ref<T> value;
303 } _v;
304
305public:
306 uninitialized_wrapper_base() noexcept = default;
307 template<typename... U>
308 std::enable_if_t<!std::is_same_v<std::tuple<std::remove_cv_t<U>...>, std::tuple<tuple_type>>, void>
309 uninitialized_set(U&&... vs) {
310 new (&_v.value) maybe_wrap_ref<T>(T(std::forward<U>(vs)...));
311 }
312 void uninitialized_set(tuple_type&& v) {
313 uninitialized_set(std::move(std::get<0>(v)));
314 }
315 void uninitialized_set(const tuple_type& v) {
316 uninitialized_set(std::get<0>(v));
317 }
318 maybe_wrap_ref<T>& uninitialized_get() {
319 return _v.value;
320 }
321 const maybe_wrap_ref<T>& uninitialized_get() const {
322 return _v.value;
323 }
324};
325
326template <typename T> struct uninitialized_wrapper_base<T, true> : private T {
327 using tuple_type = future_tuple_type_t<T>;
328 uninitialized_wrapper_base() noexcept = default;
329 template<typename... U>
330 std::enable_if_t<!std::is_same_v<std::tuple<std::remove_cv_t<U>...>, std::tuple<tuple_type>>, void>
331 uninitialized_set(U&&... vs) {
332 new (this) T(std::forward<U>(vs)...);
333 }
334 void uninitialized_set(tuple_type&& v) {
335 if constexpr (std::tuple_size_v<tuple_type> != 0) {
336 uninitialized_set(std::move(std::get<0>(v)));
337 }
338 }
339 void uninitialized_set(const tuple_type& v) {
340 if constexpr (std::tuple_size_v<tuple_type> != 0) {
341 uninitialized_set(std::get<0>(v));
342 }
343 }
344 T& uninitialized_get() {
345 return *this;
346 }
347 const T& uninitialized_get() const {
348 return *this;
349 }
350};
351
352template <typename T>
353constexpr bool can_inherit =
354 (std::is_trivially_destructible_v<T> && std::is_trivially_constructible_v<T> &&
355 std::is_class_v<T> && !std::is_final_v<T>);
356
357// The objective is to avoid extra space for empty types like std::tuple<>. We could use std::is_empty_v, but it is
358// better to check that both the constructor and destructor can be skipped.
359template <typename T>
360struct uninitialized_wrapper
361 : public uninitialized_wrapper_base<T, can_inherit<T>> {};
362
363template <typename T>
364struct is_trivially_move_constructible_and_destructible {
365 static constexpr bool value = std::is_trivially_move_constructible_v<T> && std::is_trivially_destructible_v<T>;
366};
367
368template <bool... v>
369struct all_true : std::false_type {};
370
371template <>
372struct all_true<> : std::true_type {};
373
374template <bool... v>
375struct all_true<true, v...> : public all_true<v...> {};
376
377template<typename T>
378struct is_tuple_effectively_trivially_move_constructible_and_destructible_helper;
379
380template <typename... T>
381struct is_tuple_effectively_trivially_move_constructible_and_destructible_helper<std::tuple<T...>> {
382 static constexpr bool value = all_true<is_trivially_move_constructible_and_destructible<T>::value...>::value;
383};
384
385template <typename T>
386static constexpr bool is_tuple_effectively_trivially_move_constructible_and_destructible =
387 is_tuple_effectively_trivially_move_constructible_and_destructible_helper<T>::value;
388
389}
390
391//
392// A future/promise pair maintain one logical value (a future_state).
393// There are up to three places that can store it, but only one is
394// active at any time.
395//
396// - in the promise _local_state member variable
397//
398// This is necessary because a promise is created first and there
399// would be nowhere else to put the value.
400//
401// - in the future _state variable
402//
403// This is used anytime a future exists and then has not been called
404// yet. This guarantees a simple access to the value for any code
405// that already has a future.
406//
407// - in the task associated with the .then() clause (after .then() is called,
408// if a value was not set)
409//
410//
411// The promise maintains a pointer to the state, which is modified as
412// the state moves to a new location due to events (such as .then() or
413// get_future being called) or due to the promise or future being
414// moved around.
415//
416
417// non templated base class to reduce code duplication
418SEASTAR_MODULE_EXPORT
420 static_assert(sizeof(std::exception_ptr) == sizeof(void*), "exception_ptr not a pointer");
421 enum class state : uintptr_t {
422 invalid = 0,
423 future = 1,
424 // the substate is intended to decouple the run-time prevention
425 // for duplicative result extraction (calling e.g. then() twice
426 // ends up in abandoned()) from the wrapped object's destruction
427 // handling which is orchestrated by future_state. Instead of
428 // creating a temporary future_state just for the sake of setting
429 // the "invalid" in the source instance, result_unavailable can
430 // be set to ensure future_state_base::available() returns false.
431 result_unavailable = 2,
432 result = 3,
433 exception_min = 4, // or anything greater
434 };
435 union any {
436 any() noexcept { st = state::future; }
437 any(state s) noexcept { st = s; }
438 void set_exception(std::exception_ptr&& e) noexcept {
439 new (&ex) std::exception_ptr(std::move(e));
440 assert(st >= state::exception_min);
441 }
442 any(std::exception_ptr&& e) noexcept {
443 set_exception(std::move(e));
444 }
445 // From a users' perspective, a result_unavailable is not valid
446 bool valid() const noexcept { return st != state::invalid && st != state::result_unavailable; }
447 bool available() const noexcept { return st == state::result || st >= state::exception_min; }
448 bool failed() const noexcept { return __builtin_expect(st >= state::exception_min, false); }
449 void check_failure() noexcept;
450 ~any() noexcept { }
451 std::exception_ptr take_exception() noexcept {
452 std::exception_ptr ret(std::move(ex));
453 // Unfortunately in libstdc++ ~exception_ptr is defined out of line. We know that it does nothing for
454 // moved out values, so we omit calling it. This is critical for the code quality produced for this
455 // function. Without the out of line call, gcc can figure out that both sides of the if produce
456 // identical code and merges them.if
457 // We don't make any assumptions about other c++ libraries.
458 // There is request with gcc to define it inline: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90295
459#ifndef __GLIBCXX__
460 ex.~exception_ptr();
461#endif
462 st = state::invalid;
463 return ret;
464 }
465 void move_it(any&& x) noexcept {
466#ifdef __GLIBCXX__
467 // Unfortunally gcc cannot fully optimize the regular
468 // implementation:
469 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95014
470 // Given what we know about the libstdc++ implementation
471 // (see the comment in take_exception), we can just
472 // memmove and zero x. We use memmove to guarantee
473 // vaild results if &x == this.
474 memmove(static_cast<void*>(this), &x, sizeof(any));
475 x.st = state::invalid;
476#else
477 if (x.st < state::exception_min) {
478 st = x.st;
479 x.st = state::invalid;
480 } else {
481 new (&ex) std::exception_ptr(x.take_exception());
482 }
483#endif
484 }
485 any(any&& x) noexcept {
486 move_it(std::move(x));
487 }
488 any& operator=(any&& x) noexcept {
489 check_failure();
490 // If this is a self move assignment, check_failure
491 // guarantees that we don't have an exception and calling
492 // move_it is safe.
493 move_it(std::move(x));
494 return *this;
495 }
496 bool has_result() const noexcept {
497 return st == state::result || st == state::result_unavailable;
498 }
499 state st;
500 std::exception_ptr ex;
501 } _u;
502
503 future_state_base() noexcept = default;
504 future_state_base(state st) noexcept : _u(st) { }
505 future_state_base(std::exception_ptr&& ex) noexcept : _u(std::move(ex)) { }
506 future_state_base(future_state_base&& x) noexcept : _u(std::move(x._u)) { }
507
508 // We never need to destruct this polymorphicly, so we can make it
509 // protected instead of virtual.
510protected:
516 ~future_state_base() noexcept = default;
517
518 void rethrow_exception() &&;
519 void rethrow_exception() const&;
520
521public:
522
523 bool valid() const noexcept { return _u.valid(); }
524 bool available() const noexcept { return _u.available(); }
525 bool failed() const noexcept { return _u.failed(); }
526
527 void ignore() noexcept;
528
529 void set_exception(std::exception_ptr&& ex) noexcept {
530 assert(_u.st == state::future);
531 _u.set_exception(std::move(ex));
532 }
533 future_state_base& operator=(future_state_base&& x) noexcept = default;
534 void set_exception(future_state_base&& state) noexcept {
535 assert(_u.st == state::future);
536 *this = std::move(state);
537 }
538 std::exception_ptr get_exception() && noexcept {
539 assert(_u.st >= state::exception_min);
540 // Move ex out so future::~future() knows we've handled it
541 return _u.take_exception();
542 }
543 const std::exception_ptr& get_exception() const& noexcept {
544 assert(_u.st >= state::exception_min);
545 return _u.ex;
546 }
547 template <typename U>
548 friend struct future_state;
549 template <typename U>
551 template <typename U>
552 friend class future;
553 template <typename T>
554 friend struct futurize;
555};
556
557void report_failed_future(future_state_base::any&& state) noexcept;
558
559inline void future_state_base::any::check_failure() noexcept {
560 if (failed()) {
561 report_failed_future(std::move(*this));
562 }
563}
564
568
570template <typename T>
571struct future_state : public future_state_base, private internal::uninitialized_wrapper<T> {
572 static constexpr bool copy_noexcept = std::is_nothrow_copy_constructible_v<T>;
573 static constexpr bool has_trivial_move_and_destroy = internal::is_trivially_move_constructible_and_destructible<T>::value;
574 static_assert(std::is_nothrow_move_constructible_v<T>,
575 "Types must be no-throw move constructible");
576 static_assert(std::is_nothrow_destructible_v<T>,
577 "Types must be no-throw destructible");
578 future_state() noexcept = default;
579 void move_it(future_state&& x) noexcept {
580 if constexpr (has_trivial_move_and_destroy) {
581#pragma GCC diagnostic push
582 // This function may copy uninitialized memory, such as when
583 // creating an uninitialized promise and calling get_future()
584 // on it. Gcc 12 started to catch some simple cases of this
585 // at compile time, so we need to tell it that it's fine.
586#pragma GCC diagnostic ignored "-Wuninitialized"
587 memmove(reinterpret_cast<char*>(&this->uninitialized_get()),
588 &x.uninitialized_get(),
589 internal::used_size<internal::maybe_wrap_ref<T>>::value);
590#pragma GCC diagnostic pop
591 } else if (_u.has_result()) {
592 this->uninitialized_set(std::move(x.uninitialized_get()));
593 std::destroy_at(&x.uninitialized_get());
594 }
595 }
596
597 [[gnu::always_inline]]
598 future_state(future_state&& x) noexcept : future_state_base(std::move(x)) {
599 move_it(std::move(x));
600 }
601
602 void clear() noexcept {
603 if (_u.has_result()) {
604 std::destroy_at(&this->uninitialized_get());
605 } else {
606 _u.check_failure();
607 }
608 }
609 __attribute__((always_inline))
610 ~future_state() noexcept {
611 clear();
612 }
613 future_state& operator=(future_state&& x) noexcept {
614 clear();
615 future_state_base::operator=(std::move(x));
616 // If &x == this, _u.st is now state::invalid and so it is
617 // safe to call move_it.
618 move_it(std::move(x));
619 return *this;
620 }
621 template <typename... A>
622 future_state(ready_future_marker, A&&... a) noexcept : future_state_base(state::result) {
623 try {
624 this->uninitialized_set(std::forward<A>(a)...);
625 } catch (...) {
626 new (this) future_state(current_exception_future_marker());
627 }
628 }
629 template <typename... A>
630 void set(A&&... a) noexcept {
631 assert(_u.st == state::future);
632 new (this) future_state(ready_future_marker(), std::forward<A>(a)...);
633 }
634 future_state(exception_future_marker, std::exception_ptr&& ex) noexcept : future_state_base(std::move(ex)) { }
635 future_state(exception_future_marker, future_state_base&& state) noexcept : future_state_base(std::move(state)) { }
636 future_state(current_exception_future_marker m) noexcept : future_state_base(m) { }
637 future_state(nested_exception_marker m, future_state_base&& old) noexcept : future_state_base(m, std::move(old)) { }
638 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)) { }
639 T&& get_value() && noexcept {
640 assert(_u.st == state::result);
641 return static_cast<T&&>(this->uninitialized_get());
642 }
643 T&& take_value() && noexcept {
644 assert(_u.st == state::result);
645 _u.st = state::result_unavailable;
646 return static_cast<T&&>(this->uninitialized_get());
647 }
648 template<typename U = T>
649 const std::enable_if_t<std::is_copy_constructible_v<U>, U>& get_value() const& noexcept(copy_noexcept) {
650 assert(_u.st == state::result);
651 return this->uninitialized_get();
652 }
653 T&& take() && {
654 assert(available());
655 if (_u.st >= state::exception_min) {
656 std::move(*this).rethrow_exception();
657 }
658 _u.st = state::result_unavailable;
659 return static_cast<T&&>(this->uninitialized_get());
660 }
661 T&& get() && {
662 assert(available());
663 if (_u.st >= state::exception_min) {
664 std::move(*this).rethrow_exception();
665 }
666 return static_cast<T&&>(this->uninitialized_get());
667 }
668 const T& get() const& {
669 assert(available());
670 if (_u.st >= state::exception_min) {
671 rethrow_exception();
672 }
673 return this->uninitialized_get();
674 }
675 using get0_return_type = typename internal::get0_return_type<T>::type;
676 static get0_return_type get0(T&& x) {
677 return internal::get0_return_type<T>::get0(std::move(x));
678 }
679
680 get0_return_type get0() {
681 return std::move(*this).get();
682 }
683};
684
685template <typename T = void>
686class continuation_base : public task {
687protected:
688 using future_state = seastar::future_state<internal::future_stored_type_t<T>>;
689 future_state _state;
690 using future_type = future<T>;
691 using promise_type = promise<T>;
692public:
693 continuation_base() noexcept = default;
694 void set_state(future_state&& state) noexcept {
695 _state = std::move(state);
696 }
697 // This override of waiting_task() is needed here because there are cases
698 // when backtrace is obtained from the destructor of this class and objects
699 // of derived classes are already destroyed at that time. If we didn't
700 // have this override we would get a "pure virtual function call" exception.
701 virtual task* waiting_task() noexcept override { return nullptr; }
702 friend class internal::promise_base_with_type<T>;
703 friend class promise<T>;
704 friend class future<T>;
705};
706
707// Given a future type, find the corresponding continuation_base.
708template <typename Future>
709struct continuation_base_from_future;
710
711template <typename... T>
712struct continuation_base_from_future<future<T...>> {
713 using type = continuation_base<T...>;
714};
715
716template <typename Future>
717using continuation_base_from_future_t = typename continuation_base_from_future<Future>::type;
718
719template <typename Promise, typename T = void>
720class continuation_base_with_promise : public continuation_base<T> {
721 friend class internal::promise_base_with_type<T>;
722protected:
723 continuation_base_with_promise(Promise&& pr) noexcept : _pr(std::move(pr)) {
724 task::make_backtrace();
725 }
726 virtual task* waiting_task() noexcept override;
727 Promise _pr;
728};
729
730template <typename Promise, typename Func, typename Wrapper, typename T = void>
731struct continuation final : continuation_base_with_promise<Promise, T> {
732 // Func is the original function passed to then/then_wrapped. The
733 // Wrapper is a helper function that implements the specific logic
734 // needed by then/then_wrapped. We call the wrapper passing it the
735 // original function, promise and state.
736 // Note that if Func's move constructor throws, this will call
737 // std::unexpected. We could try to require Func to be nothrow
738 // move constructible, but that will cause a lot of churn. Since
739 // we can't support a failure to create a continuation, calling
740 // std::unexpected as close to the failure as possible is the best
741 // we can do.
742 continuation(Promise&& pr, Func&& func, Wrapper&& wrapper) noexcept
743 : continuation_base_with_promise<Promise, T>(std::move(pr))
744 , _func(std::move(func))
745 , _wrapper(std::move(wrapper)) {}
746 virtual void run_and_dispose() noexcept override {
747 try {
748 _wrapper(std::move(this->_pr), _func, std::move(this->_state));
749 } catch (...) {
750 this->_pr.set_to_current_exception();
751 }
752 delete this;
753 }
754 Func _func;
755 [[no_unique_address]] Wrapper _wrapper;
756};
757
758namespace internal {
759
760template <typename T = void>
761future<T> make_exception_future(future_state_base&& state) noexcept;
762
763template <typename T = void>
764void set_callback(future<T>&& fut, continuation_base<T>* callback) noexcept;
765
766class future_base;
767
768class promise_base {
769protected:
770 enum class urgent { no, yes };
771 future_base* _future = nullptr;
772
773 // This points to the future_state that is currently being
774 // used. See comment above the future_state struct definition for
775 // details.
776 future_state_base* _state;
777
778 task* _task = nullptr;
779#ifdef SEASTAR_DEBUG_PROMISE
780 int _task_shard = -1;
781
782 void set_task(task* task) noexcept {
783 _task = task;
784 _task_shard = this_shard_id();
785 }
786 void assert_task_shard() const noexcept;
787#else
788 void set_task(task* task) noexcept {
789 _task = task;
790 }
791 void assert_task_shard() const noexcept { }
792#endif
793
794 promise_base(const promise_base&) = delete;
795 promise_base(future_state_base* state) noexcept : _state(state) {}
796 promise_base(future_base* future, future_state_base* state) noexcept;
797 void move_it(promise_base&& x) noexcept;
798 promise_base(promise_base&& x) noexcept;
799
800 void clear() noexcept;
801
802 // We never need to destruct this polymorphicly, so we can make it
803 // protected instead of virtual
804 ~promise_base() noexcept {
805 clear();
806 }
807
808 void operator=(const promise_base&) = delete;
809 promise_base& operator=(promise_base&& x) noexcept;
810
811 template<urgent Urgent>
812 void make_ready() noexcept;
813
814 template<typename T>
815 void set_exception_impl(T&& val) noexcept {
816 if (_state) {
817 _state->set_exception(std::move(val));
818 make_ready<urgent::no>();
819 } else {
820 // We get here if promise::get_future is called and the
821 // returned future is destroyed without creating a
822 // continuation.
823 // In older versions of seastar we would store a local
824 // copy of ex and warn in the promise destructor.
825 // Since there isn't any way for the user to clear
826 // the exception, we issue the warning from here.
827 report_failed_future(val);
828 }
829 }
830
831 void set_exception(future_state_base&& state) noexcept {
832 set_exception_impl(std::move(state));
833 }
834
835 void set_exception(std::exception_ptr&& ex) noexcept {
836 set_exception_impl(std::move(ex));
837 }
838
839 void set_exception(const std::exception_ptr& ex) noexcept {
840 set_exception(std::exception_ptr(ex));
841 }
842
843 template<typename Exception>
844 std::enable_if_t<!std::is_same_v<std::remove_reference_t<Exception>, std::exception_ptr>, void> set_exception(Exception&& e) noexcept {
845 set_exception(std::make_exception_ptr(std::forward<Exception>(e)));
846 }
847
848 friend class future_base;
849 template <typename U> friend class seastar::future;
850
851public:
856 void set_to_current_exception() noexcept;
857
859 task* waiting_task() const noexcept { return _task; }
860};
861
868template <typename T>
869class promise_base_with_type : protected internal::promise_base {
870protected:
871 using future_state = seastar::future_state<future_stored_type_t<T>>;
872 future_state* get_state() noexcept {
873 return static_cast<future_state*>(_state);
874 }
875 static constexpr bool copy_noexcept = future_state::copy_noexcept;
876public:
877 promise_base_with_type(future_state_base* state) noexcept : promise_base(state) { }
878 promise_base_with_type(future<T>* future) noexcept : promise_base(future, &future->_state) { }
879 promise_base_with_type(promise_base_with_type&& x) noexcept = default;
880 promise_base_with_type(const promise_base_with_type&) = delete;
881 promise_base_with_type& operator=(promise_base_with_type&& x) noexcept = default;
882 void operator=(const promise_base_with_type&) = delete;
883
884 void set_urgent_state(future_state&& state) noexcept {
885 auto* ptr = get_state();
886 // The state can be null if the corresponding future has been
887 // destroyed without producing a continuation.
888 if (ptr) {
889 // FIXME: This is a fairly expensive assert. It would be a
890 // good candidate for being disabled in release builds if
891 // we had such an assert.
892 assert(ptr->_u.st == future_state_base::state::future);
893 new (ptr) future_state(std::move(state));
894 make_ready<urgent::yes>();
895 }
896 }
897
898 template <typename... A>
899 void set_value(A&&... a) noexcept {
900 if (auto *s = get_state()) {
901 s->set(std::forward<A>(a)...);
902 make_ready<urgent::no>();
903 }
904 }
905
910 void set_to_current_exception() noexcept {
911 internal::promise_base::set_to_current_exception();
912 }
913
915 using internal::promise_base::waiting_task;
916
917private:
918
919 template <typename U>
920 friend class seastar::future;
921
922 friend future_state;
923};
924}
926
932SEASTAR_MODULE_EXPORT
933template <typename T>
934class promise : private internal::promise_base_with_type<T> {
935 using future_state = typename internal::promise_base_with_type<T>::future_state;
936 future_state _local_state;
937
938public:
942 promise() noexcept : internal::promise_base_with_type<T>(&_local_state) {}
943
945 void move_it(promise&& x) noexcept;
946 promise(promise&& x) noexcept : internal::promise_base_with_type<T>(std::move(x)) {
947 move_it(std::move(x));
948 }
949 promise(const promise&) = delete;
950 promise& operator=(promise&& x) noexcept {
951 internal::promise_base_with_type<T>::operator=(std::move(x));
952 // If this is a self-move, _state is now nullptr and it is
953 // safe to call move_it.
954 move_it(std::move(x));
955 return *this;
956 }
957 void operator=(const promise&) = delete;
958
963 void set_to_current_exception() noexcept {
964 internal::promise_base::set_to_current_exception();
965 }
966
968 using internal::promise_base::waiting_task;
969
977
989 template <typename... A>
990 void set_value(A&&... a) noexcept {
991 internal::promise_base_with_type<T>::set_value(std::forward<A>(a)...);
992 }
993
998 void set_exception(std::exception_ptr&& ex) noexcept {
999 internal::promise_base::set_exception(std::move(ex));
1000 }
1001
1002 void set_exception(const std::exception_ptr& ex) noexcept {
1003 internal::promise_base::set_exception(ex);
1004 }
1005
1010 template<typename Exception>
1011 std::enable_if_t<!std::is_same_v<std::remove_reference_t<Exception>, std::exception_ptr>, void> set_exception(Exception&& e) noexcept {
1012 internal::promise_base::set_exception(std::forward<Exception>(e));
1013 }
1014
1015 using internal::promise_base_with_type<T>::set_urgent_state;
1016
1017 template <typename U>
1018 friend class future;
1019};
1020
1022
1025
1026
1032template <typename... T> struct is_future : std::false_type {};
1033
1036template <typename... T> struct is_future<future<T...>> : std::true_type {};
1037
1039
1040
1044SEASTAR_MODULE_EXPORT
1045template <typename T>
1046struct futurize;
1047
1048template <typename T>
1049concept Future = is_future<T>::value;
1050
1051template <typename Func, typename... T>
1052concept CanInvoke = std::invocable<Func, T...>;
1053
1054// Deprecated alias
1055template <typename Func, typename... T>
1056concept CanApply = CanInvoke<Func, T...>;
1057
1058template <typename Func, typename... T>
1059concept CanApplyTuple
1060 = sizeof...(T) == 1
1061 && requires (Func func, std::tuple<T...> wrapped_val) {
1062 { std::apply(func, std::get<0>(std::move(wrapped_val))) };
1063 };
1064
1065// Deprecated, use std::is_invocable_r_v
1066template <typename Func, typename Return, typename... T>
1067concept InvokeReturns = requires (Func f, T... args) {
1068 { f(std::forward<T>(args)...) } -> std::same_as<Return>;
1069};
1070
1071// Deprecated alias
1072template <typename Func, typename Return, typename... T>
1073concept ApplyReturns = InvokeReturns<Func, Return, T...>;
1074
1075template <typename Func, typename... T>
1076concept InvokeReturnsAnyFuture = Future<std::invoke_result_t<Func, T...>>;
1077
1078// Deprecated alias
1079template <typename Func, typename... T>
1080concept ApplyReturnsAnyFuture = InvokeReturnsAnyFuture<Func, T...>;
1081
1083
1084// Converts a type to a future type, if it isn't already.
1085template <typename T>
1086using futurize_t = typename futurize<T>::type;
1087
1089
1090template<typename Func, typename... Args>
1091auto futurize_invoke(Func&& func, Args&&... args) noexcept;
1092
1093template<typename Func, typename... Args>
1094auto futurize_apply(Func&& func, std::tuple<Args...>&& args) noexcept;
1095
1098namespace internal {
1099class future_base {
1100protected:
1101 promise_base* _promise;
1102 future_base() noexcept : _promise(nullptr) {}
1103 future_base(promise_base* promise, future_state_base* state) noexcept : _promise(promise) {
1104 _promise->_future = this;
1105 _promise->_state = state;
1106 }
1107
1108 void move_it(future_base&& x, future_state_base* state) noexcept {
1109 _promise = x._promise;
1110 if (auto* p = _promise) {
1111 x.detach_promise();
1112 p->_future = this;
1113 p->_state = state;
1114 }
1115 }
1116
1117 future_base(future_base&& x, future_state_base* state) noexcept {
1118 move_it(std::move(x), state);
1119 }
1120
1121 void clear() noexcept {
1122 if (_promise) {
1123 detach_promise();
1124 }
1125 }
1126
1127 ~future_base() noexcept {
1128 clear();
1129 }
1130
1131 promise_base* detach_promise() noexcept {
1132 _promise->_state = nullptr;
1133 _promise->_future = nullptr;
1134 return std::exchange(_promise, nullptr);
1135 }
1136
1137 void schedule(task* tws, future_state_base* state) noexcept {
1138 promise_base* p = detach_promise();
1139 p->_state = state;
1140 p->set_task(tws);
1141 }
1142
1143 void do_wait() noexcept;
1144
1145 void set_coroutine(task& coroutine) noexcept;
1146
1147 friend class promise_base;
1148};
1149
1150template <typename Func, typename... T>
1151struct future_result {
1152 using type = std::invoke_result_t<Func, T...>;
1153 using future_type = futurize_t<type>;
1154 using func_type = future_type (T&&...);
1155};
1156
1157template <typename Func>
1158struct future_result<Func, void> {
1159 using type = std::invoke_result_t<Func>;
1160 using future_type = futurize_t<type>;
1161 using func_type = future_type ();
1162};
1163
1164template <typename Func, typename T>
1165using future_result_t = typename future_result<Func, T>::type;
1166
1167template <typename Func, typename T>
1168auto future_invoke(Func&& func, T&& v) {
1169 if constexpr (std::is_same_v<T, monostate>) {
1170 return std::invoke(std::forward<Func>(func));
1171 } else {
1172 return std::invoke(std::forward<Func>(func), std::forward<T>(v));
1173 }
1174}
1175
1176template <typename Func, typename... T>
1177struct result_of_apply {
1178 // no "type" member if not a function call signature or not a tuple
1179};
1180
1181template <typename Func, typename... T>
1182struct result_of_apply<Func, std::tuple<T...>> : std::invoke_result<Func, T...> {
1183 // Let std::invoke_result_t determine the result if the input is a tuple
1184};
1185
1186template <typename Func, typename... T>
1187using result_of_apply_t = typename result_of_apply<Func, T...>::type;
1188
1189}
1190
1191template <typename Promise, typename T>
1192task* continuation_base_with_promise<Promise, T>::waiting_task() noexcept {
1193 return _pr.waiting_task();
1194}
1195
1238SEASTAR_MODULE_EXPORT
1239template <typename T>
1240class [[nodiscard]] future : private internal::future_base {
1241 using future_state = seastar::future_state<internal::future_stored_type_t<T>>;
1242 future_state _state;
1243 static constexpr bool copy_noexcept = future_state::copy_noexcept;
1244
1245private:
1246 // This constructor creates a future that is not ready but has no
1247 // associated promise yet. The use case is to have a less flexible
1248 // but more efficient future/promise pair where we know that
1249 // promise::set_value cannot possibly be called without a matching
1250 // future and so that promise doesn't need to store a
1251 // future_state.
1253
1254 future(promise<T>* pr) noexcept : future_base(pr, &_state), _state(std::move(pr->_local_state)) { }
1255 template <typename... A>
1256 future(ready_future_marker m, A&&... a) noexcept : _state(m, std::forward<A>(a)...) { }
1258 future(future_state_base::nested_exception_marker m, future_state_base&& old) noexcept : _state(m, std::move(old)) {}
1259 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)) {}
1260 future(exception_future_marker m, std::exception_ptr&& ex) noexcept : _state(m, std::move(ex)) { }
1261 future(exception_future_marker m, future_state_base&& state) noexcept : _state(m, std::move(state)) { }
1262 [[gnu::always_inline]]
1263 explicit future(future_state&& state) noexcept
1264 : _state(std::move(state)) {
1265 }
1266 internal::promise_base_with_type<T> get_promise() noexcept {
1267 assert(!_promise);
1268 return internal::promise_base_with_type<T>(this);
1269 }
1270 internal::promise_base_with_type<T>* detach_promise() noexcept {
1271 return static_cast<internal::promise_base_with_type<T>*>(future_base::detach_promise());
1272 }
1273 void schedule(continuation_base<T>* tws) noexcept {
1274 future_base::schedule(tws, &tws->_state);
1275 }
1276 template <typename Pr, typename Func, typename Wrapper>
1277 void schedule(Pr&& pr, Func&& func, Wrapper&& wrapper) noexcept {
1278 // If this new throws a std::bad_alloc there is nothing that
1279 // can be done about it. The corresponding future is not ready
1280 // and we cannot break the chain. Since this function is
1281 // noexcept, it will call std::terminate if new throws.
1283 auto tws = new continuation<Pr, Func, Wrapper, T>(std::move(pr), std::move(func), std::move(wrapper));
1284 // In a debug build we schedule ready futures, but not in
1285 // other build modes.
1286#ifdef SEASTAR_DEBUG
1287 if (_state.available()) {
1288 tws->set_state(get_available_state_ref());
1289 ::seastar::schedule(tws);
1290 return;
1291 }
1292#endif
1293 schedule(tws);
1294 _state._u.st = future_state_base::state::invalid;
1295 }
1296
1297 [[gnu::always_inline]]
1298 future_state&& get_available_state_ref() noexcept {
1299 if (_promise) {
1300 detach_promise();
1301 }
1302 return std::move(_state);
1303 }
1304
1305 future<T> rethrow_with_nested(future_state_base&& n) noexcept {
1306 return future<T>(future_state_base::nested_exception_marker(), std::move(n), std::move(_state));
1307 }
1308
1309 future<T> rethrow_with_nested() noexcept {
1310 return future<T>(future_state_base::nested_exception_marker(), std::move(_state));
1311 }
1312
1313 template<typename... U>
1314 friend class shared_future;
1315public:
1317 using value_type = internal::future_stored_type_t<T>;
1318 using tuple_type = internal::future_tuple_type_t<value_type>;
1322 [[gnu::always_inline]]
1323 future(future&& x) noexcept : future_base(std::move(x), &_state), _state(std::move(x._state)) { }
1324 future(const future&) = delete;
1325 future& operator=(future&& x) noexcept {
1326 clear();
1327 move_it(std::move(x), &_state);
1328 _state = std::move(x._state);
1329 return *this;
1330 }
1331 void operator=(const future&) = delete;
1341 [[gnu::always_inline]]
1343 wait();
1344 return get_available_state_ref().take();
1345 }
1346
1347 [[gnu::always_inline]]
1348 std::exception_ptr get_exception() noexcept {
1349 return get_available_state_ref().get_exception();
1350 }
1351
1372 using get0_return_type = typename future_state::get0_return_type;
1373 [[deprecated("Use get() instead")]]
1374 get0_return_type get0() {
1375 return (get0_return_type)get();
1376 }
1377
1383 void wait() noexcept {
1384 if (_state.available()) {
1385 return;
1386 }
1387 do_wait();
1388 }
1389
1393 [[gnu::always_inline]]
1394 bool available() const noexcept {
1395 return _state.available();
1396 }
1397
1401 [[gnu::always_inline]]
1402 bool failed() const noexcept {
1403 return _state.failed();
1404 }
1405
1421 template <typename Func, typename Result = typename internal::future_result<Func, T>::future_type>
1422 requires std::invocable<Func, T>
1423 || (std::same_as<void, T> && std::invocable<Func>)
1424 Result
1425 then(Func&& func) noexcept {
1426#ifndef SEASTAR_TYPE_ERASE_MORE
1427 return then_impl(std::move(func));
1428#else
1429 using func_type = typename internal::future_result<Func, T>::func_type;
1431 {
1433 ncf = noncopyable_function<func_type>([func = std::forward<Func>(func)](auto&&... args) mutable {
1434 return futurize_invoke(func, std::forward<decltype(args)>(args)...);
1435 });
1436 }
1437 return then_impl(std::move(ncf));
1438#endif
1439 }
1440
1460 template <typename Func, typename Result = futurize_t<internal::result_of_apply_t<Func, T>>>
1461 requires ::seastar::CanApplyTuple<Func, T>
1462 Result
1463 then_unpack(Func&& func) noexcept {
1464 return then([func = std::forward<Func>(func)] (T&& tuple) mutable {
1465 // sizeof...(tuple) is required to be 1
1466 return std::apply(func, std::move(tuple));
1467 });
1468 }
1469
1470private:
1471
1472 // Keep this simple so that Named Return Value Optimization is used.
1473 template <typename Func, typename Result>
1474 Result then_impl_nrvo(Func&& func) noexcept {
1476 typename futurator::type fut(future_for_get_promise_marker{});
1477 using pr_type = decltype(fut.get_promise());
1478 schedule(fut.get_promise(), std::move(func), [](pr_type&& pr, Func& func, future_state&& state) {
1479 if (state.failed()) {
1480 pr.set_exception(static_cast<future_state_base&&>(std::move(state)));
1481 } else {
1482 futurator::satisfy_with_result_of(std::move(pr), [&func, &state] {
1483 // clang thinks that "state" is not used, below, for future<>.
1484 // Make it think it is used to avoid an unused-lambda-capture warning.
1485 (void)state;
1486 return internal::future_invoke(func, std::move(state).get_value());
1487 });
1488 }
1489 });
1490 return fut;
1491 }
1492
1493 template <typename Func, typename Result = futurize_t<internal::future_result_t<Func, T>>>
1494 Result
1495 then_impl(Func&& func) noexcept {
1496#ifndef SEASTAR_DEBUG
1497 using futurator = futurize<internal::future_result_t<Func, T>>;
1498 if (failed()) {
1499 return futurator::make_exception_future(static_cast<future_state_base&&>(get_available_state_ref()));
1500 } else if (available()) {
1501 return futurator::invoke(std::forward<Func>(func), get_available_state_ref().take_value());
1502 }
1503#endif
1504 return then_impl_nrvo<Func, Result>(std::forward<Func>(func));
1505 }
1506
1507public:
1523 template <std::invocable<future> Func, typename FuncResult = std::invoke_result_t<Func, future>>
1524 futurize_t<FuncResult>
1525 then_wrapped(Func&& func) & noexcept {
1526 return then_wrapped_maybe_erase<false, FuncResult>(std::forward<Func>(func));
1527 }
1528
1529 template <std::invocable<future&&> Func, typename FuncResult = std::invoke_result_t<Func, future&&>>
1530 futurize_t<FuncResult>
1531 then_wrapped(Func&& func) && noexcept {
1532 return then_wrapped_maybe_erase<true, FuncResult>(std::forward<Func>(func));
1533 }
1534
1535private:
1536
1537 template <bool AsSelf, typename FuncResult, typename Func>
1538 futurize_t<FuncResult>
1539 then_wrapped_maybe_erase(Func&& func) noexcept {
1540#ifndef SEASTAR_TYPE_ERASE_MORE
1541 return then_wrapped_common<AsSelf, FuncResult>(std::forward<Func>(func));
1542#else
1543 using futurator = futurize<FuncResult>;
1544 using WrapFuncResult = typename futurator::type;
1545 noncopyable_function<WrapFuncResult (future&&)> ncf;
1546 {
1547 memory::scoped_critical_alloc_section _;
1548 ncf = noncopyable_function<WrapFuncResult(future &&)>([func = std::forward<Func>(func)](future&& f) mutable {
1549 return futurator::invoke(func, std::move(f));
1550 });
1551 }
1552 return then_wrapped_common<AsSelf, WrapFuncResult>(std::move(ncf));
1553#endif
1554 }
1555
1556 // Keep this simple so that Named Return Value Optimization is used.
1557 template <typename FuncResult, typename Func>
1558 futurize_t<FuncResult>
1559 then_wrapped_nrvo(Func&& func) noexcept {
1560 using futurator = futurize<FuncResult>;
1561 typename futurator::type fut(future_for_get_promise_marker{});
1562 using pr_type = decltype(fut.get_promise());
1563 schedule(fut.get_promise(), std::move(func), [](pr_type&& pr, Func& func, future_state&& state) {
1564 futurator::satisfy_with_result_of(std::move(pr), [&func, &state] {
1565 return func(future(std::move(state)));
1566 });
1567 });
1568 return fut;
1569 }
1570
1571
1572 template <bool AsSelf, typename FuncResult, typename Func>
1573 futurize_t<FuncResult>
1574 then_wrapped_common(Func&& func) noexcept {
1575#ifndef SEASTAR_DEBUG
1576 using futurator = futurize<FuncResult>;
1577 if (available()) {
1578 if constexpr (AsSelf) {
1579 if (_promise) {
1580 detach_promise();
1581 }
1582 return futurator::invoke(std::forward<Func>(func), std::move(*this));
1583 } else {
1584 return futurator::invoke(std::forward<Func>(func), future(get_available_state_ref()));
1585 }
1586 }
1587#endif
1588 return then_wrapped_nrvo<FuncResult, Func>(std::forward<Func>(func));
1589 }
1590
1591 void forward_to(internal::promise_base_with_type<T>&& pr) noexcept {
1592 if (_state.available()) {
1593 pr.set_urgent_state(std::move(_state));
1594 } else {
1595 *detach_promise() = std::move(pr);
1596 }
1597 }
1598
1599public:
1610 void forward_to(promise<T>&& pr) noexcept {
1611 if (_state.available()) {
1612 pr.set_urgent_state(std::move(_state));
1613 } else if (&pr._local_state != pr._state) {
1614 // The only case when _state points to _local_state is
1615 // when get_future was never called. Given that pr will
1616 // soon be destroyed, we know get_future will never be
1617 // called and we can just ignore this request.
1618 *detach_promise() = std::move(pr);
1619 }
1620 }
1621
1622
1623
1639 template <std::invocable Func>
1640 future<T> finally(Func&& func) noexcept {
1641 return then_wrapped(finally_body<Func, is_future<std::invoke_result_t<Func>>::value>(std::forward<Func>(func)));
1642 }
1643
1644
1645 template <typename Func, bool FuncReturnsFuture>
1647
1648 template <typename Func>
1649 struct finally_body<Func, true> {
1650 Func _func;
1651
1652 finally_body(Func&& func) noexcept : _func(std::forward<Func>(func))
1653 { }
1654
1655 future<T> operator()(future<T>&& result) noexcept {
1656 return futurize_invoke(_func).then_wrapped([result = std::move(result)](auto&& f_res) mutable {
1657 if (!f_res.failed()) {
1658 return std::move(result);
1659 } else {
1660 return result.rethrow_with_nested(std::move(f_res._state));
1661 }
1662 });
1663 }
1664 };
1665
1666 template <typename Func>
1667 struct finally_body<Func, false> {
1668 Func _func;
1669
1670 finally_body(Func&& func) noexcept : _func(std::forward<Func>(func))
1671 { }
1672
1673 future<T> operator()(future<T>&& result) noexcept {
1674 try {
1675 _func();
1676 return std::move(result);
1677 } catch (...) {
1678 return result.rethrow_with_nested();
1679 }
1680 };
1681 };
1682
1688 return then_wrapped([] (auto&& f) {
1689 try {
1690 f.get();
1691 } catch (...) {
1692 engine_exit(std::current_exception());
1693 }
1694 });
1695 }
1696
1702 // We need the generic variadic lambda, below, because then() behaves differently
1703 // when value_type is when_all_succeed_tuple
1704 return then([] (auto&&...) {});
1705 }
1706
1720 template <typename Func>
1721 requires std::is_invocable_r_v<future<T> ,Func, std::exception_ptr>
1722 || (std::tuple_size_v<tuple_type> == 0 && std::is_invocable_r_v<void, Func, std::exception_ptr>)
1723 || (std::tuple_size_v<tuple_type> == 1 && std::is_invocable_r_v<T, Func, std::exception_ptr>)
1724 || (std::tuple_size_v<tuple_type> > 1 && std::is_invocable_r_v<tuple_type ,Func, std::exception_ptr>)
1725 future<T> handle_exception(Func&& func) noexcept {
1726 return then_wrapped([func = std::forward<Func>(func)]
1727 (auto&& fut) mutable -> future<T> {
1728 if (!fut.failed()) {
1729 return make_ready_future<T>(fut.get());
1730 } else {
1731 return futurize_invoke(func, fut.get_exception());
1732 }
1733 });
1734 }
1735
1746 template <typename Func>
1747 future<T> handle_exception_type(Func&& func) noexcept {
1748 using trait = function_traits<Func>;
1749 static_assert(trait::arity == 1, "func can take only one parameter");
1750 using ex_type = typename trait::template arg<0>::type;
1751 return then_wrapped([func = std::forward<Func>(func)]
1752 (auto&& fut) mutable -> future<T> {
1753 try {
1754 return make_ready_future<T>(fut.get());
1755 } catch(ex_type& ex) {
1756 return futurize_invoke(func, ex);
1757 }
1758 });
1759 }
1760
1766 void ignore_ready_future() noexcept {
1767 _state.ignore();
1768 }
1769
1770 using future_base::set_coroutine;
1771
1772private:
1773 void set_task(task& t) noexcept {
1774 assert(_promise);
1775 _promise->set_task(&t);
1776 }
1777
1778 void set_callback(continuation_base<T>* callback) noexcept {
1779 if (_state.available()) {
1780 callback->set_state(get_available_state_ref());
1781 ::seastar::schedule(callback);
1782 } else {
1783 assert(_promise);
1784 schedule(callback);
1785 }
1786
1787 }
1788
1790 template <typename U>
1791 friend class future;
1792 template <typename U>
1793 friend class promise;
1794 template <typename U>
1795 friend struct futurize;
1796 template <typename U>
1797 friend class internal::promise_base_with_type;
1798 template <typename U, typename... A>
1799 friend future<U> make_ready_future(A&&... value) noexcept;
1800 template <typename U>
1801 friend future<U> make_exception_future(std::exception_ptr&& ex) noexcept;
1802 template <typename U, typename Exception>
1803 friend future<U> make_exception_future(Exception&& ex) noexcept;
1804 template <typename U>
1805 friend future<U> internal::make_exception_future(future_state_base&& state) noexcept;
1806 template <typename U>
1807 friend future<U> current_exception_as_future() noexcept;
1808 template <typename U>
1809 friend void internal::set_callback(future<U>&&, continuation_base<U>*) noexcept;
1811};
1812
1813
1814namespace internal {
1815template <typename T>
1816struct futurize_base {
1818 using type = future<T>;
1820 using promise_type = promise<T>;
1821 using promise_base_with_type = internal::promise_base_with_type<T>;
1822
1824 static inline type convert(T&& value) { return make_ready_future<T>(std::move(value)); }
1825 static inline type convert(type&& value) { return std::move(value); }
1826
1828 template <typename Arg>
1829 static inline type make_exception_future(Arg&& arg) noexcept;
1830};
1831
1832template <>
1833struct futurize_base<void> {
1834 using type = future<>;
1835 using promise_type = promise<>;
1836 using promise_base_with_type = internal::promise_base_with_type<>;
1837
1838 static inline type convert(type&& value) {
1839 return std::move(value);
1840 }
1841 template <typename Arg>
1842 static inline type make_exception_future(Arg&& arg) noexcept;
1843};
1844
1845template <typename T>
1846struct futurize_base<future<T>> : public futurize_base<T> {};
1847
1848template <>
1849struct futurize_base<future<>> : public futurize_base<void> {};
1850}
1851
1852template <typename T>
1853struct futurize : public internal::futurize_base<T> {
1854 using base = internal::futurize_base<T>;
1855 using type = typename base::type;
1856 using promise_type = typename base::promise_type;
1857 using promise_base_with_type = typename base::promise_base_with_type;
1860 using tuple_type = typename type::tuple_type;
1861 using base::convert;
1862 using base::make_exception_future;
1863
1866 template<typename Func, typename... FuncArgs>
1867 static inline type apply(Func&& func, std::tuple<FuncArgs...>&& args) noexcept;
1868
1871 template<typename Func, typename... FuncArgs>
1872 static inline type invoke(Func&& func, FuncArgs&&... args) noexcept;
1873
1874 template<typename Func>
1875 static inline type invoke(Func&& func, internal::monostate) noexcept {
1876 return invoke(std::forward<Func>(func));
1877 }
1878
1880 template<typename Func, typename... FuncArgs>
1881 [[deprecated("Use invoke for varargs")]]
1882 static inline type apply(Func&& func, FuncArgs&&... args) noexcept {
1883 return invoke(std::forward<Func>(func), std::forward<FuncArgs>(args)...);
1884 }
1885
1886 static type current_exception_as_future() noexcept {
1888 }
1889
1891 static type from_tuple(tuple_type&& value) {
1892 return type(ready_future_marker(), std::move(value));
1893 }
1895 static type from_tuple(const tuple_type& value) {
1896 return type(ready_future_marker(), value);
1897 }
1898
1900 static type from_tuple(value_type&& value) {
1901 return type(ready_future_marker(), std::move(value));
1902 }
1904 static type from_tuple(const value_type& value) {
1905 return type(ready_future_marker(), value);
1906 }
1907private:
1911 template<std::invocable Func>
1912 static void satisfy_with_result_of(promise_base_with_type&&, Func&& func);
1913
1914 template <typename U>
1915 friend class future;
1916};
1917
1918inline internal::promise_base::promise_base(future_base* future, future_state_base* state) noexcept
1919 : _future(future), _state(state) {
1920 _future->_promise = this;
1921}
1922
1923template <typename T>
1924inline
1925future<T>
1927 assert(!this->_future && this->_state && !this->_task);
1928 return future<T>(this);
1929}
1930
1931template <typename T>
1932inline
1933void promise<T>::move_it(promise&& x) noexcept {
1934 if (this->_state == &x._local_state) {
1935 this->_state = &_local_state;
1936 new (&_local_state) future_state(std::move(x._local_state));
1937 }
1938}
1939
1940SEASTAR_MODULE_EXPORT_BEGIN
1941template <typename T, typename... A>
1942inline
1943future<T> make_ready_future(A&&... value) noexcept {
1944 return future<T>(ready_future_marker(), std::forward<A>(value)...);
1945}
1946
1947template <typename T>
1948inline
1949future<T> make_exception_future(std::exception_ptr&& ex) noexcept {
1950 return future<T>(exception_future_marker(), std::move(ex));
1951}
1952SEASTAR_MODULE_EXPORT_END
1953
1954template <typename T>
1955inline
1956future<T> internal::make_exception_future(future_state_base&& state) noexcept {
1957 return future<T>(exception_future_marker(), std::move(state));
1958}
1959
1960SEASTAR_MODULE_EXPORT_BEGIN
1961template <typename T>
1964}
1965
1966void log_exception_trace() noexcept;
1967
1974template <typename T, typename Exception>
1975inline
1976future<T> make_exception_future(Exception&& ex) noexcept {
1977 log_exception_trace();
1978 return make_exception_future<T>(std::make_exception_ptr(std::forward<Exception>(ex)));
1979}
1980
1981template <typename T, typename Exception>
1982future<T> make_exception_future_with_backtrace(Exception&& ex) noexcept {
1983 return make_exception_future<T>(make_backtraced_exception_ptr<Exception>(std::forward<Exception>(ex)));
1984}
1985SEASTAR_MODULE_EXPORT_END
1986
1988
1990
1991template<typename T>
1992template<typename Func, typename... FuncArgs>
1993typename futurize<T>::type futurize<T>::apply(Func&& func, std::tuple<FuncArgs...>&& args) noexcept {
1994 try {
1995 using ret_t = decltype(std::apply(std::forward<Func>(func), std::move(args)));
1996 if constexpr (std::is_void_v<ret_t>) {
1997 std::apply(std::forward<Func>(func), std::move(args));
1998 return make_ready_future<>();
1999 } else if constexpr (is_future<ret_t>::value){
2000 return std::apply(std::forward<Func>(func), std::move(args));
2001 } else {
2002 return convert(std::apply(std::forward<Func>(func), std::move(args)));
2003 }
2004 } catch (...) {
2006 }
2007}
2008
2009template<typename T>
2010template<std::invocable Func>
2011void futurize<T>::satisfy_with_result_of(promise_base_with_type&& pr, Func&& func) {
2012 using ret_t = decltype(func());
2013 if constexpr (std::is_void_v<ret_t>) {
2014 func();
2015 pr.set_value();
2016 } else if constexpr (is_future<ret_t>::value) {
2017 func().forward_to(std::move(pr));
2018 } else {
2019 pr.set_value(func());
2020 }
2021}
2022
2023template<typename T>
2024template<typename Func, typename... FuncArgs>
2025typename futurize<T>::type futurize<T>::invoke(Func&& func, FuncArgs&&... args) noexcept {
2026 try {
2027 using ret_t = decltype(func(std::forward<FuncArgs>(args)...));
2028 if constexpr (std::is_void_v<ret_t>) {
2029 func(std::forward<FuncArgs>(args)...);
2030 return make_ready_future<>();
2031 } else if constexpr (is_future<ret_t>::value) {
2032 return func(std::forward<FuncArgs>(args)...);
2033 } else {
2034 return convert(func(std::forward<FuncArgs>(args)...));
2035 }
2036 } catch (...) {
2038 }
2039}
2040
2041template <typename T>
2042template <typename Arg>
2043inline
2044future<T>
2045internal::futurize_base<T>::make_exception_future(Arg&& arg) noexcept {
2046 using ::seastar::make_exception_future;
2047 using ::seastar::internal::make_exception_future;
2048 return make_exception_future<T>(std::forward<Arg>(arg));
2049}
2050
2051template <typename Arg>
2052inline
2053future<>
2054internal::futurize_base<void>::make_exception_future(Arg&& arg) noexcept {
2055 using ::seastar::make_exception_future;
2056 using ::seastar::internal::make_exception_future;
2057 return make_exception_future<>(std::forward<Arg>(arg));
2058}
2059
2060template<typename Func, typename... Args>
2061auto futurize_invoke(Func&& func, Args&&... args) noexcept {
2062 using futurator = futurize<std::invoke_result_t<Func, Args&&...>>;
2063 return futurator::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
2064}
2065
2066template<typename Func, typename... Args>
2067[[deprecated("Use futurize_invoke for varargs")]]
2068auto futurize_apply(Func&& func, Args&&... args) noexcept {
2069 return futurize_invoke(std::forward<Func>(func), std::forward<Args>(args)...);
2070}
2071
2072template<typename Func, typename... Args>
2073auto futurize_apply(Func&& func, std::tuple<Args...>&& args) noexcept {
2074 using futurator = futurize<std::invoke_result_t<Func, Args&&...>>;
2075 return futurator::apply(std::forward<Func>(func), std::move(args));
2076}
2077
2078namespace internal {
2079
2080template <typename T>
2081inline
2082void set_callback(future<T>&& fut, continuation_base<T>* callback) noexcept {
2083 return std::move(fut).set_callback(callback);
2084}
2085
2086}
2087
2088
2090
2091}
A representation of a possibly not-yet-computed value.
Definition: future.hh:1240
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:1525
future< T > handle_exception_type(Func &&func) noexcept
Handle the exception of a certain type carried by this future.
Definition: future.hh:1747
void wait() noexcept
Definition: future.hh:1383
internal::future_stored_type_t< T > value_type
The data type carried by the future.
Definition: future.hh:1317
future< T > handle_exception(Func &&func) noexcept
Handle the exception carried by this future.
Definition: future.hh:1725
Result then(Func &&func) noexcept
Schedule a block of code to run when the future is ready.
Definition: future.hh:1425
value_type && get()
gets the value returned by the computation
Definition: future.hh:1342
bool failed() const noexcept
Checks whether the future has failed.
Definition: future.hh:1402
requires ::seastar::CanApplyTuple< Func, T > Result then_unpack(Func &&func) noexcept
Schedule a block of code to run when the future is ready, unpacking tuples.
Definition: future.hh:1463
bool available() const noexcept
Checks whether the future is available.
Definition: future.hh:1394
typename future_state::get0_return_type get0_return_type
Definition: future.hh:1372
void forward_to(promise< T > &&pr) noexcept
Satisfy some promise object with this future as a result.
Definition: future.hh:1610
future(future &&x) noexcept
Moves the future into a new object.
Definition: future.hh:1323
future discard_result() noexcept
Discards the value carried by this future.
Definition: future.hh:1701
future or_terminate() noexcept
Terminate the program if this future fails.
Definition: future.hh:1687
void ignore_ready_future() noexcept
Ignore any result hold by this future.
Definition: future.hh:1766
Definition: future.hh:1646
promise - allows a future value to be made available at a later time.
Definition: future.hh:934
void set_to_current_exception() noexcept
Definition: future.hh:963
std::enable_if_t<!std::is_same_v< std::remove_reference_t< Exception >, std::exception_ptr >, void > set_exception(Exception &&e) noexcept
Marks the promise as failed.
Definition: future.hh:1011
void set_value(A &&... a) noexcept
Sets the promises value.
Definition: future.hh:990
void set_exception(std::exception_ptr &&ex) noexcept
Marks the promise as failed.
Definition: future.hh:998
promise() noexcept
Constructs an empty promise.
Definition: future.hh:942
Like future except the result can be waited for by many fibers.
Definition: shared_future.hh:108
Definition: task.hh:34
future< T > make_ready_future(A &&... value) noexcept
Creates a future in an available, value state.
Definition: future.hh:1943
future< T > get_future() noexcept
Gets the promise's associated future.
Definition: future.hh:1926
future< std::remove_cv_t< std::remove_reference_t< T > > > as_ready_future(T &&v) noexcept
Returns a ready future that is already resolved.
Definition: future.hh:173
future< T > make_exception_future(std::exception_ptr &&value) noexcept
Creates a future in an available, failed state.
Definition: future.hh:1949
future< T > current_exception_as_future() noexcept
Returns std::current_exception() wrapped in a future.
Definition: future.hh:1962
void move_it(promise &&x) noexcept
Moves a promise object.
Definition: future.hh:1933
Definition: future.hh:566
Definition: future.hh:565
Definition: critical_alloc_section.hh:80
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
shard_id this_shard_id() noexcept
Returns shard_id of the of the current shard.
Definition: shard_id.hh:52
Definition: noncopyable_function.hh:37
Definition: function_traits.hh:62
STL namespace.
Exception type for broken promises.
Definition: future.hh:222
Definition: future.hh:419
friend future< U > current_exception_as_future() noexcept
Returns std::current_exception() wrapped in a future.
Definition: future.hh:1962
Converts a type to a future type, if it isn't already.
Definition: future.hh:1853
static type apply(Func &&func, FuncArgs &&... args) noexcept
Deprecated alias of invoke.
Definition: future.hh:1882
static type from_tuple(tuple_type &&value)
Convert the tuple representation into a future.
Definition: future.hh:1891
static type from_tuple(value_type &&value)
Convert the tuple representation into a future.
Definition: future.hh:1900
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:1904
static type from_tuple(const tuple_type &value)
Convert the tuple representation into a future.
Definition: future.hh:1895
typename type::value_type value_type
The value tuple type associated with type.
Definition: future.hh:1859
static type invoke(Func &&func, FuncArgs &&... args) noexcept
Check whether a type is a future.
Definition: future.hh:1032
Definition: future.hh:48
Definition: future.hh:435