Skip to content

Commit 9a6a762

Browse files
committed
comments
1 parent 744a83b commit 9a6a762

File tree

20 files changed

+595
-219
lines changed

20 files changed

+595
-219
lines changed

docs/api/schedule.rst

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,8 @@ Busy pool
1616
Unit pool
1717
-------------------
1818

19-
.. doxygentypedef:: lf::unit_pool
19+
.. doxygenclass:: lf::unit_pool
2020

2121

22-
Debug pool (extension)
23-
----------------------------
2422

25-
.. doxygentypedef:: lf::ext::debug_pool
2623

include/libfork/core/co_alloc.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,17 @@ struct [[nodiscard("This object should be co_awaited")]] co_new_t {
4747
static constexpr std::size_t count = Extent; ///< The number of elements to allocate.
4848
};
4949

50+
/**
51+
* @brief An awaitable (in the context of an ``lf::task``) which triggers stack allocation.
52+
*/
5053
template <co_allocable T>
5154
struct [[nodiscard("This object should be co_awaited")]] co_new_t<T, std::dynamic_extent> {
5255
std::size_t count; ///< The number of elements to allocate.
5356
};
5457

58+
/**
59+
* @brief An awaitable (in the context of an ``lf::task``) which triggers stack deallocation.
60+
*/
5561
template <co_allocable T, std::size_t Extent>
5662
struct [[nodiscard("This object should be co_awaited")]] co_delete_t : std::span<T, Extent> {};
5763

include/libfork/core/defer.hpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111

1212
#include <concepts>
1313
#include <functional>
14-
#include <libfork/core/macro.hpp>
1514
#include <type_traits>
1615
#include <utility>
1716

17+
#include "libfork/core/macro.hpp"
18+
1819
#include "libfork/core/impl/utility.hpp"
1920

2021
/**
@@ -69,9 +70,6 @@ class [[nodiscard("Defer will execute unless bound to a name!")]] defer : impl::
6970
[[no_unique_address]] F m_f;
7071
};
7172

72-
#define LF_CONCAT_OUTER(a, b) LF_CONCAT_INNER(a, b)
73-
#define LF_CONCAT_INNER(a, b) a##b
74-
7573
/**
7674
* @brief A macro to create an automatically named defer object.
7775
*/

include/libfork/core/eventually.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ class manual_eventually : impl::manual_lifetime<T> {
145145
using impl::manual_lifetime<T>::destroy;
146146
};
147147

148+
/**
149+
* @brief A `lf::manual_eventually<T>` is an `lf::eventually<T>` which does not call destroy on destruction.
150+
*
151+
* This is useful for writing exception safe fork-join code and should be considered an expert-only feature.
152+
*/
148153
template <impl::non_void T>
149154
requires impl::reference<T>
150155
class manual_eventually<T> : eventually<T> {
@@ -155,7 +160,10 @@ class manual_eventually<T> : eventually<T> {
155160
using eventually<T>::operator->;
156161
using eventually<T>::operator*;
157162

158-
void destroy() noexcept {};
163+
/**
164+
* @brief Destroy the contained object (call its destructor).
165+
*/
166+
void destroy() noexcept { static_assert(std::is_trivially_destructible_v<T>); };
159167
};
160168

161169
} // namespace core

