diff options
| author | j-berman <justinberman@protonmail.com> | 2025-11-07 16:00:57 -0800 |
|---|---|---|
| committer | j-berman <justinberman@protonmail.com> | 2025-11-11 10:44:26 -0800 |
| commit | a83a46d60059a063ec953ba15f4cdcc2b3874440 (patch) | |
| tree | a152e55dfff1e3b4a84dd83ae8648d15e189a21d /tests/unit_tests | |
| parent | 3cc9d65c9374b541e64320052c933184944375ea (diff) | |
| download | monzero-core-a83a46d60059a063ec953ba15f4cdcc2b3874440.tar.gz monzero-core-a83a46d60059a063ec953ba15f4cdcc2b3874440.tar.xz monzero-core-a83a46d60059a063ec953ba15f4cdcc2b3874440.zip | |
Fix logging deadlock
Diffstat (limited to 'tests/unit_tests')
| -rw-r--r-- | tests/unit_tests/logging.cpp | 56 |
1 files changed, 56 insertions, 0 deletions
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 <condition_variable> +#include <mutex> +#include <thread> + #include <boost/filesystem.hpp> #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<std::mutex> lock_until_t1_starts_logger(mutex1); + std::unique_lock<std::mutex> 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<std::mutex> 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<std::mutex> 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(); +} |
