// test_race_conditions.cxx // SPDX-License-Identifier: GPL-3.0-or-later // Author: Unai Blazquez #include #include #include #include #include #include #include #include "Consumer.hpp" #include "UnixIpcBridge.hpp" static int argc_ = 0; static QCoreApplication app_(argc_, nullptr); TEST(RaceConditionTest, RepeatedStartStopWhileProducerSends) { const std::string sock = "/tmp/test_race.sock"; constexpr int kCycles = 20; // Watchdog: if the test takes longer than 15s, declare deadlock. std::atomic test_done{false}; std::thread watchdog([&test_done]() { for (int i = 0; i < 150 && !test_done.load(); ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } if (!test_done.load()) { std::cerr << "DEADLOCK DETECTED: RepeatedStartStopWhileProducerSends timed out" << std::endl; std::abort(); } }); // Producer thread: keeps trying to send values. connect() failures // (consumer mid-restart) are expected and silently ignored. std::atomic producer_running{true}; std::thread producer([&]() { while (producer_running.load()) { try { UnixIpcBridge bridge(sock); bridge.send(42); } catch (const std::runtime_error&) { // Expected: consumer socket not ready or just torn down. } std::this_thread::sleep_for(std::chrono::milliseconds(5)); } }); // Main thread: repeatedly start/stop the consumer. for (int i = 0; i < kCycles; ++i) { ConsumerThread consumer(sock); consumer.start(); // Let it run briefly so the producer can connect during some cycles. std::this_thread::sleep_for(std::chrono::milliseconds(10 + (i % 5) * 5)); // stop() must return without deadlock every single time. consumer.stop(); } producer_running.store(false); producer.join(); test_done.store(true); watchdog.join(); // If we reach here, no deadlock across kCycles start/stop cycles. SUCCEED(); }