78 lines
3.3 KiB
Markdown
78 lines
3.3 KiB
Markdown
|
|
# Post-to and post-back in posting invokers
|
||
|
|
|
||
|
|
## Two targets
|
||
|
|
|
||
|
|
Posting coroutines (`TaggedPostingPromise` / `*ViralPostingInvoker` / `*NonViralPostingInvoker`) use two different `io_context` targets:
|
||
|
|
|
||
|
|
| Direction | When | Target |
|
||
|
|
|---|---|---|
|
||
|
|
| **Post-TO** | `initial_suspend` | Where the callee coroutine **starts running** |
|
||
|
|
| **Post-BACK** | `final_suspend` | Where the caller resumes after `co_await` |
|
||
|
|
|
||
|
|
Post-back always uses `callerIoContext`, initialized from `ComponentThread::getSelf()->getIoContext()` at the `co_await` site. That behavior is unchanged.
|
||
|
|
|
||
|
|
Post-to defaults to the static `ThreadTag::io_context()` for the invoker alias (e.g. `MrnttThreadTag`, `BodyThreadTag`).
|
||
|
|
|
||
|
|
## Static post-TO (default)
|
||
|
|
|
||
|
|
Existing coroutines need no signature change. `TaggedPostingPromise::initial_suspend()` posts the callee handle to `ThreadTag::io_context()`.
|
||
|
|
|
||
|
|
## Dynamic post-TO (`ExplicitPostTarget`)
|
||
|
|
|
||
|
|
Opt in by adding `sscl::co::ExplicitPostTarget` to the coroutine parameter list. The promise constructor extracts it into `std::optional<ExplicitPostTarget> calleePostTarget`; `initial_suspend()` posts to `calleePostTarget->ioContext` instead of `ThreadTag::io_context()`.
|
||
|
|
|
||
|
|
```cpp
|
||
|
|
// Viral member example: run on body thread, post back to mrntt caller
|
||
|
|
BodyViralPostingInvoker<bool> Body::initializeCReq(
|
||
|
|
sscl::co::ExplicitPostTarget postTarget)
|
||
|
|
{
|
||
|
|
co_await ...;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Non-viral example
|
||
|
|
reattachKnownListCReq(
|
||
|
|
sscl::co::ExplicitPostTarget{someIoContext},
|
||
|
|
exceptionPtr,
|
||
|
|
callback);
|
||
|
|
```
|
||
|
|
|
||
|
|
The caller must ensure the referenced `io_context` outlives the callee frame.
|
||
|
|
|
||
|
|
## DeviceManager attach/detach (mrntt orchestrator, library on body/world)
|
||
|
|
|
||
|
|
`DeviceManager::attachStimBuffDeviceCReq` and `detachStimBuffDeviceCReq` stay
|
||
|
|
`MrnttViralPostingInvoker` on the marionette thread. They `co_await` library
|
||
|
|
`attachDeviceCReq` / `detachDeviceCReq` (`DynamicViralPostingInvoker`) with
|
||
|
|
`ExplicitPostTarget` first:
|
||
|
|
|
||
|
|
- **edev** (`sensorType == 'e'`) → world thread
|
||
|
|
- **otherwise** → body thread
|
||
|
|
|
||
|
|
Post-TO runs the library coroutine on that target; post-back resumes the
|
||
|
|
DeviceManager coroutine on mrntt. Attach also passes `componentThread` for
|
||
|
|
device/producer binding inside the library.
|
||
|
|
|
||
|
|
```cpp
|
||
|
|
auto targetThread = threadForDeviceOp(*spec);
|
||
|
|
co_return co_await lib.stimBuffApiDesc.sal_mgmt_libOps.attachDeviceCReq(
|
||
|
|
sscl::co::ExplicitPostTarget{targetThread->getIoContext()},
|
||
|
|
spec,
|
||
|
|
targetThread);
|
||
|
|
```
|
||
|
|
|
||
|
|
Detach uses the same `threadForDeviceOp` rule (not producer lookup).
|
||
|
|
|
||
|
|
## Constructor discrimination
|
||
|
|
|
||
|
|
`PostingPromise` mirrors the existing implicit-`this` peel:
|
||
|
|
|
||
|
|
- Member coroutines pass the object parameter first; it is discarded.
|
||
|
|
- When present, `ExplicitPostTarget` is the next parameter (before non-viral `exception_ptr&` and completion callback).
|
||
|
|
- Free non-viral dynamic: `ExplicitPostTarget`, then `exception_ptr&`, then callback.
|
||
|
|
- `ExplicitPostTarget` is recognized by type (`is_explicit_post_target_v`) and stored in `calleePostTarget`.
|
||
|
|
- `ObjectArg` requires `!is_explicit_post_target_v` so the wrapper is never mistaken for `thisptr`.
|
||
|
|
|
||
|
|
## Timing invariant
|
||
|
|
|
||
|
|
Post-TO and post-BACK work must run from `InitialSuspendPostingInvoker::await_suspend` and `FinalSuspendPostingInvoker::await_suspend`, not synchronously inside `initial_suspend()` / `final_suspend()` bodies. See comments in `postingPromise.h`.
|