- NOLINT the compiler-mandated coroutine protocol names (promise_type,
await_ready, ...) that conflict with readability-identifier-naming and
readability-convert-member-functions-to-static
- Add [[nodiscard]] to handle(), done(), await_ready()
- Replace std::lock_guard with std::scoped_lock const
- Pass CoroTaskRunner name by value and std::move it; default-init
runCount_ in-class
- Drop unused <coroutine> include from JobQueue.h; include
instrumentation.h directly in JobQueueAwaiter.h
- CoroTask_test: kN constant naming, const locals, file-level NOLINT for
cppcoreguidelines-avoid-capturing-lambda-coroutines (lifetimes are
gated and joined)
- resume() now skips the handle resume when the task is null or done
(duplicate external post() after completion), matching the old
Coro::resume() 'if (coro_)' guard instead of invoking UB in release
builds. The runCount_ bookkeeping still runs to balance post().
- Exceptions escaping a top-level coroutine body were captured by
unhandled_exception() and destroyed unobserved with the frame; they
are now logged at error level before the frame is released.
- Document that join() may return via the finished_ disjunct while the
final resume() is still completing its bookkeeping.
Forward-merge PR 6429 (and develop) into the TSAN branch.
Conflict resolutions:
- JobQueue.h: keep the TSAN-safe postCoroTask (jobCounter_.wrap slot
reservation) on top of the legacy Coro removal.
- CoroTaskRunner.ipp: keep atomic finished_ (acquire loads) with the
renamed mutexRun_ from develop.
- reusable-build-test-config.yml: keep the single sanitizer-options step
and fold the sanitizer single-threaded test parallelism into the
coverage parallelism logic.
- linux.json: add "thread" to the amd64 sanitizer matrix (replaces the
removed generate.py logic).
- CoroTask_test.cpp: rename create_t/jtCLIENT to CreateT/JtClient in
testExpectEarlyExit.
Resolves the develop rename of cspell.config.yaml and the JobQueue.h
conflicts, and aligns the new coroutine primitives with develop naming
(CreateT, mutex_/mutexRun_, JtClient, forceMultiThread,
beast::unit_test::Suite).
Also addresses two review findings:
- postCoroTask now holds a jobCounter_ reservation for the whole
function. JobQueue::stop() joins jobCounter_ before asserting
nSuspend_ == 0, so the reservation closes the window between the
++nSuspend_ and the balancing post()/expectEarlyExit(), and doubles
as the shutdown check.
- YieldPostAwaiter::await_suspend returns a coroutine_handle<>
(symmetric transfer) instead of resuming inline. This keeps a
yield loop against a stopping JobQueue from growing the stack
without bound and avoids touching a frame that resume() may have
already destroyed.
- Fix TSAN data races in CoroTaskRunner (atomic operations, mutex guards)
- Enable TSAN CI builds with proper ucontext support
- Add TSAN suppressions for pre-existing rippled issues
- Remove -fno-pie flags for sanitizer compatibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add C++20 std::coroutine based task primitives for the JobQueue:
- CoroTask<T>: A coroutine return type with RAII ownership semantics
and symmetric transfer for efficient resumption.
- CoroTaskRunner: Manages coroutine lifecycle on the JobQueue with
suspend/resume tracking, LocalValue preservation, and graceful
shutdown support.
- JobQueueAwaiter: External awaiter combining yield+post atomically.
- yieldAndPost(): Inline awaiter workaround for GCC-12 codegen bug
where external awaiters at multiple co_await points corrupt the
coroutine state machine resume index.
- CoroTask_test: Comprehensive test suite covering task lifecycle,
suspend/resume, shutdown, and value-returning coroutines.
- BoostToStdCoroutineSwitchPlan.md: Migration plan documentation.