Add awaiters for DeviceManager continuations

This commit is contained in:
2026-05-24 23:08:04 -04:00
parent 72134aeac5
commit c539e6e924
2 changed files with 253 additions and 0 deletions
@@ -0,0 +1,93 @@
#ifndef CPS_CALLBACK_AREQ_H
#define CPS_CALLBACK_AREQ_H
#include <atomic>
#include <coroutine>
#include <functional>
#include <memory>
#include <boost/asio/io_service.hpp>
#include <boost/asio/post.hpp>
#include <spinscale/cps/callback.h>
namespace smo {
namespace cpsBoundary {
/** Eager-start CPS callback → coroutine adapter (mirrors
* PuppetThread::ViralThreadLifetimeMgmtInvoker).
*/
template <typename Result, typename CallbackFn, typename StartFn>
class CpsCallbackAReq
{
public:
struct AsyncState
{
std::atomic<bool> settled{false};
Result result{};
std::coroutine_handle<> callerSchedHandle;
};
CpsCallbackAReq(
boost::asio::io_service &resumeIoService,
StartFn startFn)
: asyncState(std::make_shared<AsyncState>()),
resumeIoService(resumeIoService)
{
startFn(sscl::cps::Callback<CallbackFn>{
nullptr,
[this](auto &&...args)
{
storeResult(std::forward<decltype(args)>(args)...);
signalSettledAndResumeCaller();
}});
}
bool await_ready() const noexcept
{
return asyncState->settled.load(std::memory_order_acquire);
}
bool await_suspend(std::coroutine_handle<> callerSchedHandle) noexcept
{
if (asyncState->settled.load(std::memory_order_acquire)) {
return false;
}
asyncState->callerSchedHandle = callerSchedHandle;
return true;
}
Result await_resume() noexcept
{
return asyncState->result;
}
private:
template <typename... Args>
void storeResult(Args &&...args)
{
asyncState->result = Result{std::forward<Args>(args)...};
}
void signalSettledAndResumeCaller() noexcept
{
asyncState->settled.store(true, std::memory_order_release);
std::coroutine_handle<> handle = asyncState->callerSchedHandle;
if (!handle) {
return;
}
boost::asio::post(
resumeIoService,
[handle]() { handle.resume(); });
}
std::shared_ptr<AsyncState> asyncState;
boost::asio::io_service &resumeIoService;
};
} // namespace cpsBoundary
} // namespace smo
#endif // CPS_CALLBACK_AREQ_H
@@ -0,0 +1,160 @@
#ifndef STIM_BUFF_DEVICE_AREQ_H
#define STIM_BUFF_DEVICE_AREQ_H
#include <atomic>
#include <coroutine>
#include <memory>
#include <boost/asio/io_service.hpp>
#include <boost/asio/post.hpp>
#include <spinscale/cps/callback.h>
#include <stimBuffApis/stimBuffApiLib.h>
#include <user/deviceAttachmentSpec.h>
#include <user/senseApiDesc.h>
namespace smo {
namespace cpsBoundary {
struct StimBuffDeviceOpResult
{
bool success = false;
std::shared_ptr<device::DeviceAttachmentSpec> deviceSpec;
};
struct AttachStimBuffDeviceAReq
{
struct AsyncState
{
std::atomic<bool> settled{false};
StimBuffDeviceOpResult result;
std::coroutine_handle<> callerSchedHandle;
};
AttachStimBuffDeviceAReq(
const std::shared_ptr<device::DeviceAttachmentSpec> &spec,
stim_buff::StimBuffApiLib &lib,
const std::shared_ptr<sscl::ComponentThread> &threadForAttachment,
boost::asio::io_service &resumeIoService)
: asyncState(std::make_shared<AsyncState>()),
resumeIoService(resumeIoService)
{
lib.stimBuffApiDesc.sal_mgmt_libOps.attachDeviceReq(
spec, threadForAttachment,
{nullptr,
[asyncState = asyncState, &resumeIoService = resumeIoService](
bool success,
std::shared_ptr<device::DeviceAttachmentSpec> deviceSpec)
{
asyncState->result = StimBuffDeviceOpResult{
success, deviceSpec};
asyncState->settled.store(
true, std::memory_order_release);
std::coroutine_handle<> handle =
asyncState->callerSchedHandle;
if (!handle) {
return;
}
boost::asio::post(
resumeIoService,
[handle]() { handle.resume(); });
}});
}
bool await_ready() const noexcept
{
return asyncState->settled.load(std::memory_order_acquire);
}
bool await_suspend(std::coroutine_handle<> callerSchedHandle) noexcept
{
if (asyncState->settled.load(std::memory_order_acquire)) {
return false;
}
asyncState->callerSchedHandle = callerSchedHandle;
return true;
}
StimBuffDeviceOpResult await_resume() noexcept
{
return asyncState->result;
}
std::shared_ptr<AsyncState> asyncState;
boost::asio::io_service &resumeIoService;
};
struct DetachStimBuffDeviceAReq
{
struct AsyncState
{
std::atomic<bool> settled{false};
StimBuffDeviceOpResult result;
std::coroutine_handle<> callerSchedHandle;
};
DetachStimBuffDeviceAReq(
const std::shared_ptr<device::DeviceAttachmentSpec> &spec,
stim_buff::StimBuffApiLib &lib,
boost::asio::io_service &resumeIoService)
: asyncState(std::make_shared<AsyncState>()),
resumeIoService(resumeIoService)
{
lib.stimBuffApiDesc.sal_mgmt_libOps.detachDeviceReq(
spec,
{nullptr,
[asyncState = asyncState, &resumeIoService = resumeIoService](
bool success,
std::shared_ptr<device::DeviceAttachmentSpec> deviceSpec)
{
asyncState->result = StimBuffDeviceOpResult{
success, deviceSpec};
asyncState->settled.store(
true, std::memory_order_release);
std::coroutine_handle<> handle =
asyncState->callerSchedHandle;
if (!handle) {
return;
}
boost::asio::post(
resumeIoService,
[handle]() { handle.resume(); });
}});
}
bool await_ready() const noexcept
{
return asyncState->settled.load(std::memory_order_acquire);
}
bool await_suspend(std::coroutine_handle<> callerSchedHandle) noexcept
{
if (asyncState->settled.load(std::memory_order_acquire)) {
return false;
}
asyncState->callerSchedHandle = callerSchedHandle;
return true;
}
StimBuffDeviceOpResult await_resume() noexcept
{
return asyncState->result;
}
std::shared_ptr<AsyncState> asyncState;
boost::asio::io_service &resumeIoService;
};
} // namespace cpsBoundary
} // namespace smo
#endif // STIM_BUFF_DEVICE_AREQ_H