morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
loop_executor.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4#include <core/net/EventLoop.hpp>
5#include <functional>
6#include <memory>
7
8#include "../attributes.hpp"
9#include "../core/executor.hpp"
10
11/// @file
12/// @brief `morph::tui::LoopExecutor`: a morph executor whose tasks run in turns of a core-cpp event loop.
13///
14/// Specified in `docs/spec/tui/frontend.md`, "The loop executor".
15
16namespace morph::tui {
17
18/// @brief Runs every posted task in a later turn of one `core::net::EventLoop`, with this executor current.
19///
20/// The TUI frontend's reactive `Runtime` is owned by one, and every `BridgeHandler` an application builds receives
21/// it as its callback executor, so model replies, timers, sockets and input all run on the thread that turns the
22/// loop. `post()` may be called from any thread. A task still queued when the executor is destroyed is dropped,
23/// and a task that throws is logged and does not stop the loop.
24///
25/// Destroy it on the thread that turns the loop, between turns or from inside one of its own tasks, never from
26/// another thread: a task already running there would go on using an owner (the reactive `Runtime`) that is gone.
27/// Nothing guards against that, because a lock held across a task would deadlock a task that destroys its own
28/// executor.
29class LoopExecutor final : public exec::IExecutor {
30public:
31 /// @param loop The loop to post to. Borrowed: it must outlive this executor.
32 explicit LoopExecutor(::core::net::EventLoop& loop MORPH_LIFETIMEBOUND);
33
34 /// @brief Destroys the executor; tasks it posted that have not run yet are dropped when the loop reaches them.
35 ~LoopExecutor() override;
36
37 LoopExecutor(LoopExecutor const&) = delete;
38 LoopExecutor& operator=(LoopExecutor const&) = delete;
39 LoopExecutor(LoopExecutor&&) = delete;
40 LoopExecutor& operator=(LoopExecutor&&) = delete;
41
42 /// @brief Queues @p task for a later turn of the loop.
43 /// @param task What to run; inside it `exec::runningOn(*this)` holds.
44 void post(std::function<void()> task) override;
45
46private:
47 ::core::net::EventLoop* _loop;
48 /// Read by each queued task: once this executor is gone the task is dropped. A box rather than the executor,
49 /// because a task outlives the executor that posted it.
50 std::shared_ptr<LoopExecutor*> _alive;
51};
52
53} // namespace morph::tui
LoopExecutor(::core::net::EventLoop &loop)
void post(std::function< void()> task) override
Queues task for a later turn of the loop.
~LoopExecutor() override
Destroys the executor; tasks it posted that have not run yet are dropped when the loop reaches them.
Abstract executor interface.
Definition executor.hpp:70