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