Skip to content

Commit cee5719

Browse files
committed
simplify locking and avoid Initialize/Shutdown deadlock
- Use a single global mutex to guard logging state initialization/shutdown. - Introduce ShutdownUnlocked() helper to avoid nested lock acquisition.
1 parent 40582ca commit cee5719

2 files changed

Lines changed: 25 additions & 24 deletions

File tree

src/utils/logger_backend.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,6 @@ LoggerBackend& LoggerBackend::operator=(LoggerBackend&& other) noexcept {
195195

196196
void LoggerBackend::Log(LogLevel level, const std::string& message,
197197
const LogContext& context, LogColor color) {
198-
std::lock_guard<std::mutex> lock(log_mutex_);
199-
200198
// Update statistics
201199
stats_.total_messages++;
202200
if (static_cast<size_t>(level) < kNumLogLevels) {

src/utils/logging.cpp

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -547,12 +547,27 @@ namespace {
547547
// Main Logging Interface Implementation
548548
//-----------------------------------------------------------------------------
549549

550+
// Internal helper for cleanup (no locking to avoid deadlock with stream capture).
551+
static void ShutdownUnlocked() {
552+
// Restore original stream buffers
553+
if (g_orig_cout) {
554+
std::cout.rdbuf(g_orig_cout);
555+
}
556+
if (g_orig_cerr) {
557+
std::cerr.rdbuf(g_orig_cerr);
558+
}
559+
g_cout_capture.reset();
560+
g_cerr_capture.reset();
561+
562+
g_cli_logger.reset();
563+
g_backend.reset();
564+
g_initialized = false;
565+
}
566+
550567
bool Initialize(const LoggingConfig& config) {
551-
std::lock_guard<std::mutex> lock(g_logging_mutex);
552-
553568
// Shutdown existing logging if any
554569
if (g_initialized) {
555-
Shutdown();
570+
ShutdownUnlocked();
556571
}
557572

558573
g_backend = std::make_shared<LoggerBackend>(config);
@@ -572,36 +587,25 @@ bool Initialize(const LoggingConfig& config) {
572587
std::cout.rdbuf(g_cout_capture.get());
573588
std::cerr.rdbuf(g_cerr_capture.get());
574589
// Ensure restoration happens even if user code forgets to call Shutdown.
575-
std::atexit([](){ Shutdown(); });
590+
// Note: Only register once to avoid multiple atexit handlers
591+
static bool atexit_registered = false;
592+
if (!atexit_registered) {
593+
std::atexit([](){ Shutdown(); });
594+
atexit_registered = true;
595+
}
576596
g_initialized = true;
577597
return true;
578598
}
579599

580600
void Shutdown() {
581-
std::lock_guard<std::mutex> lock(g_logging_mutex);
582-
583-
// Restore original stream buffers
584-
if (g_orig_cout) {
585-
std::cout.rdbuf(g_orig_cout);
586-
}
587-
if (g_orig_cerr) {
588-
std::cerr.rdbuf(g_orig_cerr);
589-
}
590-
g_cout_capture.reset();
591-
g_cerr_capture.reset();
592-
593-
g_cli_logger.reset();
594-
g_backend.reset();
595-
g_initialized = false;
601+
ShutdownUnlocked();
596602
}
597603

598604
static std::shared_ptr<CLILogger> GetCLILogger() {
599-
std::lock_guard<std::mutex> lock(g_logging_mutex);
600605
return g_cli_logger;
601606
}
602607

603608
bool IsInitialized() noexcept {
604-
std::lock_guard<std::mutex> lock(g_logging_mutex);
605609
return g_initialized && g_backend != nullptr;
606610
}
607611

@@ -788,7 +792,6 @@ void LogError(const std::string& message) {
788792
}
789793

790794
bool IsDebugEnabled() noexcept {
791-
std::lock_guard<std::mutex> lock(g_logging_mutex);
792795
if (!g_initialized || !g_backend) return false;
793796
const auto& cfg = g_backend->GetConfig();
794797
// Enable if explicitly requested or if either sink is set to Debug threshold

0 commit comments

Comments
 (0)