Skip to content

Commit 4a96018

Browse files
committed
coroutine: allocate coroutine frame in a critical section
Like continuations, coroutines are glue that cannot be allowed to fail. For example, if cleanup coroutine fails to allocate and returns an exception future, cleanup will not be done and the system will enter an undefined state. Better to crash. This conflicts with test code that tries to inject memory failures and see how they are handled (file_io_test.cc handle_bad_alloc_test). The coroutine will throw std::bad_alloc (since we don't define get_return_object_on_allocation_failure()), and since it's declared noexcept, will call std::terminate. To avoid all this, follow future::schedule() and prevent memory allocation failure injection from interfering with coroutine frame allocation. In this regard a coroutine frame is just like a continuation. This is done by injecting class-specific operator new and operator delete. Sized deallocation is also defined if supported by the compiler.
1 parent eb05cf6 commit 4a96018

File tree

1 file changed

+19
-2
lines changed

1 file changed

+19
-2
lines changed

include/seastar/core/coroutine.hh

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
#ifndef SEASTAR_MODULE
3333
#include <coroutine>
34+
#include <new>
3435
#endif
3536

3637
namespace seastar {
@@ -51,10 +52,26 @@ execute_involving_handle_destruction_in_await_suspend(std::invocable<> auto&& fu
5152
}
5253

5354

55+
class coroutine_allocators {
56+
public:
57+
static void* operator new(size_t size) {
58+
memory::scoped_critical_alloc_section _;
59+
return ::operator new(size);
60+
}
61+
static void operator delete(void* ptr) noexcept {
62+
::operator delete(ptr);
63+
}
64+
#ifdef __cpp_sized_deallocation
65+
static void operator delete(void* ptr, std::size_t sz) noexcept {
66+
::operator delete(ptr, sz);
67+
}
68+
#endif
69+
};
70+
5471
template <typename T = void>
5572
class coroutine_traits_base {
5673
public:
57-
class promise_type final : public seastar::task {
74+
class promise_type final : public seastar::task, public coroutine_allocators {
5875
seastar::promise<T> _promise;
5976
public:
6077
promise_type() = default;
@@ -106,7 +123,7 @@ public:
106123
template <>
107124
class coroutine_traits_base<> {
108125
public:
109-
class promise_type final : public seastar::task {
126+
class promise_type final : public seastar::task, public coroutine_allocators {
110127
seastar::promise<> _promise;
111128
public:
112129
promise_type() = default;

0 commit comments

Comments
 (0)