Seastar
High performance C++ framework for concurrent servers
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
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
289
290template <typename T>
291struct uninitialized_wrapper {
292 using tuple_type = future_tuple_type_t<T>;
293 [[no_unique_address]] union any {
294 any() noexcept {}
295 ~any() {}
296 // T can be a reference, so wrap it.
297 [[no_unique_address]] maybe_wrap_ref<T> value;
298 } _v;
299
300public:
301 uninitialized_wrapper() noexcept = default;
302 template<typename... U>
303 std::enable_if_t<!std::is_same_v<std::tuple<std::remove_cv_t<U>...>, std::tuple<tuple_type>>, void>
304 uninitialized_set(U&&... vs) {
305 new (&_v.value) maybe_wrap_ref<T>(T(std::forward<U>(vs)...));
306 }
307 void uninitialized_set(tuple_type&& v) {
308 uninitialized_set(std::move(std::get<0>(v)));
309 }
310 void uninitialized_set(const tuple_type& v) {
311 uninitialized_set(std::get<0>(v));
312 }
313 maybe_wrap_ref<T>& uninitialized_get() {
314 return _v.value;
315 }
316 const maybe_wrap_ref<T>& uninitialized_get() const {
317 return _v.value;
318 }
319};
320
321template <>
322struct uninitialized_wrapper<internal::monostate> {
323 [[no_unique_address]] internal::monostate _v;
324public:
325 uninitialized_wrapper() noexcept = default;
326 void uninitialized_set() {
327 }
328 void uninitialized_set(internal::monostate) {
329 }
330 void uninitialized_set(std::tuple<>&& v) {
331 }
332 void uninitialized_set(const std::tuple<>& v) {
333 }
334 internal::monostate& uninitialized_get() {
335 return _v;
336 }
337 const internal::monostate& uninitialized_get() const {
338 return _v;
339 }
340};
341
342template <typename T>
343struct is_trivially_move_constructible_and_destructible {
344 static constexpr bool value = std::is_trivially_move_constructible_v<T> && std::is_trivially_destructible_v<T>;
345};
346
347template <bool... v>
348struct all_true : std::false_type {};
349
350template <>
351struct all_true<> : std::true_type {};
352
353template <bool... v>
354struct all_true<true, v...> : public all_true<v...> {};
355
356template<typename T>
357struct is_tuple_effectively_trivially_move_constructible_and_destructible_helper;
358
359template <typename... T>
360struct is_tuple_effectively_trivially_move_constructible_and_destructible_helper<std::tuple<T...>> {
361 static constexpr bool value = all_true<is_trivially_move_constructible_and_destructible<T>::value...>::value;
362};
363
364template <typename T>
365static constexpr bool is_tuple_effectively_trivially_move_constructible_and_destructible =
366 is_tuple_effectively_trivially_move_constructible_and_destructible_helper<T>::value;
367
368}
369
370//
371// A future/promise pair maintain one logical value (a future_state).
372// There are up to three places that can store it, but only one is
373// active at any time.
374//
375// - in the promise _local_state member variable
376//
377// This is necessary because a promise is created first and there
378// would be nowhere else to put the value.
379//
380// - in the future _state variable
381//
382// This is used anytime a future exists and then has not been called
383// yet. This guarantees a simple access to the value for any code
384// that already has a future.
385//
386// - in the task associated with the .then() clause (after .then() is called,
387// if a value was not set)
388//
389//
390// The promise maintains a pointer to the state, which is modified as
391// the state moves to a new location due to events (such as .then() or
392// get_future being called) or due to the promise or future being
393// moved around.
394//
395
396// non templated base class to reduce code duplication
397SEASTAR_MODULE_EXPORT
399 static_assert(sizeof(std::exception_ptr) == sizeof(void*), "exception_ptr not a pointer");
400 enum class state : uintptr_t {
401 invalid = 0,
402 future = 1,
403 // the substate is intended to decouple the run-time prevention
404 // for duplicative result extraction (calling e.g. then() twice
405 // ends up in abandoned()) from the wrapped object's destruction
406 // handling which is orchestrated by future_state. Instead of
407 // creating a temporary future_state just for the sake of setting
408 // the "invalid" in the source instance, result_unavailable can
409 // be set to ensure future_state_base::available() returns false.
410 result_unavailable = 2,
411 result = 3,
412 exception_min = 4, // or anything greater
413 };
414 union any {
415 any() noexcept { st = state::future; }
416 any(state s) noexcept { st = s; }
417 void set_exception(std::exception_ptr&& e) noexcept {
418 new (&ex) std::exception_ptr(std::move(e));
419 assert(st >= state::exception_min);
420 }
421 any(std::exception_ptr&& e) noexcept {
422 set_exception(std::move(e));
423 }
424 // From a users' perspective, a result_unavailable is not valid
425 bool valid() const noexcept { return st != state::invalid && st != state::result_unavailable; }
426 bool available() const noexcept { return st == state::result || st >= state::exception_min; }
427 bool failed() const noexcept { return __builtin_expect(st >= state::exception_min, false); }
428 void check_failure() noexcept;
429 ~any() noexcept { }
430 std::exception_ptr take_exception() noexcept {
431 std::exception_ptr ret(std::move(ex));
432 // Unfortunately in libstdc++ ~exception_ptr is defined out of line. We know that it does nothing for
433 // moved out values, so we omit calling it. This is critical for the code quality produced for this
434 // function. Without the out of line call, gcc can figure out that both sides of the if produce
435 // identical code and merges them.if
436 // We don't make any assumptions about other c++ libraries.
437 // There is request with gcc to define it inline: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90295
438#ifndef __GLIBCXX__
439 ex.~exception_ptr();
440#endif
441 st = state::invalid;
442 return ret;
443 }
444 void move_it(any&& x) noexcept {
445#ifdef __GLIBCXX__
446 // Unfortunally gcc cannot fully optimize the regular
447 // implementation:
448 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95014
449 // Given what we know about the libstdc++ implementation
450 // (see the comment in take_exception), we can just
451 // memmove and zero x. We use memmove to guarantee
452 // vaild results if &x == this.
453 memmove(static_cast<void*>(this), &x, sizeof(any));
454 x.st = state::invalid;
455#else
456 if (x.st < state::exception_min) {
457 st = x.st;
458 x.st = state::invalid;
459 } else {
460 new (&ex) std::exception_ptr(x.take_exception());
461 }
462#endif
463 }
464 any(any&& x) noexcept {
465 move_it(std::move(x));
466 }
467 any& operator=(any&& x) noexcept {
468 check_failure();
469 // If this is a self move assignment, check_failure
470 // guarantees that we don't have an exception and calling
471 // move_it is safe.
472 move_it(std::move(x));
473 return *this;
474 }
475 bool has_result() const noexcept {
476 return st == state::result || st == state::result_unavailable;
477 }
478 state st;
479 std::exception_ptr ex;
480 } _u;
481
482 future_state_base() noexcept = default;
483 future_state_base(state st) noexcept : _u(st) { }
484 future_state_base(std::exception_ptr&& ex) noexcept : _u(std::move(ex)) { }
485 future_state_base(future_state_base&& x) noexcept : _u(std::move(x._u)) { }
486
487 // We never need to destruct this polymorphicly, so we can make it
488 // protected instead of virtual.
489protected:
495 ~future_state_base() noexcept = default;
496
497 void rethrow_exception() &&;
498 void rethrow_exception() const&;
499
500public:
501
502 bool valid() const noexcept { return _u.valid(); }
503 bool available() const noexcept { return _u.available(); }
504 bool failed() const noexcept { return _u.failed(); }
505
506 void ignore() noexcept;
507
508 void set_exception(std::exception_ptr&& ex) noexcept {
509 assert(_u.st == state::future);
510 _u.set_exception(std::move(ex));
511 }
512 future_state_base& operator=(future_state_base&& x) noexcept = default;
513 void set_exception(future_state_base&& state) noexcept {
514 assert(_u.st == state::future);
515 *this = std::move(state);
516 }
517 std::exception_ptr get_exception() && noexcept {
518 assert(_u.st >= state::exception_min);
519 // Move ex out so future::~future() knows we've handled it
520 return _u.take_exception();
521 }
522 const std::exception_ptr& get_exception() const& noexcept {
523 assert(_u.st >= state::exception_min);
524 return _u.ex;
525 }
526 template <typename U>
527 friend struct future_state;
528 template <typename U>
530 template <typename U>
531 friend class future;
532 template <typename T>
533 friend struct futurize;
534};
535
536void report_failed_future(future_state_base::any&& state) noexcept;
537
538inline void future_state_base::any::check_failure() noexcept {
539 if (failed()) {
540 report_failed_future(std::move(*this));
541 }
542}
543
547
549template <typename T>
550struct future_state : public future_state_base, private internal::uninitialized_wrapper<T> {
551 static constexpr bool copy_noexcept = std::is_nothrow_copy_constructible_v<T>;
552 static constexpr bool has_trivial_move_and_destroy = internal::is_trivially_move_constructible_and_destructible<T>::value;
553 static_assert(std::is_nothrow_move_constructible_v<T>,
554 "Types must be no-throw move constructible");
555 static_assert(std::is_nothrow_destructible_v<T>,
556 "Types must be no-throw destructible");
557 future_state() noexcept = default;
558 void move_it(future_state&& x) noexcept {
559 if constexpr (has_trivial_move_and_destroy) {
560#pragma GCC diagnostic push
561 // This function may copy uninitialized memory, such as when
562 // creating an uninitialized promise and calling get_future()
563 // on it. Gcc 12 started to catch some simple cases of this
564 // at compile time, so we need to tell it that it's fine.
565#pragma GCC diagnostic ignored "-Wuninitialized"
566 memmove(reinterpret_cast<char*>(&this->uninitialized_get()),
567 &x.uninitialized_get(),
568 internal::used_size<internal::maybe_wrap_ref<T>>::value);
569#pragma GCC diagnostic pop
570 } else if (_u.has_result()) {
571 this->uninitialized_set(std::move(x.uninitialized_get()));
572 std::destroy_at(&x.uninitialized_get());
573 }
574 }
575
576 [[gnu::always_inline]]
577 future_state(future_state&& x) noexcept : future_state_base(std::move(x)) {
578 move_it(std::move(x));
579 }
580
581 void clear() noexcept {
582 if (_u.has_result()) {
583 std::destroy_at(&this->uninitialized_get());
584 } else {
585 _u.check_failure();
586 }
587 }
588 __attribute__((always_inline))
589 ~future_state() noexcept {
590 clear();
591 }
592 future_state& operator=(future_state&& x) noexcept {
593 clear();
594 future_state_base::operator=(std::move(x));
595 // If &x == this, _u.st is now state::invalid and so it is
596 // safe to call move_it.
597 move_it(std::move(x));
598 return *this;
599 }
600 template <typename... A>
601 future_state(ready_future_marker, A&&... a) noexcept : future_state_base(state::result) {
602 try {
603 this->uninitialized_set(std::forward<A>(a)...);
604 } catch (...) {
605 new (this) future_state(current_exception_future_marker());
606 }
607 }
608 template <typename... A>
609 void set(A&&... a) noexcept {
610 assert(_u.st == state::future);
611 new (this) future_state(ready_future_marker(), std::forward<A>(a)...);
612 }
613 future_state(exception_future_marker, std::exception_ptr&& ex) noexcept : future_state_base(std::move(ex)) { }
614 future_state(exception_future_marker, future_state_base&& state) noexcept : future_state_base(std::move(state)) { }
615 future_state(current_exception_future_marker m) noexcept : future_state_base(m) { }
616 future_state(nested_exception_marker m, future_state_base&& old) noexcept : future_state_base(m, std::move(old)) { }
617 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)) { }
618 T&& get_value() && noexcept {
619 assert(_u.st == state::result);
620 return static_cast<T&&>(this->uninitialized_get());
621 }
622 T&& take_value() && noexcept {
623 assert(_u.st == state::result);
624 _u.st = state::result_unavailable;
625 return static_cast<T&&>(this->uninitialized_get());
626 }
627 template<typename U = T>
628 const std::enable_if_t<std::is_copy_constructible_v<U>, U>& get_value() const& noexcept(copy_noexcept) {
629 assert(_u.st == state::result);
630 return this->uninitialized_get();
631 }
632 T&& take() && {
633 assert(available());
634 if (_u.st >= state::exception_min) {
635 std::move(*this).rethrow_exception();
636 }
637 _u.st = state::result_unavailable;
638 return static_cast<T&&>(this->uninitialized_get());
639 }
640 T&& get() && {
641 assert(available());
642 if (_u.st >= state::exception_min) {
643 std::move(*this).rethrow_exception();
644 }
645 return static_cast<T&&>(this->uninitialized_get());
646 }
647 const T& get() const& {
648 assert(available());
649 if (_u.st >= state::exception_min) {
650 rethrow_exception();
651 }
652 return this->uninitialized_get();
653 }
654 using get0_return_type = typename internal::get0_return_type<T>::type;
655 static get0_return_type get0(T&& x) {
656 return internal::get0_return_type<T>::get0(std::move(x));
657 }
658
659 get0_return_type get0() {
660 return std::move(*this).get();
661 }
662};
663
664template <typename T = void>
665class continuation_base : public task {
666protected:
667 using future_state = seastar::future_state<internal::future_stored_type_t<T>>;
668 future_state _state;
669 using future_type = future<T>;
670 using promise_type = promise<T>;
671public:
672 continuation_base() noexcept = default;
673 void set_state(future_state&& state) noexcept {
674 _state = std::move(state);
675 }
676 // This override of waiting_task() is needed here because there are cases
677 // when backtrace is obtained from the destructor of this class and objects
678 // of derived classes are already destroyed at that time. If we didn't
679 // have this override we would get a "pure virtual function call" exception.
680 virtual task* waiting_task() noexcept override { return nullptr; }
681 friend class internal::promise_base_with_type<T>;
682 friend class promise<T>;
683 friend class future<T>;
684};
685
686// Given a future type, find the corresponding continuation_base.
687template <typename Future>
688struct continuation_base_from_future;
689
690template <typename... T>
691struct continuation_base_from_future<future<T...>> {
692 using type = continuation_base<T...>;
693};
694
695template <typename Future>
696using continuation_base_from_future_t = typename continuation_base_from_future<Future>::type;
697
698template <typename Promise, typename T = void>
699class continuation_base_with_promise : public continuation_base<T> {
700 friend class internal::promise_base_with_type<T>;
701protected:
702 continuation_base_with_promise(Promise&& pr) noexcept : _pr(std::move(pr)) {
703 task::make_backtrace();
704 }
705 virtual task* waiting_task() noexcept override;
706 Promise _pr;
707};
708
709template <typename Promise, typename Func, typename Wrapper, typename T = void>
710struct continuation final : continuation_base_with_promise<Promise, T> {
711 // Func is the original function passed to then/then_wrapped. The
712 // Wrapper is a helper function that implements the specific logic
713 // needed by then/then_wrapped. We call the wrapper passing it the
714 // original function, promise and state.
715 // Note that if Func's move constructor throws, this will call
716 // std::unexpected. We could try to require Func to be nothrow
717 // move constructible, but that will cause a lot of churn. Since
718 // we can't support a failure to create a continuation, calling
719 // std::unexpected as close to the failure as possible is the best
720 // we can do.
721 continuation(Promise&& pr, Func&& func, Wrapper&& wrapper) noexcept
722 : continuation_base_with_promise<Promise, T>(std::move(pr))
723 , _func(std::move(func))
724 , _wrapper(std::move(wrapper)) {}
725 virtual void run_and_dispose() noexcept override {
726 try {
727 _wrapper(std::move(this->_pr), _func, std::move(this->_state));
728 } catch (...) {
729 this->_pr.set_to_current_exception();
730 }
731 delete this;
732 }
733 Func _func;
734 [[no_unique_address]] Wrapper _wrapper;
735};
736
737namespace internal {
738
739template <typename T = void>
740future<T> make_exception_future(future_state_base&& state) noexcept;
741
742template <typename T = void>
743void set_callback(future<T>&& fut, continuation_base<T>* callback) noexcept;
744
745class future_base;
746
747class promise_base {
748protected:
749 enum class urgent { no, yes };
750 future_base* _future = nullptr;
751
752 // This points to the future_state that is currently being
753 // used. See comment above the future_state struct definition for
754 // details.
755 future_state_base* _state;
756
757 task* _task = nullptr;
758#ifdef SEASTAR_DEBUG_PROMISE
759 int _task_shard = -1;
760
761 void set_task(task* task) noexcept {
762 _task = task;
763 _task_shard = this_shard_id();
764 }
765 void assert_task_shard() const noexcept;
766#else
767 void set_task(task* task) noexcept {
768 _task = task;
769 }
770 void assert_task_shard() const noexcept { }
771#endif
772
773 promise_base(const promise_base&) = delete;
774 promise_base(future_state_base* state) noexcept : _state(state) {}
775 promise_base(future_base* future, future_state_base* state) noexcept;
776 void move_it(promise_base&& x) noexcept;
777 promise_base(promise_base&& x) noexcept;
778
779 void clear() noexcept;
780
781 // We never need to destruct this polymorphicly, so we can make it
782 // protected instead of virtual
783 ~promise_base() noexcept {
784 clear();
785 }
786
787 void operator=(const promise_base&) = delete;
788 promise_base& operator=(promise_base&& x) noexcept;
789
790 template<urgent Urgent>
791 void make_ready() noexcept;
792
793 template<typename T>
794 void set_exception_impl(T&& val) noexcept {
795 if (_state) {
796 _state->set_exception(std::move(val));
797 make_ready<urgent::no>();
798 } else {
799 // We get here if promise::get_future is called and the
800 // returned future is destroyed without creating a
801 // continuation.
802 // In older versions of seastar we would store a local
803 // copy of ex and warn in the promise destructor.
804 // Since there isn't any way for the user to clear
805 // the exception, we issue the warning from here.
806 report_failed_future(val);
807 }
808 }
809
810 void set_exception(future_state_base&& state) noexcept {
811 set_exception_impl(std::move(state));
812 }
813
814 void set_exception(std::exception_ptr&& ex) noexcept {
815 set_exception_impl(std::move(ex));
816 }
817
818 void set_exception(const std::exception_ptr& ex) noexcept {
819 set_exception(std::exception_ptr(ex));
820 }
821
822 template<typename Exception>
823 std::enable_if_t<!std::is_same_v<std::remove_reference_t<Exception>, std::exception_ptr>, void> set_exception(Exception&& e) noexcept {
824 set_exception(std::make_exception_ptr(std::forward<Exception>(e)));
825 }
826
827 friend class future_base;
828 template <typename U> friend class seastar::future;
829
830public:
835 void set_to_current_exception() noexcept;
836
838 task* waiting_task() const noexcept { return _task; }
839};
840
847template <typename T>
848class promise_base_with_type : protected internal::promise_base {
849protected:
850 using future_state = seastar::future_state<future_stored_type_t<T>>;
851 future_state* get_state() noexcept {
852 return static_cast<future_state*>(_state);
853 }
854 static constexpr bool copy_noexcept = future_state::copy_noexcept;
855public:
856 promise_base_with_type(future_state_base* state) noexcept : promise_base(state) { }
857 promise_base_with_type(future<T>* future) noexcept : promise_base(future, &future->_state) { }
858 promise_base_with_type(promise_base_with_type&& x) noexcept = default;
859 promise_base_with_type(const promise_base_with_type&) = delete;
860 promise_base_with_type& operator=(promise_base_with_type&& x) noexcept = default;
861 void operator=(const promise_base_with_type&) = delete;
862
863 void set_urgent_state(future_state&& state) noexcept {
864 auto* ptr = get_state();
865 // The state can be null if the corresponding future has been
866 // destroyed without producing a continuation.
867 if (ptr) {
868 // FIXME: This is a fairly expensive assert. It would be a
869 // good candidate for being disabled in release builds if
870 // we had such an assert.
871 assert(ptr->_u.st == future_state_base::state::future);
872 new (ptr) future_state(std::move(state));
873 make_ready<urgent::yes>();
874 }
875 }
876
877 template <typename... A>
878 void set_value(A&&... a) noexcept {
879 if (auto *s = get_state()) {
880 s->set(std::forward<A>(a)...);
881 make_ready<urgent::no>();
882 }
883 }
884
889 void set_to_current_exception() noexcept {
890 internal::promise_base::set_to_current_exception();
891 }
892
894 using internal::promise_base::waiting_task;
895
896private:
897
898 template <typename U>
899 friend class seastar::future;
900
901 friend future_state;
902};
903}
905
911SEASTAR_MODULE_EXPORT
912template <typename T>
913class promise : private internal::promise_base_with_type<T> {
914 using future_state = typename internal::promise_base_with_type<T>::future_state;
915 future_state _local_state;
916
917public:
921 promise() noexcept : internal::promise_base_with_type<T>(&_local_state) {}
922
924 void move_it(promise&& x) noexcept;
925 promise(promise&& x) noexcept : internal::promise_base_with_type<T>(std::move(x)) {
926 move_it(std::move(x));
927 }
928 promise(const promise&) = delete;
929 promise& operator=(promise&& x) noexcept {
930 internal::promise_base_with_type<T>::operator=(std::move(x));
931 // If this is a self-move, _state is now nullptr and it is
932 // safe to call move_it.
933 move_it(std::move(x));
934 return *this;
935 }
936 void operator=(const promise&) = delete;
937
942 void set_to_current_exception() noexcept {
943 internal::promise_base::set_to_current_exception();
944 }
945
947 using internal::promise_base::waiting_task;
948
956
968 template <typename... A>
969 void set_value(A&&... a) noexcept {
970 internal::promise_base_with_type<T>::set_value(std::forward<A>(a)...);
971 }
972
977 void set_exception(std::exception_ptr&& ex) noexcept {
978 internal::promise_base::set_exception(std::move(ex));
979 }
980
981 void set_exception(const std::exception_ptr& ex) noexcept {
982 internal::promise_base::set_exception(ex);
983 }
984
989 template<typename Exception>
990 std::enable_if_t<!std::is_same_v<std::remove_reference_t<Exception>, std::exception_ptr>, void> set_exception(Exception&& e) noexcept {
991 internal::promise_base::set_exception(std::forward<Exception>(e));
992 }
993
994 using internal::promise_base_with_type<T>::set_urgent_state;
995
996 template <typename U>
997 friend class future;
998};
999
1001
1004
1005
1011template <typename... T> struct is_future : std::false_type {};
1012
1015template <typename... T> struct is_future<future<T...>> : std::true_type {};
1016
1018
1019
1023SEASTAR_MODULE_EXPORT
1024template <typename T>
1025struct futurize;
1026
1027template <typename T>
1028concept Future = is_future<T>::value;
1029
1030template <typename Func, typename... T>
1031concept CanInvoke = std::invocable<Func, T...>;
1032
1033// Deprecated alias
1034template <typename Func, typename... T>
1035concept CanApply = CanInvoke<Func, T...>;
1036
1037template <typename Func, typename... T>
1038concept CanApplyTuple
1039 = sizeof...(T) == 1
1040 && requires (Func func, std::tuple<T...> wrapped_val) {
1041 { std::apply(func, std::get<0>(std::move(wrapped_val))) };
1042 };
1043
1044// Deprecated, use std::is_invocable_r_v
1045template <typename Func, typename Return, typename... T>
1046concept InvokeReturns = requires (Func f, T... args) {
1047 { f(std::forward<T>(args)...) } -> std::same_as<Return>;
1048};
1049
1050// Deprecated alias
1051template <typename Func, typename Return, typename... T>
1052concept ApplyReturns = InvokeReturns<Func, Return, T...>;
1053
1054template <typename Func, typename... T>
1055concept InvokeReturnsAnyFuture = Future<std::invoke_result_t<Func, T...>>;
1056
1057// Deprecated alias
1058template <typename Func, typename... T>
1059concept ApplyReturnsAnyFuture = InvokeReturnsAnyFuture<Func, T...>;
1060
1062
1063// Converts a type to a future type, if it isn't already.
1064template <typename T>
1065using futurize_t = typename futurize<T>::type;
1066
1068
1069template<typename Func, typename... Args>
1070auto futurize_invoke(Func&& func, Args&&... args) noexcept;
1071
1072template<typename Func, typename... Args>
1073auto futurize_apply(Func&& func, std::tuple<Args...>&& args) noexcept;
1074
1077namespace internal {
1078class future_base {
1079protected:
1080 promise_base* _promise;
1081 future_base() noexcept : _promise(nullptr) {}
1082 future_base(promise_base* promise, future_state_base* state) noexcept : _promise(promise) {
1083 _promise->_future = this;
1084 _promise->_state = state;
1085 }
1086
1087 void move_it(future_base&& x, future_state_base* state) noexcept {
1088 _promise = x._promise;
1089 if (auto* p = _promise) {
1090 x.detach_promise();
1091 p->_future = this;
1092 p->_state = state;
1093 }
1094 }
1095
1096 future_base(future_base&& x, future_state_base* state) noexcept {
1097 move_it(std::move(x), state);
1098 }
1099
1100 void clear() noexcept {
1101 if (_promise) {
1102 detach_promise();
1103 }
1104 }
1105
1106 ~future_base() noexcept {
1107 clear();
1108 }
1109
1110 promise_base* detach_promise() noexcept {
1111 _promise->_state = nullptr;
1112 _promise->_future = nullptr;
1113 return std::exchange(_promise, nullptr);
1114 }
1115
1116 void schedule(task* tws, future_state_base* state) noexcept {
1117 promise_base* p = detach_promise();
1118 p->_state = state;
1119 p->set_task(tws);
1120 }
1121
1122 void do_wait() noexcept;
1123
1124 void set_coroutine(task& coroutine) noexcept;
1125
1126 friend class promise_base;
1127};
1128
1129template <typename Func, typename... T>
1130struct future_result {
1131 using type = std::invoke_result_t<Func, T...>;
1132 using future_type = futurize_t<type>;
1133 using func_type = future_type (T&&...);
1134};
1135
1136template <typename Func>
1137struct future_result<Func, void> {
1138 using type = std::invoke_result_t<Func>;
1139 using future_type = futurize_t<type>;
1140 using func_type = future_type ();
1141};
1142
1143template <typename Func, typename T>
1144using future_result_t = typename future_result<Func, T>::type;
1145
1146template <typename Func, typename T>
1147auto future_invoke(Func&& func, T&& v) {
1148 if constexpr (std::is_same_v<T, monostate>) {
1149 return std::invoke(std::forward<Func>(func));
1150 } else {
1151 return std::invoke(std::forward<Func>(func), std::forward<T>(v));
1152 }
1153}
1154
1155template <typename Func, typename... T>
1156struct result_of_apply {
1157 // no "type" member if not a function call signature or not a tuple
1158};
1159
1160template <typename Func, typename... T>
1161struct result_of_apply<Func, std::tuple<T...>> : std::invoke_result<Func, T...> {
1162 // Let std::invoke_result_t determine the result if the input is a tuple
1163};
1164
1165template <typename Func, typename... T>
1166using result_of_apply_t = typename result_of_apply<Func, T...>::type;
1167
1168}
1169
1170template <typename Promise, typename T>
1171task* continuation_base_with_promise<Promise, T>::waiting_task() noexcept {
1172 return _pr.waiting_task();
1173}
1174
1217SEASTAR_MODULE_EXPORT
1218template <typename T>
1219class [[nodiscard]] future : private internal::future_base {
1220 using future_state = seastar::future_state<internal::future_stored_type_t<T>>;
1221 future_state _state;
1222 static constexpr bool copy_noexcept = future_state::copy_noexcept;
1223
1224private:
1225 // This constructor creates a future that is not ready but has no
1226 // associated promise yet. The use case is to have a less flexible
1227 // but more efficient future/promise pair where we know that
1228 // promise::set_value cannot possibly be called without a matching
1229 // future and so that promise doesn't need to store a
1230 // future_state.
1232
1233 future(promise<T>* pr) noexcept : future_base(pr, &_state), _state(std::move(pr->_local_state)) { }
1234 template <typename... A>
1235 future(ready_future_marker m, A&&... a) noexcept : _state(m, std::forward<A>(a)...) { }
1237 future(future_state_base::nested_exception_marker m, future_state_base&& old) noexcept : _state(m, std::move(old)) {}
1238 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)) {}
1239 future(exception_future_marker m, std::exception_ptr&& ex) noexcept : _state(m, std::move(ex)) { }
1240 future(exception_future_marker m, future_state_base&& state) noexcept : _state(m, std::move(state)) { }
1241 [[gnu::always_inline]]
1242 explicit future(future_state&& state) noexcept
1243 : _state(std::move(state)) {
1244 }
1245 internal::promise_base_with_type<T> get_promise() noexcept {
1246 assert(!_promise);
1247 return internal::promise_base_with_type<T>(this);
1248 }
1249 internal::promise_base_with_type<T>* detach_promise() noexcept {
1250 return static_cast<internal::promise_base_with_type<T>*>(future_base::detach_promise());
1251 }
1252 void schedule(continuation_base<T>* tws) noexcept {
1253 future_base::schedule(tws, &tws->_state);
1254 }
1255 template <typename Pr, typename Func, typename Wrapper>
1256 void schedule(Pr&& pr, Func&& func, Wrapper&& wrapper) noexcept {
1257 // If this new throws a std::bad_alloc there is nothing that
1258 // can be done about it. The corresponding future is not ready
1259 // and we cannot break the chain. Since this function is
1260 // noexcept, it will call std::terminate if new throws.
1262 auto tws = new continuation<Pr, Func, Wrapper, T>(std::move(pr), std::move(func), std::move(wrapper));
1263 // In a debug build we schedule ready futures, but not in
1264 // other build modes.
1265#ifdef SEASTAR_DEBUG
1266 if (_state.available()) {
1267 tws->set_state(get_available_state_ref());
1268 ::seastar::schedule(tws);
1269 return;
1270 }
1271#endif
1272 schedule(tws);
1273 _state._u.st = future_state_base::state::invalid;
1274 }
1275
1276 [[gnu::always_inline]]
1277 future_state&& get_available_state_ref() noexcept {
1278 if (_promise) {
1279 detach_promise();
1280 }
1281 return std::move(_state);
1282 }
1283
1284 future<T> rethrow_with_nested(future_state_base&& n) noexcept {
1285 return future<T>(future_state_base::nested_exception_marker(), std::move(n), std::move(_state));
1286 }
1287
1288 future<T> rethrow_with_nested() noexcept {
1289 return future<T>(future_state_base::nested_exception_marker(), std::move(_state));
1290 }
1291
1292 template<typename... U>
1293 friend class shared_future;
1294public:
1296 using value_type = internal::future_stored_type_t<T>;
1297 using tuple_type = internal::future_tuple_type_t<value_type>;
1301 [[gnu::always_inline]]
1302 future(future&& x) noexcept : future_base(std::move(x), &_state), _state(std::move(x._state)) { }
1303 future(const future&) = delete;
1304 future& operator=(future&& x) noexcept {
1305 clear();
1306 move_it(std::move(x), &_state);
1307 _state = std::move(x._state);
1308 return *this;
1309 }
1310 void operator=(const future&) = delete;
1320 [[gnu::always_inline]]
1322 wait();
1323 return get_available_state_ref().take();
1324 }
1325
1326 [[gnu::always_inline]]
1327 std::exception_ptr get_exception() noexcept {
1328 return get_available_state_ref().get_exception();
1329 }
1330
1351 using get0_return_type = typename future_state::get0_return_type;
1352 [[deprecated("Use get() instead")]]
1353 get0_return_type get0() {
1354 return (get0_return_type)get();
1355 }
1356
1362 void wait() noexcept {
1363 if (_state.available()) {
1364 return;
1365 }
1366 do_wait();
1367 }
1368
1372 [[gnu::always_inline]]
1373 bool available() const noexcept {
1374 return _state.available();
1375 }
1376
1380 [[gnu::always_inline]]
1381 bool failed() const noexcept {
1382 return _state.failed();
1383 }
1384
1400 template <typename Func, typename Result = typename internal::future_result<Func, T>::future_type>
1401 requires std::invocable<Func, T>
1402 || (std::same_as<void, T> && std::invocable<Func>)
1403 Result
1404 then(Func&& func) noexcept {
1405#ifndef SEASTAR_TYPE_ERASE_MORE
1406 return then_impl(std::move(func));
1407#else
1408 using func_type = typename internal::future_result<Func, T>::func_type;
1410 {
1412 ncf = noncopyable_function<func_type>([func = std::forward<Func>(func)](auto&&... args) mutable {
1413 return futurize_invoke(func, std::forward<decltype(args)>(args)...);
1414 });
1415 }
1416 return then_impl(std::move(ncf));
1417#endif
1418 }
1419
1439 template <typename Func, typename Result = futurize_t<internal::result_of_apply_t<Func, T>>>
1440 requires ::seastar::CanApplyTuple<Func, T>
1441 Result
1442 then_unpack(Func&& func) noexcept {
1443 return then([func = std::forward<Func>(func)] (T&& tuple) mutable {
1444 // sizeof...(tuple) is required to be 1
1445 return std::apply(func, std::move(tuple));
1446 });
1447 }
1448
1449private:
1450
1451 // Keep this simple so that Named Return Value Optimization is used.
1452 template <typename Func, typename Result>
1453 Result then_impl_nrvo(Func&& func) noexcept {
1455 typename futurator::type fut(future_for_get_promise_marker{});
1456 using pr_type = decltype(fut.get_promise());
1457 schedule(fut.get_promise(), std::move(func), [](pr_type&& pr, Func& func, future_state&& state) {
1458 if (state.failed()) {
1459 pr.set_exception(static_cast<future_state_base&&>(std::move(state)));
1460 } else {
1461 futurator::satisfy_with_result_of(std::move(pr), [&func, &state] {
1462 // clang thinks that "state" is not used, below, for future<>.
1463 // Make it think it is used to avoid an unused-lambda-capture warning.
1464 (void)state;
1465 return internal::future_invoke(func, std::move(state).get_value());
1466 });
1467 }
1468 });
1469 return fut;
1470 }
1471
1472 template <typename Func, typename Result = futurize_t<internal::future_result_t<Func, T>>>
1473 Result
1474 then_impl(Func&& func) noexcept {
1475#ifndef SEASTAR_DEBUG
1476 using futurator = futurize<internal::future_result_t<Func, T>>;
1477 if (failed()) {
1478 return futurator::make_exception_future(static_cast<future_state_base&&>(get_available_state_ref()));
1479 } else if (available()) {
1480 return futurator::invoke(std::forward<Func>(func), get_available_state_ref().take_value());
1481 }
1482#endif
1483 return then_impl_nrvo<Func, Result>(std::forward<Func>(func));
1484 }
1485
1486public:
1502 template <std::invocable<future> Func, typename FuncResult = std::invoke_result_t<Func, future>>
1503 futurize_t<FuncResult>
1504 then_wrapped(Func&& func) & noexcept {
1505 return then_wrapped_maybe_erase<false, FuncResult>(std::forward<Func>(func));
1506 }
1507
1508 template <std::invocable<future&&> Func, typename FuncResult = std::invoke_result_t<Func, future&&>>
1509 futurize_t<FuncResult>
1510 then_wrapped(Func&& func) && noexcept {
1511 return then_wrapped_maybe_erase<true, FuncResult>(std::forward<Func>(func));
1512 }
1513
1514private:
1515
1516 template <bool AsSelf, typename FuncResult, typename Func>
1517 futurize_t<FuncResult>
1518 then_wrapped_maybe_erase(Func&& func) noexcept {
1519#ifndef SEASTAR_TYPE_ERASE_MORE
1520 return then_wrapped_common<AsSelf, FuncResult>(std::forward<Func>(func));
1521#else
1522 using futurator = futurize<FuncResult>;
1523 using WrapFuncResult = typename futurator::type;
1524 noncopyable_function<WrapFuncResult (future&&)> ncf;
1525 {
1526 memory::scoped_critical_alloc_section _;
1527 ncf = noncopyable_function<WrapFuncResult(future &&)>([func = std::forward<Func>(func)](future&& f) mutable {
1528 return futurator::invoke(func, std::move(f));
1529 });
1530 }
1531 return then_wrapped_common<AsSelf, WrapFuncResult>(std::move(ncf));
1532#endif
1533 }
1534
1535 // Keep this simple so that Named Return Value Optimization is used.
1536 template <typename FuncResult, typename Func>
1537 futurize_t<FuncResult>
1538 then_wrapped_nrvo(Func&& func) noexcept {
1539 using futurator = futurize<FuncResult>;
1540 typename futurator::type fut(future_for_get_promise_marker{});
1541 using pr_type = decltype(fut.get_promise());
1542 schedule(fut.get_promise(), std::move(func), [](pr_type&& pr, Func& func, future_state&& state) {
1543 futurator::satisfy_with_result_of(std::move(pr), [&func, &state] {
1544 return func(future(std::move(state)));
1545 });
1546 });
1547 return fut;
1548 }
1549
1550
1551 template <bool AsSelf, typename FuncResult, typename Func>
1552 futurize_t<FuncResult>
1553 then_wrapped_common(Func&& func) noexcept {
1554#ifndef SEASTAR_DEBUG
1555 using futurator = futurize<FuncResult>;
1556 if (available()) {
1557 if constexpr (AsSelf) {
1558 if (_promise) {
1559 detach_promise();
1560 }
1561 return futurator::invoke(std::forward<Func>(func), std::move(*this));
1562 } else {
1563 return futurator::invoke(std::forward<Func>(func), future(get_available_state_ref()));
1564 }
1565 }
1566#endif
1567 return then_wrapped_nrvo<FuncResult, Func>(std::forward<Func>(func));
1568 }
1569
1570 void forward_to(internal::promise_base_with_type<T>&& pr) noexcept {
1571 if (_state.available()) {
1572 pr.set_urgent_state(std::move(_state));
1573 } else {
1574 *detach_promise() = std::move(pr);
1575 }
1576 }
1577
1578public:
1589 void forward_to(promise<T>&& pr) noexcept {
1590 if (_state.available()) {
1591 pr.set_urgent_state(std::move(_state));
1592 } else if (&pr._local_state != pr._state) {
1593 // The only case when _state points to _local_state is
1594 // when get_future was never called. Given that pr will
1595 // soon be destroyed, we know get_future will never be
1596 // called and we can just ignore this request.
1597 *detach_promise() = std::move(pr);
1598 }
1599 }
1600
1601
1602
1618 template <std::invocable Func>
1619 future<T> finally(Func&& func) noexcept {
1620 return then_wrapped(finally_body<Func, is_future<std::invoke_result_t<Func>>::value>(std::forward<Func>(func)));
1621 }
1622
1623
1624 template <typename Func, bool FuncReturnsFuture>
1626
1627 template <typename Func>
1628 struct finally_body<Func, true> {
1629 Func _func;
1630
1631 finally_body(Func&& func) noexcept : _func(std::forward<Func>(func))
1632 { }
1633
1634 future<T> operator()(future<T>&& result) noexcept {
1635 return futurize_invoke(_func).then_wrapped([result = std::move(result)](auto&& f_res) mutable {
1636 if (!f_res.failed()) {
1637 return std::move(result);
1638 } else {
1639 return result.rethrow_with_nested(std::move(f_res._state));
1640 }
1641 });
1642 }
1643 };
1644
1645 template <typename Func>
1646 struct finally_body<Func, false> {
1647 Func _func;
1648
1649 finally_body(Func&& func) noexcept : _func(std::forward<Func>(func))
1650 { }
1651
1652 future<T> operator()(future<T>&& result) noexcept {
1653 try {
1654 _func();
1655 return std::move(result);
1656 } catch (...) {
1657 return result.rethrow_with_nested();
1658 }
1659 };
1660 };
1661
1667 return then_wrapped([] (auto&& f) {
1668 try {
1669 f.get();
1670 } catch (...) {
1671 engine_exit(std::current_exception());
1672 }
1673 });
1674 }
1675
1681 // We need the generic variadic lambda, below, because then() behaves differently
1682 // when value_type is when_all_succeed_tuple
1683 return then([] (auto&&...) {});
1684 }
1685
1699 template <typename Func>
1700 requires std::is_invocable_r_v<future<T> ,Func, std::exception_ptr>
1701 || (std::tuple_size_v<tuple_type> == 0 && std::is_invocable_r_v<void, Func, std::exception_ptr>)
1702 || (std::tuple_size_v<tuple_type> == 1 && std::is_invocable_r_v<T, Func, std::exception_ptr>)
1703 || (std::tuple_size_v<tuple_type> > 1 && std::is_invocable_r_v<tuple_type ,Func, std::exception_ptr>)
1704 future<T> handle_exception(Func&& func) noexcept {
1705 return then_wrapped([func = std::forward<Func>(func)]
1706 (auto&& fut) mutable -> future<T> {
1707 if (!fut.failed()) {
1708 return make_ready_future<T>(fut.get());
1709 } else {
1710 return futurize_invoke(func, fut.get_exception());
1711 }
1712 });
1713 }
1714
1725 template <typename Func>
1726 future<T> handle_exception_type(Func&& func) noexcept {
1727 using trait = function_traits<Func>;
1728 static_assert(trait::arity == 1, "func can take only one parameter");
1729 using ex_type = typename trait::template arg<0>::type;
1730 return then_wrapped([func = std::forward<Func>(func)]
1731 (auto&& fut) mutable -> future<T> {
1732 try {
1733 return make_ready_future<T>(fut.get());
1734 } catch(ex_type& ex) {
1735 return futurize_invoke(func, ex);
1736 }
1737 });
1738 }
1739
1745 void ignore_ready_future() noexcept {
1746 _state.ignore();
1747 }
1748
1749 using future_base::set_coroutine;
1750
1751private:
1752 void set_task(task& t) noexcept {
1753 assert(_promise);
1754 _promise->set_task(&t);
1755 }
1756
1757 void set_callback(continuation_base<T>* callback) noexcept {
1758 if (_state.available()) {
1759 callback->set_state(get_available_state_ref());
1760 ::seastar::schedule(callback);
1761 } else {
1762 assert(_promise);
1763 schedule(callback);
1764 }
1765
1766 }
1767
1769 template <typename U>
1770 friend class future;
1771 template <typename U>
1772 friend class promise;
1773 template <typename U>
1774 friend struct futurize;
1775 template <typename U>
1776 friend class internal::promise_base_with_type;
1777 template <typename U, typename... A>
1778 friend future<U> make_ready_future(A&&... value) noexcept;
1779 template <typename U>
1780 friend future<U> make_exception_future(std::exception_ptr&& ex) noexcept;
1781 template <typename U, typename Exception>
1782 friend future<U> make_exception_future(Exception&& ex) noexcept;
1783 template <typename U>
1784 friend future<U> internal::make_exception_future(future_state_base&& state) noexcept;
1785 template <typename U>
1786 friend future<U> current_exception_as_future() noexcept;
1787 template <typename U>
1788 friend void internal::set_callback(future<U>&&, continuation_base<U>*) noexcept;
1790};
1791
1792
1793namespace internal {
1794template <typename T>
1795struct futurize_base {
1797 using type = future<T>;
1799 using promise_type = promise<T>;
1800 using promise_base_with_type = internal::promise_base_with_type<T>;
1801
1803 static inline type convert(T&& value) { return make_ready_future<T>(std::move(value)); }
1804 static inline type convert(type&& value) { return std::move(value); }
1805
1807 template <typename Arg>
1808 static inline type make_exception_future(Arg&& arg) noexcept;
1809};
1810
1811template <>
1812struct futurize_base<void> {
1813 using type = future<>;
1814 using promise_type = promise<>;
1815 using promise_base_with_type = internal::promise_base_with_type<>;
1816
1817 static inline type convert(type&& value) {
1818 return std::move(value);
1819 }
1820 template <typename Arg>
1821 static inline type make_exception_future(Arg&& arg) noexcept;
1822};
1823
1824template <typename T>
1825struct futurize_base<future<T>> : public futurize_base<T> {};
1826
1827template <>
1828struct futurize_base<future<>> : public futurize_base<void> {};
1829}
1830
1831template <typename T>
1832struct futurize : public internal::futurize_base<T> {
1833 using base = internal::futurize_base<T>;
1834 using type = typename base::type;
1835 using promise_type = typename base::promise_type;
1836 using promise_base_with_type = typename base::promise_base_with_type;
1839 using tuple_type = typename type::tuple_type;
1840 using base::convert;
1841 using base::make_exception_future;
1842
1845 template<typename Func, typename... FuncArgs>
1846 static inline type apply(Func&& func, std::tuple<FuncArgs...>&& args) noexcept;
1847
1850 template<typename Func, typename... FuncArgs>
1851 static inline type invoke(Func&& func, FuncArgs&&... args) noexcept;
1852
1853 template<typename Func>
1854 static inline type invoke(Func&& func, internal::monostate) noexcept {
1855 return invoke(std::forward<Func>(func));
1856 }
1857
1859 template<typename Func, typename... FuncArgs>
1860 [[deprecated("Use invoke for varargs")]]
1861 static inline type apply(Func&& func, FuncArgs&&... args) noexcept {
1862 return invoke(std::forward<Func>(func), std::forward<FuncArgs>(args)...);
1863 }
1864
1865 static type current_exception_as_future() noexcept {
1867 }
1868
1870 static type from_tuple(tuple_type&& value) {
1871 return type(ready_future_marker(), std::move(value));
1872 }
1874 static type from_tuple(const tuple_type& value) {
1875 return type(ready_future_marker(), value);
1876 }
1877
1879 static type from_tuple(value_type&& value) {
1880 return type(ready_future_marker(), std::move(value));
1881 }
1883 static type from_tuple(const value_type& value) {
1884 return type(ready_future_marker(), value);
1885 }
1886private:
1890 template<std::invocable Func>
1891 static void satisfy_with_result_of(promise_base_with_type&&, Func&& func);
1892
1893 template <typename U>
1894 friend class future;
1895};
1896
1897inline internal::promise_base::promise_base(future_base* future, future_state_base* state) noexcept
1898 : _future(future), _state(state) {
1899 _future->_promise = this;
1900}
1901
1902template <typename T>
1903inline
1904future<T>
1906 assert(!this->_future && this->_state && !this->_task);
1907 return future<T>(this);
1908}
1909
1910template <typename T>
1911inline
1912void promise<T>::move_it(promise&& x) noexcept {
1913 if (this->_state == &x._local_state) {
1914 this->_state = &_local_state;
1915 new (&_local_state) future_state(std::move(x._local_state));
1916 }
1917}
1918
1919SEASTAR_MODULE_EXPORT_BEGIN
1920template <typename T, typename... A>
1921inline
1922future<T> make_ready_future(A&&... value) noexcept {
1923 return future<T>(ready_future_marker(), std::forward<A>(value)...);
1924}
1925
1926template <typename T>
1927inline
1928future<T> make_exception_future(std::exception_ptr&& ex) noexcept {
1929 return future<T>(exception_future_marker(), std::move(ex));
1930}
1931SEASTAR_MODULE_EXPORT_END
1932
1933template <typename T>
1934inline
1935future<T> internal::make_exception_future(future_state_base&& state) noexcept {
1936 return future<T>(exception_future_marker(), std::move(state));
1937}
1938
1939SEASTAR_MODULE_EXPORT_BEGIN
1940template <typename T>
1943}
1944
1945void log_exception_trace() noexcept;
1946
1953template <typename T, typename Exception>
1954inline
1955future<T> make_exception_future(Exception&& ex) noexcept {
1956 log_exception_trace();
1957 return make_exception_future<T>(std::make_exception_ptr(std::forward<Exception>(ex)));
1958}
1959
1960template <typename T, typename Exception>
1961future<T> make_exception_future_with_backtrace(Exception&& ex) noexcept {
1962 return make_exception_future<T>(make_backtraced_exception_ptr<Exception>(std::forward<Exception>(ex)));
1963}
1964SEASTAR_MODULE_EXPORT_END
1965
1967
1969
1970template<typename T>
1971template<typename Func, typename... FuncArgs>
1972typename futurize<T>::type futurize<T>::apply(Func&& func, std::tuple<FuncArgs...>&& args) noexcept {
1973 try {
1974 using ret_t = decltype(std::apply(std::forward<Func>(func), std::move(args)));
1975 if constexpr (std::is_void_v<ret_t>) {
1976 std::apply(std::forward<Func>(func), std::move(args));
1977 return make_ready_future<>();
1978 } else if constexpr (is_future<ret_t>::value){
1979 return std::apply(std::forward<Func>(func), std::move(args));
1980 } else {
1981 return convert(std::apply(std::forward<Func>(func), std::move(args)));
1982 }
1983 } catch (...) {
1985 }
1986}
1987
1988template<typename T>
1989template<std::invocable Func>
1990void futurize<T>::satisfy_with_result_of(promise_base_with_type&& pr, Func&& func) {
1991 using ret_t = decltype(func());
1992 if constexpr (std::is_void_v<ret_t>) {
1993 func();
1994 pr.set_value();
1995 } else if constexpr (is_future<ret_t>::value) {
1996 func().forward_to(std::move(pr));
1997 } else {
1998 pr.set_value(func());
1999 }
2000}
2001
2002template<typename T>
2003template<typename Func, typename... FuncArgs>
2004typename futurize<T>::type futurize<T>::invoke(Func&& func, FuncArgs&&... args) noexcept {
2005 try {
2006 using ret_t = decltype(func(std::forward<FuncArgs>(args)...));
2007 if constexpr (std::is_void_v<ret_t>) {
2008 func(std::forward<FuncArgs>(args)...);
2009 return make_ready_future<>();
2010 } else if constexpr (is_future<ret_t>::value) {
2011 return func(std::forward<FuncArgs>(args)...);
2012 } else {
2013 return convert(func(std::forward<FuncArgs>(args)...));
2014 }
2015 } catch (...) {
2017 }
2018}
2019
2020template <typename T>
2021template <typename Arg>
2022inline
2023future<T>
2024internal::futurize_base<T>::make_exception_future(Arg&& arg) noexcept {
2025 using ::seastar::make_exception_future;
2026 using ::seastar::internal::make_exception_future;
2027 return make_exception_future<T>(std::forward<Arg>(arg));
2028}
2029
2030template <typename Arg>
2031inline
2032future<>
2033internal::futurize_base<void>::make_exception_future(Arg&& arg) noexcept {
2034 using ::seastar::make_exception_future;
2035 using ::seastar::internal::make_exception_future;
2036 return make_exception_future<>(std::forward<Arg>(arg));
2037}
2038
2039template<typename Func, typename... Args>
2040auto futurize_invoke(Func&& func, Args&&... args) noexcept {
2041 using futurator = futurize<std::invoke_result_t<Func, Args&&...>>;
2042 return futurator::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
2043}
2044
2045template<typename Func, typename... Args>
2046[[deprecated("Use futurize_invoke for varargs")]]
2047auto futurize_apply(Func&& func, Args&&... args) noexcept {
2048 return futurize_invoke(std::forward<Func>(func), std::forward<Args>(args)...);
2049}
2050
2051template<typename Func, typename... Args>
2052auto futurize_apply(Func&& func, std::tuple<Args...>&& args) noexcept {
2053 using futurator = futurize<std::invoke_result_t<Func, Args&&...>>;
2054 return futurator::apply(std::forward<Func>(func), std::move(args));
2055}
2056
2057namespace internal {
2058
2059template <typename T>
2060inline
2061void set_callback(future<T>&& fut, continuation_base<T>* callback) noexcept {
2062 return std::move(fut).set_callback(callback);
2063}
2064
2065}
2066
2067
2069
2070}
A representation of a possibly not-yet-computed value.
Definition: future.hh:1219
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:1504
future< T > handle_exception_type(Func &&func) noexcept
Handle the exception of a certain type carried by this future.
Definition: future.hh:1726
void wait() noexcept
Definition: future.hh:1362
internal::future_stored_type_t< T > value_type
The data type carried by the future.
Definition: future.hh:1296
future< T > handle_exception(Func &&func) noexcept
Handle the exception carried by this future.
Definition: future.hh:1704
Result then(Func &&func) noexcept
Schedule a block of code to run when the future is ready.
Definition: future.hh:1404
value_type && get()
gets the value returned by the computation
Definition: future.hh:1321
bool failed() const noexcept
Checks whether the future has failed.
Definition: future.hh:1381
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:1442
bool available() const noexcept
Checks whether the future is available.
Definition: future.hh:1373
typename future_state::get0_return_type get0_return_type
Definition: future.hh:1351
void forward_to(promise< T > &&pr) noexcept
Satisfy some promise object with this future as a result.
Definition: future.hh:1589
future(future &&x) noexcept
Moves the future into a new object.
Definition: future.hh:1302
future discard_result() noexcept
Discards the value carried by this future.
Definition: future.hh:1680
future or_terminate() noexcept
Terminate the program if this future fails.
Definition: future.hh:1666
void ignore_ready_future() noexcept
Ignore any result hold by this future.
Definition: future.hh:1745
Definition: future.hh:1625
promise - allows a future value to be made available at a later time.
Definition: future.hh:913
void set_to_current_exception() noexcept
Definition: future.hh:942
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:990
void set_value(A &&... a) noexcept
Sets the promises value.
Definition: future.hh:969
void set_exception(std::exception_ptr &&ex) noexcept
Marks the promise as failed.
Definition: future.hh:977
promise() noexcept
Constructs an empty promise.
Definition: future.hh:921
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:1922
future< T > get_future() noexcept
Gets the promise's associated future.
Definition: future.hh:1905
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:1928
future< T > current_exception_as_future() noexcept
Returns std::current_exception() wrapped in a future.
Definition: future.hh:1941
void move_it(promise &&x) noexcept
Moves a promise object.
Definition: future.hh:1912
Definition: future.hh:545
Definition: future.hh:544
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:398
friend future< U > current_exception_as_future() noexcept
Returns std::current_exception() wrapped in a future.
Definition: future.hh:1941
Converts a type to a future type, if it isn't already.
Definition: future.hh:1832
static type apply(Func &&func, FuncArgs &&... args) noexcept
Deprecated alias of invoke.
Definition: future.hh:1861
static type from_tuple(tuple_type &&value)
Convert the tuple representation into a future.
Definition: future.hh:1870
static type from_tuple(value_type &&value)
Convert the tuple representation into a future.
Definition: future.hh:1879
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:1883
static type from_tuple(const tuple_type &value)
Convert the tuple representation into a future.
Definition: future.hh:1874
typename type::value_type value_type
The value tuple type associated with type.
Definition: future.hh:1838
static type invoke(Func &&func, FuncArgs &&... args) noexcept
Check whether a type is a future.
Definition: future.hh:1011
Definition: future.hh:48
Definition: future.hh:414