6#include <core/async/StopToken.hpp>
7#include <core/async/Task.hpp>
28namespace morph::model {
38 static constexpr bool isTask =
false;
85 template <std::invocable Start>
86 void enter(Start&& start) {
87 Occupancy
const occupancy{*
this};
88 if (_held || (_waiting !=
nullptr && !_waiting->empty())) {
89 if (_waiting ==
nullptr) {
90 _waiting = std::make_unique<std::deque<std::function<void()>>>();
92 _waiting->emplace_back(std::forward<Start>(start));
108 [[nodiscard]]
bool tryEnter() {
109 Occupancy
const occupancy{*
this};
110 if (_held || (_waiting !=
nullptr && !_waiting->empty())) {
123 Occupancy
const occupancy{*
this};
129 while (!_held && _waiting !=
nullptr && !_waiting->empty()) {
130 auto next = std::move(_waiting->front());
131 _waiting->pop_front();
146 [[nodiscard]]
static std::size_t overlapsObserved()
noexcept {
return overlapCounter().load(); }
149 static std::atomic<std::size_t>& overlapCounter()
noexcept {
150 static std::atomic<std::size_t> counter{0};
159 explicit Occupancy(ActionGate& gate) noexcept : _gate{&gate} {
160 auto expected = std::thread::id{};
161 auto const self = std::this_thread::get_id();
162 _owner = _gate->_occupant.compare_exchange_strong(expected, self);
163 if (!_owner && expected != self) {
164 overlapCounter().fetch_add(1);
167 Occupancy(
const Occupancy&) =
delete;
168 Occupancy& operator=(
const Occupancy&) =
delete;
169 Occupancy(Occupancy&&) =
delete;
170 Occupancy& operator=(Occupancy&&) =
delete;
173 _gate->_occupant.store(std::thread::id{});
182 std::atomic<std::thread::id> _occupant;
184 bool _draining =
false;
188 std::unique_ptr<std::deque<std::function<void()>>> _waiting;
198struct TaskHandlerDriver {
202 struct promise_type {
203 ::core::async::StopToken token;
205 TaskHandlerDriver get_return_object()
noexcept {
206 return TaskHandlerDriver{std::coroutine_handle<promise_type>::from_promise(*
this)};
208 [[nodiscard]] std::suspend_always initial_suspend()
const noexcept {
return {}; }
209 [[nodiscard]] std::suspend_never final_suspend()
const noexcept {
return {}; }
210 void return_void()
const noexcept {}
213 [[noreturn]]
void unhandled_exception()
const noexcept { std::terminate(); }
214 [[nodiscard]] ::core::async::StopToken stopToken()
const noexcept {
return token; }
218 std::coroutine_handle<promise_type> handle;
229TaskHandlerDriver driveTaskHandler(std::shared_ptr<::morph::exec::detail::TaskResumer> executor,
230 ::core::async::Task<R> task,
231 std::function<
void(std::optional<R>, std::exception_ptr)> done) {
232 static_cast<void>(executor);
233 std::optional<R> result;
234 std::exception_ptr error;
238 R value =
co_await std::move(task);
239 result.emplace(std::move(value));
241 error = std::current_exception();
243 done(std::move(result), error);
257void startTaskHandler(
const std::shared_ptr<::morph::exec::detail::TaskResumer>& executor, ::core::async::Task<R> task,
258 ::core::async::StopToken token, std::function<
void(std::optional<R>, std::exception_ptr)> done) {
259 auto driver = driveTaskHandler<R>(executor, std::move(task), std::move(done));
260 driver.handle.promise().token = std::move(token);
261 executor->resumeHere(driver.handle);
morph's strands: one per model instance, from core-cpp's core::async::KeyedStrands,...
R type
The action's result type: what the Task produces.
static constexpr bool isTask
Whether the handler is a coroutine returning core::async::Task.
The result an action handler's return type stands for: R for a core::async::Task<R> handler,...
T type
The action's result type.
static constexpr bool isTask
HandlerResult< T >::type HandlerResultT
The action result a handler returning T produces.
constexpr bool isTaskHandler
Whether a handler returning T is a Task handler.