Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ target_sources(async_context PUBLIC
FILES
modules/async_context.cppm
)
target_compile_options(async_context PRIVATE
-g
-Werror
-Wno-unused-command-line-argument
-Wall
-Wextra
-Wshadow
-fexceptions
-fno-rtti)

install(
TARGETS async_context
Expand Down Expand Up @@ -73,7 +82,15 @@ else()
)

target_compile_features(async_unit_test PUBLIC cxx_std_23)
target_compile_options(async_unit_test PRIVATE -g)
target_compile_options(async_unit_test PRIVATE
-g
-Werror
-Wno-unused-command-line-argument
-Wall
-Wextra
-Wshadow
-fexceptions
-fno-rtti)
target_link_libraries(async_unit_test PRIVATE async_context Boost::ut)

add_custom_target(run_tests ALL DEPENDS async_unit_test COMMAND async_unit_test)
Expand Down
2 changes: 1 addition & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def build_requirements(self):
self.test_requires("boost-ext-ut/2.3.1")

def requirements(self):
self.requires("strong_ptr/0.0.2")
self.requires("strong_ptr/0.1.2")

def layout(self):
cmake_layout(self)
Expand Down
57 changes: 42 additions & 15 deletions modules/async_context.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -147,34 +147,53 @@ public:
return do_schedule(p_context, p_block_state, p_block_info);
}

/**
* @brief Get allocator from scheduler
*
* The memory_resource returned be owned or embedded within the scheduler. The
* memory_resource and its backing memory must live as long as the scheduler.
* The returned reference MUST NOT be bound to a nullptr.
*
* @return std::pmr::memory_resource& - the memory resource to be used to
* allocate memory for async::context stack memory. The memory_resource must
* be owned or embedded within the scheduler.
*/
std::pmr::memory_resource& get_allocator() noexcept
{
return do_get_allocator();
}

private:
virtual void do_schedule(
context& p_context,
blocked_by p_block_state,
std::variant<sleep_duration, context*> p_block_info) = 0;

virtual std::pmr::memory_resource& do_get_allocator() noexcept = 0;
};

export class context
{
public:
static auto constexpr default_timeout = sleep_duration(0);

// TODO(#18): Replace `mem::strong_ptr<std::span<byte>>` stack memory type
// with something thats easier and safer to work with.
/**
* @brief Construct a new context object
*
* @param p_scheduler - a pointer to a transition handler that
* handles transitions in blocked_by state.
* @param p_stack_memory - span to a block of memory reserved for this context
* to be used as stack memory for coroutine persistent memory. This buffer
* must outlive the lifetime of this object.
* @param p_stack_size - Number of bytes to allocate for the context's stack
* memory.
*/
context(mem::strong_ptr<scheduler> const& p_scheduler,
mem::strong_ptr<std::span<byte>> const& p_stack_memory)
context(mem::strong_ptr<scheduler> const& p_scheduler, usize p_stack_size)
: m_scheduler(p_scheduler)
, m_stack(p_stack_memory)
{
using poly_allocator = std::pmr::polymorphic_allocator<byte>;
auto allocator = poly_allocator(&p_scheduler->get_allocator());

// Allocate memory for stack and assign to m_stack
m_stack = { allocator.allocate_object<byte>(p_stack_size), p_stack_size };
}

void unblock()
Expand Down Expand Up @@ -227,7 +246,7 @@ public:

constexpr auto capacity()
{
return m_stack->size();
return m_stack.size();
}

constexpr auto memory_remaining()
Expand Down Expand Up @@ -258,11 +277,11 @@ public:
[[nodiscard]] constexpr void* allocate(std::size_t p_bytes)
{
auto const new_stack_index = m_stack_index + p_bytes;
if (new_stack_index > m_stack->size()) [[unlikely]] {
if (new_stack_index > m_stack.size()) [[unlikely]] {
throw bad_coroutine_alloc(this);
}
m_state = p_bytes;
auto* const stack_address = &(*m_stack)[m_stack_index];
auto* const stack_address = &m_stack[m_stack_index];
m_stack_index = new_stack_index;
return stack_address;
}
Expand All @@ -277,15 +296,23 @@ public:
m_state = p_exception;
}

~context()
{
using poly_allocator = std::pmr::polymorphic_allocator<byte>;
auto allocator = poly_allocator(&m_scheduler->get_allocator());
allocator.deallocate_object<byte>(m_stack.data(), m_stack.size());
};

private:
friend class promise_base;
using context_state = std::variant<usize, blocked_by, std::exception_ptr>;

// Should stay within a standard cache-line of 64 bytes (8 words)
std::coroutine_handle<> m_active_handle = std::noop_coroutine(); // word 1
mem::strong_ptr<scheduler> m_scheduler; // word 2-3
mem::strong_ptr<std::span<byte>> m_stack; // word 4-5
usize m_stack_index = 0; // word 6
std::variant<usize, blocked_by, std::exception_ptr> m_state; // word 7-8
mem::strong_ptr<scheduler> m_scheduler; // word 1-2
std::coroutine_handle<> m_active_handle = std::noop_coroutine(); // word 3
std::span<byte> m_stack{}; // word 4-5
usize m_stack_index{ 0uz }; // word 6
context_state m_state{ 0uz }; // word 7-8
};

