Skip to content

Commit d91b2db

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 c4b01ba commit d91b2db

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
@@ -30,16 +30,33 @@
3030

3131
#ifndef SEASTAR_MODULE
3232
#include <coroutine>
33+
#include <new>
3334
#endif
3435

3536
namespace seastar {
3637

3738
namespace internal {
3839

40+
class coroutine_allocators {
41+
public:
42+
static void* operator new(size_t size) {
43+
memory::scoped_critical_alloc_section _;
44+
return ::operator new(size);
45+
}
46+
static void operator delete(void* ptr) noexcept {
47+
::operator delete(ptr);
48+
}
49+
#ifdef __cpp_sized_deallocation
50+
static void operator delete(void* ptr, std::size_t sz) noexcept {
51+
::operator delete(ptr, sz);
52+
}
53+
#endif
54+
};
55+
3956
template <typename T = void>
4057
class coroutine_traits_base {
4158
public:
42-
class promise_type final : public seastar::task {
59+
class promise_type final : public seastar::task, public coroutine_allocators {
4360
seastar::promise<T> _promise;
4461
public:
4562
promise_type() = default;
@@ -91,7 +108,7 @@ public:
91108
template <>
92109
class coroutine_traits_base<> {
93110
public:
94-
class promise_type final : public seastar::task {
111+
class promise_type final : public seastar::task, public coroutine_allocators {
95112
seastar::promise<> _promise;
96113
public:
97114
promise_type() = default;

0 commit comments

Comments
 (0)