From a83a46d60059a063ec953ba15f4cdcc2b3874440 Mon Sep 17 00:00:00 2001 From: j-berman Date: Fri, 7 Nov 2025 16:00:57 -0800 Subject: Fix logging deadlock --- tests/unit_tests/logging.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'tests/unit_tests/logging.cpp') diff --git a/tests/unit_tests/logging.cpp b/tests/unit_tests/logging.cpp index 2c10f2c0a..371f18812 100644 --- a/tests/unit_tests/logging.cpp +++ b/tests/unit_tests/logging.cpp @@ -28,6 +28,10 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers +#include +#include +#include + #include #include "gtest/gtest.h" #include "file_io_utils.h" @@ -215,3 +219,55 @@ TEST(logging, empty_configurations_throws) const el::Configurations cfg; EXPECT_ANY_THROW(log1.configure(cfg)); } + +TEST(logging, deadlock) +{ + std::mutex inner_mutex; + + // 1. Thread 1 starts logger + // 2. Thread 2 grabs inner mutex shared across threads + // 3. Thread 2 logs + // 4. Thread 1 grabs inner mutex shared across threads + // 5. Thread 1 finishes logging + std::condition_variable cv1, cv2; + std::mutex mutex1, mutex2; + std::unique_lock lock_until_t1_starts_logger(mutex1); + std::unique_lock lock_until_t2_finishes_logging(mutex2); + bool t1_started_logger = false; + bool t2_finished_logging = false; + + const auto thread1_func = [&] + { + const auto thread1_inner_func = [&]() -> std::string + { + t1_started_logger = true; + lock_until_t1_starts_logger.unlock(); + cv1.notify_one(); + cv2.wait(lock_until_t2_finishes_logging, [&]{return t2_finished_logging;}); + + std::lock_guard guard(inner_mutex); + return "world!"; + }; + MGINFO("Hello, " << thread1_inner_func() << " - Sincerely, thread 1"); + }; + + const auto thread2_func = [&] + { + cv1.wait(lock_until_t1_starts_logger, [&]{return t1_started_logger;}); + + { + std::lock_guard guard(inner_mutex); + MGINFO("Hello, world! - Sincerely, thread 2"); + } + + t2_finished_logging = true; + lock_until_t2_finishes_logging.unlock(); + cv2.notify_one(); + }; + + std::thread t1(thread1_func); + std::thread t2(thread2_func); + + t1.join(); + t2.join(); +} -- cgit v1.2.3