#ifndef SYNC_CANCELER_FOR_ASYNC_WORK_H #define SYNC_CANCELER_FOR_ASYNC_WORK_H #include #include #include #include namespace sscl { /** * SyncCancelerForAsyncWork * * A small helper to coordinate synchronous cancellation requests with * asynchronous work that must only observe cancellation at explicit * uncancelable segment boundaries. * * The async callee should structure its logic as: * - enter an uncancelable segment (execUncancelableSegmentOrAbort) * - perform synchronous work that must not be interrupted * - exit the segment * - perform cancelable async work (outside the lock) * - repeat * * requestStop() blocks until any currently-executing segment releases s.lock, * then flips shouldContinue to false. This guarantees shouldContinue is stable * throughout each uncancelable segment. * * startAcceptingWork() is intentionally unlocked. Precondition: callers must * only call startAcceptingWork() when no async callee is running yet (e.g. at * the end of setup(), before posting/arming the first async work). If this * method races a running callee, that is a caller bug. */ class SyncCancelerForAsyncWork { public: struct Resources { bool shouldContinue = false; }; SyncCancelerForAsyncWork() = default; void startAcceptingWork() { // Intentionally unlocked — see class-level EXPLANATION above. s.rsrc.shouldContinue = true; } /** @return shouldContinue before this call (was work being accepted?) */ bool requestStop() { sscl::SpinLock::Guard guard(s.lock); const bool wasContinuing = s.rsrc.shouldContinue; s.rsrc.shouldContinue = false; return wasContinuing; } /** @return true if requestStop() has set shouldContinue to false. */ bool isCancellationRequested() { sscl::SpinLock::Guard guard(s.lock); return isCancellationRequestedUnlocked(); } bool isCancellationRequestedUnlocked() const { return !s.rsrc.shouldContinue; } template requires std::invocable bool execUncancelableSegmentOrAbort(Body&& body) { sscl::SpinLock::Guard guard(s.lock); if (!s.rsrc.shouldContinue) { return false; } std::forward(body)(); return true; } public: sscl::SharedResourceGroup s; }; } // namespace sscl #endif // SYNC_CANCELER_FOR_ASYNC_WORK_H