Skip to content

Commit

Permalink
added docs for fiber support.
Browse files Browse the repository at this point in the history
  • Loading branch information
klemens-morgenstern committed Mar 25, 2024
1 parent d07fa3f commit 6d857ac
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 0 deletions.
6 changes: 6 additions & 0 deletions doc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ include::reference/error.adoc[]
include::reference/config.adoc[]
include::reference/leaf.adoc[]

include::reference/experimental/context.adoc[]
include::reference/experimental/fiber.adoc[]
include::reference/experimental/continuation.adoc[]



= In-Depth

include::background/custom_executors.adoc[]
Expand Down
69 changes: 69 additions & 0 deletions doc/reference/experimental/context.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
[#context]
== cobalt/experimental/context.hpp

WARNING: This is (most likely) undefined behaviour, since the violates a precondition in the standard. A paper to address this can be found here (https://isocpp.org/files/papers/P3203R0.html).

This header provides `experimental` support for using `boost.fiber` based stackful coroutines
as if they were C++20 coroutines. That is, they can use `awaitables` by being able to be put into a `coroutine_handle`.
Likewise the implementation uses a C++20 coroutine promise and runs is as if it was a C++20 coroutine.

[source,cpp]
----
//
void delay(experimental::context<promise<void>> h, std::chrono::milliseconds ms)
{
asio::steady_timer tim{co_await cobalt::this_coro::executor, ms};
h.await(tim.async_wait(cobalt::use_op)); // instead of co_await.
}
cobalt::main co_main(int argc, char *argv[])
{
cobalt::promise<void> dl = cobalt::experimental::make_context(&delay, 50);
co_await dl;
co_return 0;
}
----

=== Reference

[source,cpp]
----
// The internal coroutine context.
/// Args are the function arguments after the handle.
template<typename Return, typename ... Args>
struct context
{
// Get a handle to the promise
promise_type & promise();
const promise_type & promise() const;
// Convert it to any context if the underlying promise is the same
template<typename Return_, typename ... Args_>
constexpr operator context<Return_, Args_...>() const;
// Await something. Uses await_transform automatically.
template<typename Awaitable>
auto await(Awaitable && aw);
// Yield a value, if supported by the promise.
template<typename Yield>
auto yield(Yield && value);
};
// Create a fiber with a custom stack allocator (see boost.fiber for details) and explicit result (e.g. `promise<void>`)
template<typename Return, typename ... Args, std::invocable<context<Return, Args...>, Args...> Func, typename StackAlloc>
auto make_context(Func && func, std::allocator_arg_t, StackAlloc && salloc, Args && ... args);
// Create a fiber with the default allocator and explicit result (e.g. `promise<void>`)
template<typename Return, typename ... Args, std::invocable<context<Return, Args...>, Args...> Func>
auto make_context(Func && func, Args && ... args);
// Create a fiber with a custom stack allocator and implicit result (deduced from the first argument to func).
template<typename ... Args, typename Func, typename StackAlloc>
auto make_context(Func && func, std::allocator_arg_t, StackAlloc && salloc, Args && ... args);
// Create a fiber with the default stack allocator and implicit result (deduced from the first argument to func).
template<typename ... Args, typename Func>
auto make_context(Func && func, Args && ... args);
----

63 changes: 63 additions & 0 deletions doc/reference/experimental/continuation.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
[#continuation]
== cobalt/experimental/continuation.hpp

WARNING: This is clearly undefined behaviour, since it does an explicit specialization of `std::coroutine_handle`. A paper to address this can be found here (https://isocpp.org/files/papers/P3203R0.html).

This header provides low level support for creating a `std::coroutine_handle` from within a `boost::context::continuation`.


[source,cpp]
----
template<cobalt::awaitable_type Aw>
auto continuation_await(boost::context::continuation && f, Aw && aw)
{
if (!aw.await_ready())
{
boost::cobalt::experimental::continuation_frame ff; // This must be on the continuation stack
f = std::move(f).resume_with(
[&](boost::context::continuation && f_) -> boost::context::continuation
{
ff.continuation() = std::move(f_);
std::coroutine_handle<boost::context::continuation> h(ff);
static_assert(std::is_void_v<decltype(aw.await_suspend(h)>,
"This example only supports awaitables return `void` from await_suspend");
aw.await_suspend(h);
return {};
});
}
return aw.await_resume();
}
----

=== Reference

[source,cpp]
----
struct experimental::continuation_frame
{
boost::context::continuation& continuation();
const boost::context::continuation& continuation() const;
continuation_frame(boost::context::continuation && continuation_ = {});
};
template<>
struct std::coroutine_handle<boost::context::continuation>
{
constexpr operator coroutine_handle<>() const noexcept;
constexpr explicit operator bool() const noexcept;
constexpr bool done() const noexcept:
void operator()() const noexcept;
void resume() const noexcept;
void destroy() const noexcept;
boost::context::continuation& promise() const noexcept;
constexpr void* address() const noexcept;
// construct if from a frame
coroutine_handle(boost::cobalt::experimental::continuation_frame & frame
};
----
63 changes: 63 additions & 0 deletions doc/reference/experimental/fiber.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
[#fiber]
== cobalt/experimental/fiber.hpp

WARNING: This is clearly undefined behaviour, since it does an explicit specialization of `std::coroutine_handle`. A paper to address this can be found here (https://isocpp.org/files/papers/P3203R0.html).

This header provides low level support for creating a `std::coroutine_handle` from within a `boost::context::fiber`.


[source,cpp]
----
template<cobalt::awaitable_type Aw>
auto fiber_await(boost::context::fiber && f, Aw && aw)
{
if (!aw.await_ready())
{
boost::cobalt::experimental::fiber_frame ff; // This must be on the fiber stack
f = std::move(f).resume_with(
[&](boost::context::fiber && f_) -> boost::context::fiber
{
ff.fiber() = std::move(f_);
std::coroutine_handle<boost::context::fiber> h(ff);
static_assert(std::is_void_v<decltype(aw.await_suspend(h)>,
"This example only supports awaitables return `void` from await_suspend");
aw.await_suspend(h);
return {};
});
}
return aw.await_resume();
}
----

=== Reference

[source,cpp]
----
struct experimental::fiber_frame
{
boost::context::fiber& fiber();
const boost::context::fiber& fiber() const;
fiber_frame(boost::context::fiber && fiber_ = {});
};
template<>
struct std::coroutine_handle<boost::context::fiber>
{
constexpr operator coroutine_handle<>() const noexcept;
constexpr explicit operator bool() const noexcept;
constexpr bool done() const noexcept:
void operator()() const noexcept;
void resume() const noexcept;
void destroy() const noexcept;
boost::context::fiber& promise() const noexcept;
constexpr void* address() const noexcept;
// construct if from a frame
coroutine_handle(boost::cobalt::experimental::fiber_frame & frame
};
----

0 comments on commit 6d857ac

Please sign in to comment.