include/libfork/core/ext/context.hpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ class context : impl::immovable<context> {
8080
/**
8181
* @brief Submit pending/suspended tasks to the context.
8282
*
83-
* This is for use by implementor of the scheduler, this will trigger the notification function.
83+
* This is for use by the implementor of the scheduler, this will trigger the notification function.
8484
*/
85-
void submit(intruded_list<submit_handle> jobs) noexcept {
85+
void submit(intruded_list<submit_handle> jobs) {
8686
m_submit.push(non_null(jobs));
8787
m_notify();
8888
}
@@ -93,11 +93,16 @@ class context : impl::immovable<context> {
9393
nullary_function_t m_notify; ///< The user supplied notification function.
9494
};
9595

96+
/**
97+
* @brief Context for (user) schedulers to interact with.
98+
*
99+
* Additionally exposes submit and pop functions.
100+
*/
96101
class worker_context : public context {
97102
public:
98103
using context::context;
99104

100-
using context::submit;
105+
using context::submit; ///< Submit an external task.
101106

102107
/**
103108
* @brief Fetch a linked-list of the submitted tasks.
@@ -116,6 +121,9 @@ class worker_context : public context {
116121

117122
namespace impl {
118123

124+
/**
125+
* @brief Context for internal use, contains full-API for push/pop.
126+
*/
119127
class full_context : public worker_context {
120128
public:
121129
using worker_context::worker_context;

include/libfork/core/ext/list.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,13 @@ class intrusive_list : impl::immovable<intrusive_list<T>> {
7777

7878
/**
7979
* @brief Push a new node, this can be called concurrently from any number of threads.
80+
*
81+
* `new_node` should be an unlinked node e.g. not part of a list.
8082
*/
8183
constexpr void push(node *new_node) noexcept {
8284

85+
LF_ASSERT(new_node->m_next == nullptr);
86+
8387
node *stale_head = m_head.load(std::memory_order_relaxed);
8488

8589
for (;;) {

include/libfork/core/ext/tls.hpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,40 @@ namespace lf {
2828

2929
namespace impl::tls {
3030

31+
/**
32+
* @brief Set when `impl::tls::thread_stack` is alive.
33+
*/
3134
constinit inline thread_local bool has_stack = false;
35+
/**
36+
* @brief A workers stack.
37+
*
38+
* This is wrapped in an `manual_lifetime` to make it trivially destructible/constructible such that it
39+
* requires no construction checks to access.
40+
*/
3241
constinit inline thread_local manual_lifetime<stack> thread_stack = {};
33-
42+
/**
43+
* @brief Set when `impl::tls::thread_stack` is alive.
44+
*/
3445
constinit inline thread_local bool has_context = false;
46+
/**
47+
* @brief A workers context.
48+
*
49+
* This is wrapped in an `manual_lifetime` to make it trivially destructible/constructible such that it
50+
* requires no construction checks to access.
51+
*/
3552
constinit inline thread_local manual_lifetime<full_context> thread_context = {};
3653

54+
/**
55+
* @brief Checked access to a workers stack.
56+
*/
3757
[[nodiscard]] inline auto stack() -> stack * {
3858
LF_ASSERT(has_stack);
3959
return thread_stack.data();
4060
}
4161

62+
/**
63+
* @brief Checked access to a workers context.
64+
*/
4265
[[nodiscard]] inline auto context() -> full_context * {
4366
LF_ASSERT(has_context);
4467
return thread_context.data();

include/libfork/core/impl/awaitables.hpp

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,21 @@ namespace lf::impl {
3333

3434
// -------------------------------------------------------- //
3535

36+
/**
37+
* @brief An awaiter to explicitly transfer execution to another worker.
38+
*
39+
* This is generated by `await_transform` when awaiting on a pointer to a `lf::context`.
40+
*/
3641
struct switch_awaitable : std::suspend_always {
3742

43+
/**
44+
* @brief Shortcut if already on context.
45+
*/
3846
auto await_ready() const noexcept { return tls::context() == dest; }
3947

48+
/**
49+
* @brief Reschedule this coro onto `dest`.
50+
*/
4051
auto await_suspend(std::coroutine_handle<>) noexcept -> std::coroutine_handle<> {
4152

4253
// Schedule this coro for execution on Dest.
@@ -71,14 +82,23 @@ struct switch_awaitable : std::suspend_always {
7182
return std::noop_coroutine();
7283
}
7384

74-
intrusive_list<submit_handle>::node self;
75-
context *dest;
85+
intrusive_list<submit_handle>::node self; ///< The current coroutine's handle.
86+
context *dest; ///< Target context.
7687
};
7788

7889
// -------------------------------------------------------- //
7990

91+
/**
92+
* @brief An awaiter that returns space allocated on the current fibre's stack.
93+
*
94+
* This never suspends the coroutine and is generated by `await_transform` when awaiting on a pointer to a
95+
* `lf::context`.
96+
*/
8097
template <typename T, std::size_t E>
8198
struct alloc_awaitable : std::suspend_never, std::span<T, E> {
99+
/**
100+
* @brief Return a handle to the memory.
101+
*/
82102
[[nodiscard]] auto await_resume() const noexcept -> std::conditional_t<E == 1, T *, std::span<T, E>> {
83103
if constexpr (E == 1) {
84104
return this->data();
@@ -90,8 +110,16 @@ struct alloc_awaitable : std::suspend_never, std::span<T, E> {
90110

91111
// -------------------------------------------------------- //
92112

113+
/**
114+
* @brief An awaiter that suspends the current coroutine and transfers control to a child task.
115+
*
116+
* The parent task is made available for stealing. This is generated by `await_transform` when awaiting on an
117+
* `lf::impl::quasi_awaitable`.
118+
*/
93119
struct fork_awaitable : std::suspend_always {
94-
120+
/**
121+
* @brief Sym-transfer to child, push parent to queue.
122+
*/
95123
auto await_suspend(std::coroutine_handle<>) const noexcept -> std::coroutine_handle<> {
96124
LF_LOG("Forking, push parent to context");
97125
// Need a copy (on stack) in case *this is destructed after push.
@@ -100,22 +128,35 @@ struct fork_awaitable : std::suspend_always {
100128
return child;
101129
}
102130

103-
frame *child;
104-
frame *parent;
131+
frame *child; ///< The suspended child coroutine's frame.
132+
frame *parent; ///< The calling coroutine's frame.
105133
};
106134

135+
/**
136+
* @brief An awaiter that suspends the current coroutine and transfers control to a child task.
137+
*
138+
* The parent task is __not__ made available for stealing. This is generated by `await_transform` when
139+
* awaiting on an `lf::impl::quasi_awaitable`.
140+
*/
107141
struct call_awaitable : std::suspend_always {
108-
142+
/**
143+
* @brief Sym-transfer to child.
144+
*/
109145
auto await_suspend(std::coroutine_handle<>) const noexcept -> std::coroutine_handle<> {
110146
LF_LOG("Calling");
111147
return child->self();
112148
}
113149

114-
frame *child;
150+
frame *child; ///< The suspended child coroutine's frame.
115151
};
116152

117153
// -------------------------------------------------------------------------------- //
118154

155+
/**
156+
* @brief An awaiter to synchronize execution of child tasks.
157+
*
158+
* This is generated by `await_transform` when awaiting on an `lf::impl::join_type`.
159+
*/
119160
struct join_awaitable {
120161
private:
121162
void take_stack_reset_frame() const noexcept {
@@ -128,6 +169,9 @@ struct join_awaitable {
128169
}
129170

130171
public:
172+
/**
173+
* @brief Shortcut if children are ready.
174+
*/
131175
auto await_ready() const noexcept -> bool {
132176
// If no steals then we are the only owner of the parent and we are ready to join.
133177
if (self->load_steals() == 0) {
@@ -154,6 +198,9 @@ struct join_awaitable {
154198
return false;
155199
}
156200

201+
/**
202+
* @brief Mark at join point then yield to scheduler or resume if children are done.
203+
*/
157204
auto await_suspend(std::coroutine_handle<> task) const noexcept -> std::coroutine_handle<> {
158205
// Currently joins = k_u16_max - num_joined
159206
// We set joins = joins() - (k_u16_max - num_steals)
@@ -188,6 +235,9 @@ struct join_awaitable {
188235
return std::noop_coroutine();
189236
}
190237

238+
/**
239+
* @brief A noop in release.
240+
*/
191241
void await_resume() const noexcept {
192242
LF_LOG("join resumes");
193243
// Check we have been reset.
@@ -196,7 +246,7 @@ struct join_awaitable {
196246
LF_ASSERT(self->stacklet() == tls::stack()->top());
197247
}
198248

199-
frame *self;
249+
frame *self; ///< The frame of the awaiting coroutine.
200250
};
201251

202252
} // namespace lf::impl

include/libfork/core/impl/combinate.hpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ struct promise;
3434

3535
/**
3636
* @brief Awaitable in the context of an `lf::task` coroutine.
37+
*
38+
* This will be transformed by an `await_transform` and trigger a fork or call.
3739
*/
3840
template <returnable R, return_address_for<R> I, tag Tag>
3941
struct [[nodiscard("A quasi_awaitable MUST be immediately co_awaited!")]] quasi_awaitable {
@@ -42,6 +44,11 @@ struct [[nodiscard("A quasi_awaitable MUST be immediately co_awaited!")]] quasi_
4244

4345
// ---------------------------- //
4446

47+
/**
48+
* @brief Call an async function with a synthesized first argument.
49+
*
50+
* The first argument will contain a copy of the function hence, this is a fixed-point combinator.
51+
*/
4552
template <quasi_pointer I, tag Tag, async_function_object F>
4653
struct [[nodiscard("A bound function SHOULD be immediately invoked!")]] y_combinate {
4754

@@ -73,15 +80,20 @@ struct [[nodiscard("A bound function SHOULD be immediately invoked!")]] y_combin
7380
}
7481
};
7582

76-
// // ---------------------------- //
83+
// ---------------------------- //
7784

85+
/**
86+
* @brief Build a combinator for `ret` and `fun`.
87+
*/
7888
template <tag Tag, quasi_pointer I, async_function_object F>
7989
auto combinate(I ret, F fun) -> y_combinate<I, Tag, F> {
8090
return {std::move(ret), std::move(fun)};
8191
}
8292

8393
/**
84-
* @brief Prevent each layer wrapping the function in another `first_arg_t`.
94+
* @brief Build a combinator for `ret` and `fun`.
95+
*
96+
* This specialization prevents each layer wrapping the function in another `first_arg_t`.
8597
*/
8698
template <tag Tag,
8799
tag OtherTag,

0 commit comments

Comments
 (0)