|
morph 0.1.0
Asynchronous bridge between GUI thread and business models
|
In-process backend that executes model actions on a thread pool strand. More...
#include <backend.hpp>
Public Member Functions | |
| LocalBackend (::morph::exec::IExecutor &workerPool) | |
Constructs the backend using workerPool to run model actions. | |
| ~LocalBackend () override | |
| Stops the Task handlers still running, lets the strands drain, seals them, drains them again, and only then closes them (ModelStrands::teardown). See docs/spec/core/coroutines.md, "Teardown". | |
| void | setEventHandler (std::function< void(::morph::wire::EventBody)> handler, ::morph::exec::IExecutor *exec) override |
| Installs the event handler deliverEvent posts to. | |
| void | deliverEvent (::morph::wire::EventBody event) |
Test seam: delivers event as if a server had sent it. | |
| LocalBackend (const LocalBackend &)=delete | |
| LocalBackend & | operator= (const LocalBackend &)=delete |
| LocalBackend (LocalBackend &&)=delete | |
| LocalBackend & | operator= (LocalBackend &&)=delete |
| ::morph::exec::detail::ModelId | registerModel (const std::string &, std::function< std::unique_ptr<::morph::model::detail::IModelHolder >()> factory) override |
Creates a model instance via factory and registers it. | |
| ::morph::async::Completion<::morph::exec::detail::ModelId > | bindModel (detail::BindRequest request, ::morph::exec::IExecutor &cbExec) override |
Acquires an instance for request and settles the returned Completion before returning. | |
| void | setOwner (const ::morph::exec::detail::OwnerAffinity &owner) override |
| Records the owner every verb below is called from. | |
| void | assignPrimary (::morph::exec::detail::ModelId mid, const std::string &typeId, std::string_view primary) override |
Enters an already-live, still-anonymous instance into the directory under primary. | |
| std::vector< std::string > | listInstances (const std::string &typeId) override |
Lists the primary keys of live shared instances of typeId. | |
| void | deregisterModel (::morph::exec::detail::ModelId mid) override |
Removes the model with mid, or releases one attachment to it. | |
| void | notifyBackendChanged () override |
| Schedules onBackendChanged() on each change-aware model's strand. | |
| ::morph::async::Completion< std::shared_ptr< void > > | execute (::morph::exec::detail::ModelId mid, detail::ActionCall call, ::morph::exec::IExecutor *cbExec) final |
| Schedules call.localOp on the model's strand and returns a Completion. | |
| void | executeInto (::morph::exec::detail::ModelId mid, detail::ActionCall call, ::morph::exec::IExecutor *cbExec, std::shared_ptr<::morph::async::detail::ISettleSink > sink) override |
Schedules call.localOp on the model's strand and settles sink. | |
| void | cancelPending (const std::exception_ptr &exc) override |
Resolves every still-pending completion this backend produced with exc, and requests stop on every Task handler still running. | |
| std::size_t | trackedPendingCount () const |
| Number of entries currently held in the pending list. | |
In-process backend that executes model actions on a thread pool strand.
Each model instance gets its own strand so actions are serialised per-model without a global lock on the pool.
Its registry, its pending list and its record of Task runs belong to the caller's owner — the Bridge's, given through setOwner — and are touched only there, without a lock. Only the strand tasks it posts run elsewhere, and they reach nothing of the backend but what each carries.
Definition at line 1067 of file backend.hpp.
|
inlineexplicit |
Constructs the backend using workerPool to run model actions.
| workerPool | Executor (typically a ThreadPoolExecutor) for model work. Borrowed, not owned: this backend's strands run on it, so it must outlive the backend and keep running tasks until teardown completes — destroying it first deadlocks (see docs/spec/concurrency_and_lifetimes.md, "Destruction ordering"). |
Definition at line 1077 of file backend.hpp.
|
inlineoverride |
Stops the Task handlers still running, lets the strands drain, seals them, drains them again, and only then closes them (ModelStrands::teardown). See docs/spec/core/coroutines.md, "Teardown".
Where threads exist, in that order:
Must not run on one of this backend's strand threads, whose drain it would wait for; a debug build asserts that. The single-threaded WebAssembly build seals, stops the handlers, then closes: sealed first, each stopped handler unwinds inline in the stop, and the drains wait for nothing, since nothing else could run the strands.
Definition at line 1112 of file backend.hpp.
|
inlineoverride |
Installs the event handler deliverEvent posts to.
| handler | Callable posted to exec once per delivered event; nullptr clears. |
| exec | Executor the handler is posted to. Borrowed: it must outlive the installation. |
Definition at line 1127 of file backend.hpp.
|
inline |
Test seam: delivers event as if a server had sent it.
A local backend has no server and produces no events itself; this lets a test drive the client's event path without one. Thread-safe. The handler is posted to the executor given to setEventHandler; with no handler installed the event is dropped.
| event | The event to deliver. |
Definition at line 1142 of file backend.hpp.
|
inlineoverride |
Creates a model instance via factory and registers it.
The typeId parameter is accepted for interface compatibility but not used — it is unnamed in the signature below, and the concrete type is captured by the factory closure. If the new holder's isBackendChangeAware() returns true, the new id (a local in createAndTrack, not a parameter here) is also recorded in _changeAware so notifyBackendChanged() finds it without a dynamic_cast sweep.
| factory | Callable that constructs the IModelHolder. |
Definition at line 1173 of file backend.hpp.
|
inlineoverride |
Acquires an instance for request and settles the returned Completion before returning.
Every shape of BindRequest is answered here, against this backend's own directory: an empty primary creates a private instance; a non-empty one registers-or-attaches the shared instance for (typeId, primary), lazily evicting one whose first action failed (InstanceDirectory::attach); a non-zero current is released once the replacement is acquired, so a same-key re-attach keeps the instance it already holds and a throwing acquire never strands the caller.
| request | Owning bind request; moved from. |
| cbExec | Executor the continuation is delivered on. Borrowed: it must outlive the returned Completion. |
Definition at line 1195 of file backend.hpp.
|
inlineoverride |
Records the owner every verb below is called from.
| owner | The caller's owner. |
Definition at line 1210 of file backend.hpp.
|
inlineoverride |
Enters an already-live, still-anonymous instance into the directory under primary.
| mid | Live instance to promote. |
| typeId | Model type id — the directory's first key component. |
| primary | Canonical string encoding of the key to file it under. |
Definition at line 1217 of file backend.hpp.
|
inlineoverride |
Lists the primary keys of live shared instances of typeId.
| typeId | String type-id to enumerate. |
Definition at line 1232 of file backend.hpp.
|
inlineoverride |
Removes the model with mid, or releases one attachment to it.
A private instance is erased outright. A shared instance has its attach count decremented and is erased — and removed from the directory — only when that count reaches zero, so releasing one handler never destroys an instance another handler still holds.
| mid | Id returned by a prior registerModel()/bindModel() call. |
Definition at line 1244 of file backend.hpp.
|
inlineoverride |
Schedules onBackendChanged() on each change-aware model's strand.
Only models recorded in _changeAware — maintained by createAndTrack/ deregisterModel from IModelHolder::isBackendChangeAware(), a compile-time answer per model type — are visited; there is no dynamic_cast and no scan of models that never opted in. Each such model's onBackendChanged() (the IModelHolder base virtual) is posted onto that model's own strand (the same per-ModelId serial queue execute uses), rather than invoked inline on the caller's thread. Two properties follow, and they are the whole point:
A shared_ptr copy of each holder is captured into the posted task so a concurrent deregisterModel cannot free the model out from under its pending notification (mirrors execute's holder capture).
Definition at line 1278 of file backend.hpp.
|
inlinefinal |
Schedules call.localOp on the model's strand and returns a Completion.
The completion resolves with the opaque result on the strand thread and the callbacks are delivered via cbExec.
Expressed in terms of executeInto rather than beside it, so there is one definition of what a local dispatch does whichever entry point a caller uses. The extra CompletionState and its adapter sink are the price of the Completion-returning shape — which is exactly the cost executeInto exists to let Bridge avoid.
| mid | Target model id. |
| call | Bundled action; localOp is the only field used here. |
| cbExec | Executor for delivering callbacks. |
Definition at line 1313 of file backend.hpp.
|
inlineoverride |
Schedules call.localOp on the model's strand and settles sink.
| mid | Target model id. |
| call | Bundled action; localOp is the only field used here. |
| cbExec | Unused here: a sink carries its own delivery. Accepted so the signature matches IBackend::executeInto, whose remote implementations do need it. |
| sink | Settled on the strand thread with the result or the exception, exactly once. |
Definition at line 1332 of file backend.hpp.
|
inlineoverride |
Resolves every still-pending completion this backend produced with exc, and requests stop on every Task handler still running.
A run still waiting for its instance's action gate is failed where it waits (see admitLocal); a Task handler already running observes the stop on its token at its next co_await.
| exc | Exception delivered to every pending completion's error sink. |
Definition at line 1421 of file backend.hpp.
|
inlinenodiscard |
Number of entries currently held in the pending list.
Not the number of calls in flight: the list is compacted amortised (see trackPending), so it also carries entries whose completion has already been destroyed and which cancelPending would skip. It is an upper bound on the in-flight count and a direct measure of what the compaction policy costs in memory — which is what it exists to make observable. For a count of in-flight calls, use Bridge::pendingCalls().
Definition at line 1458 of file backend.hpp.