static_assert(sizeof(context) <=
Expand Down
9 changes: 9 additions & 0 deletions test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ target_sources(${PROJECT_NAME} PUBLIC
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23)
target_link_libraries(${PROJECT_NAME} PRIVATE async_context)

target_compile_options(${PROJECT_NAME} PRIVATE
-g
-Werror
-Wno-unused-command-line-argument
-Wall
-Wextra
-Wshadow
-fexceptions
-fno-rtti)
# Always run this custom target by making it depend on ALL
add_custom_target(copy_compile_commands ALL
COMMAND ${CMAKE_COMMAND} -E copy_if_different
Expand Down
21 changes: 13 additions & 8 deletions test_package/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,24 @@

#include <cassert>

#include <array>
#include <chrono>
#include <coroutine>
#include <memory_resource>
#include <print>
#include <span>
#include <variant>

import async_context;

struct my_scheduler : public async::scheduler
struct my_scheduler
: public async::scheduler
, mem::enable_strong_from_this<my_scheduler>
{
int sleep_count = 0;

my_scheduler(mem::strong_ptr_only_token)
{
}

private:
void do_schedule(
[[maybe_unused]] async::context& p_context,
Expand All @@ -39,6 +43,11 @@ struct my_scheduler : public async::scheduler
sleep_count++;
}
}

std::pmr::memory_resource& do_get_allocator() noexcept override
{
return *strong_from_this().get_allocator();
}
};

async::future<void> coro_double_delay(async::context&)
Expand All @@ -56,11 +65,7 @@ int main()
{
auto scheduler =
mem::make_strong_ptr<my_scheduler>(std::pmr::new_delete_resource());
auto buffer = mem::make_strong_ptr<std::array<async::u8, 1024>>(
std::pmr::new_delete_resource());
auto buffer_span = mem::make_strong_ptr<std::span<async::u8>>(
std::pmr::new_delete_resource(), *buffer);
async::context my_context(scheduler, buffer_span);
async::context my_context(scheduler, 1024);

auto future_delay = coro_double_delay(my_context);

Expand Down
19 changes: 13 additions & 6 deletions tests/async.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,16 @@ boost::ut::suite<"async::context"> async_context_suite = []() {
using namespace boost::ut;

"<TBD>"_test = []() {
struct my_scheduler : public async::scheduler
struct my_scheduler
: public async::scheduler
, mem::enable_strong_from_this<my_scheduler>
{
int sleep_count = 0;

my_scheduler(mem::strong_ptr_only_token)
{
}

private:
void do_schedule(
[[maybe_unused]] context& p_context,
Expand All @@ -59,15 +65,16 @@ boost::ut::suite<"async::context"> async_context_suite = []() {
std::println("Sleep count = {}!", sleep_count);
}
}

std::pmr::memory_resource& do_get_allocator() noexcept override
{
return *strong_from_this().get_allocator();
}
};
// Setup
auto scheduler =
mem::make_strong_ptr<my_scheduler>(std::pmr::new_delete_resource());
auto buffer = mem::make_strong_ptr<std::array<async::u8, 1024>>(
std::pmr::new_delete_resource());
auto buffer_span = mem::make_strong_ptr<std::span<async::u8>>(
std::pmr::new_delete_resource(), *buffer);
async::context my_context(scheduler, buffer_span);
async::context my_context(scheduler, 1024);

// Exercise
auto future_print = coro_print(my_context);
Expand Down