test: add ThreadSanitizer verification for lock-free Channel<T>
Add a contended SPSC stress suite (tests/test_channel_stress.cpp) that actually exercises the ring's memory-ordering pairing and spin/futex/ lost-wakeup logic, plus the CMake and CI plumbing to run it under TSan: - KPN_SANITIZER cache var + kpn_sanitizer_flags() helper (no-op when unset) - kpn_tests_stress executable, labelled "stress" for CTest - reusable tsan.yaml workflow (gcc:14 builder image, already ships libtsan) - ci.yaml gains a tsan job on the same code/dockerfile triggers as test Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
name: '🧵 ThreadSanitizer'
|
||||
|
||||
# Reusable workflow: builds the channel stress suite with ThreadSanitizer and
|
||||
# runs it. This is the dynamic half of verifying the lock-free SPSC Channel<T>
|
||||
# (the static half is the CDSChecker model-check harness in verify/).
|
||||
#
|
||||
# Triggering and path filtering are owned by ci.yaml (the orchestrator), which
|
||||
# calls this only when code changed. workflow_dispatch is kept for manual runs.
|
||||
#
|
||||
# Runs in the prebuilt builder image (gcc:14), which already ships libtsan — no
|
||||
# package installs at job time.
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
tsan:
|
||||
runs-on: linux/amd64
|
||||
container:
|
||||
image: gitea.tourolle.paris/dtourolle/kpnpp-builder:latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: tsan-${{ github.run_id }}
|
||||
|
||||
- name: Cache FetchContent dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cmake/fetchcontent
|
||||
key: cmake-fetchcontent-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
restore-keys: cmake-fetchcontent-
|
||||
|
||||
- name: Configure (TSan)
|
||||
working-directory: tsan-${{ github.run_id }}
|
||||
run: |
|
||||
cmake -S . -B build \
|
||||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DKPN_SANITIZER=thread \
|
||||
-DKPN_BUILD_TESTS=ON \
|
||||
-DKPN_BUILD_EXAMPLES=OFF \
|
||||
-DKPN_BUILD_PYTHON=OFF \
|
||||
-DFETCHCONTENT_BASE_DIR=$HOME/.cmake/fetchcontent
|
||||
|
||||
- name: Build (TSan)
|
||||
working-directory: tsan-${{ github.run_id }}
|
||||
run: cmake --build build --parallel --target kpn_tests kpn_tests_stress
|
||||
|
||||
- name: Run stress suite under TSan
|
||||
working-directory: tsan-${{ github.run_id }}
|
||||
# halt_on_error=1 makes the first detected race fail the job; the report
|
||||
# (with both stacks) is printed to the log. second_deadlock_stack gives
|
||||
# the full picture for lock-order issues.
|
||||
env:
|
||||
TSAN_OPTIONS: "halt_on_error=1 second_deadlock_stack=1"
|
||||
run: ./build/tests/kpn_tests_stress
|
||||
|
||||
- name: Run unit tests under TSan
|
||||
working-directory: tsan-${{ github.run_id }}
|
||||
env:
|
||||
TSAN_OPTIONS: "halt_on_error=1 second_deadlock_stack=1"
|
||||
run: ./build/tests/kpn_tests
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: rm -rf tsan-${{ github.run_id }}
|
||||
Reference in New Issue
Block a user