From 2cbd872744f7f0fd5b7788dafb44e8eb36095588 Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Fri, 29 May 2026 20:48:36 +0800 Subject: [PATCH 1/3] fix race condition in manual reset event --- include/nova/sync/event/parking_manual_reset_event.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nova/sync/event/parking_manual_reset_event.hpp b/include/nova/sync/event/parking_manual_reset_event.hpp index cb3b017..653b7e9 100644 --- a/include/nova/sync/event/parking_manual_reset_event.hpp +++ b/include/nova/sync/event/parking_manual_reset_event.hpp @@ -71,7 +71,7 @@ class parking_manual_reset_event bool success = detail::run_with_exponential_backoff_until( [ this ]() -> detail::backoff_result { if ( state_.load( std::memory_order_acquire ) != 0u ) return detail::backoff_result::success; - return detail::backoff_result::retry_without_backoff; + return detail::backoff_result::retry; } ); if ( success ) return; From 1cf1532c00153576a7a35aa8f9a3357a2eb9346c Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Sat, 30 May 2026 00:09:31 +0800 Subject: [PATCH 2/3] tests: fix some tsan errors --- test/event_async_asio_test.cpp | 10 +++++----- test/event_async_qt_test.cpp | 14 ++++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/test/event_async_asio_test.cpp b/test/event_async_asio_test.cpp index 78eaef3..adb5bdc 100644 --- a/test/event_async_asio_test.cpp +++ b/test/event_async_asio_test.cpp @@ -285,12 +285,12 @@ TEMPLATE_TEST_CASE( "async_event stress: signal races async_wait", using Evt = TestType; asio_event_runner runner; - const int rounds = 50; - auto completions = std::make_shared< std::atomic< int > >( 0 ); + constexpr int rounds = 50; + std::array< Evt, rounds > events; - for ( int i = 0; i < rounds; ++i ) { - Evt evt; + auto completions = std::make_shared< std::atomic< int > >( 0 ); + for ( Evt& evt : events ) { nova::sync::async_wait( runner.ioc, evt, [ completions ]( auto result ) { REQUIRE( result.has_value() ); ++( *completions ); @@ -300,7 +300,7 @@ TEMPLATE_TEST_CASE( "async_event stress: signal races async_wait", evt.signal(); // Small sleep to let this round settle before moving to the next - std::this_thread::sleep_for( 2ms ); + std::this_thread::sleep_for( 1ms ); } auto deadline = std::chrono::steady_clock::now() + 5s; diff --git a/test/event_async_qt_test.cpp b/test/event_async_qt_test.cpp index 6899758..64ac58a 100644 --- a/test/event_async_qt_test.cpp +++ b/test/event_async_qt_test.cpp @@ -117,17 +117,18 @@ TEMPLATE_TEST_CASE( "async_event (qt): fires after signal from another thread", REQUIRE( !fired->load() ); // Signal from a background thread - std::thread( [ &evt, signal_sent ] { - std::this_thread::sleep_for( 10ms ); + std::thread signal_thread( [ &evt, signal_sent ] { + std::this_thread::sleep_for( 100ms ); *signal_sent = true; evt.signal(); - } ).detach(); + } ); process_events_until( std::chrono::steady_clock::now() + 2s, [ &fired ] { return fired->load(); } ); REQUIRE( fired->load() ); REQUIRE( fired_after_signal->load() ); + signal_thread.join(); } // --------------------------------------------------------------------------- @@ -173,10 +174,10 @@ TEMPLATE_TEST_CASE( "async_event (qt): future-based qt_async_wait", "[async_even auto fut = nova::sync::qt_async_wait( evt, QCoreApplication::instance() ); // Signal from a thread to avoid blocking processEvents indefinitely - std::thread( [ &evt ] { - std::this_thread::sleep_for( 10ms ); + std::thread signal( [ &evt ] { + std::this_thread::sleep_for( 100ms ); evt.signal(); - } ).detach(); + } ); // Drive event loop until future is ready process_events_until( std::chrono::steady_clock::now() + 2s, [ &fut ] { @@ -184,6 +185,7 @@ TEMPLATE_TEST_CASE( "async_event (qt): future-based qt_async_wait", "[async_even } ); REQUIRE( fut.wait_for( 0s ) == std::future_status::ready ); + signal.join(); } // --------------------------------------------------------------------------- From 9b126ed006445b8d612403b3bfe126063beb08ae Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Sat, 30 May 2026 00:11:11 +0800 Subject: [PATCH 3/3] CI: enable sanitizers --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a157ce3..acc20bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,3 +14,4 @@ jobs: uses: timblechmann/nova_github_actions/.github/workflows/cmake-ci.yml@main with: cmake_args: -DNOVA_SYNC_TESTS_STRESS_TEST=OFF + enable_sanitizers: true