mirror of
https://github.com/monero-project/monero.git
synced 2025-12-05 20:40:22 -08:00
Fix logging deadlock
This commit is contained in:
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "easylogging++.h"
|
#include "easylogging++.h"
|
||||||
@@ -40,9 +41,15 @@
|
|||||||
#define MAX_LOG_FILE_SIZE 104850000 // 100 MB - 7600 bytes
|
#define MAX_LOG_FILE_SIZE 104850000 // 100 MB - 7600 bytes
|
||||||
#define MAX_LOG_FILES 10
|
#define MAX_LOG_FILES 10
|
||||||
|
|
||||||
|
#define LOG_TO_STRING(x) \
|
||||||
|
std::stringstream ss; \
|
||||||
|
ss << x; \
|
||||||
|
const std::string str = ss.str();
|
||||||
|
|
||||||
#define MCLOG_TYPE(level, cat, color, type, x) do { \
|
#define MCLOG_TYPE(level, cat, color, type, x) do { \
|
||||||
if (el::Loggers::allowed(level, cat)) { \
|
if (el::Loggers::allowed(level, cat)) { \
|
||||||
el::base::Writer(level, color, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << x; \
|
LOG_TO_STRING(x); \
|
||||||
|
el::base::Writer(level, color, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << str; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@@ -91,7 +98,8 @@
|
|||||||
do { \
|
do { \
|
||||||
if (el::Loggers::allowed(level, cat)) { \
|
if (el::Loggers::allowed(level, cat)) { \
|
||||||
init; \
|
init; \
|
||||||
el::base::Writer(level, color, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << x; \
|
LOG_TO_STRING(x); \
|
||||||
|
el::base::Writer(level, color, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << str; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
#define MIDEBUG(init, x) IFLOG(el::Level::Debug, MONERO_DEFAULT_LOG_CATEGORY, el::Color::Default, el::base::DispatchAction::NormalLog, init, x)
|
#define MIDEBUG(init, x) IFLOG(el::Level::Debug, MONERO_DEFAULT_LOG_CATEGORY, el::Color::Default, el::base::DispatchAction::NormalLog, init, x)
|
||||||
|
|||||||
3
external/easylogging++/easylogging++.cc
vendored
3
external/easylogging++/easylogging++.cc
vendored
@@ -3065,8 +3065,9 @@ void Writer::triggerDispatch(void) {
|
|||||||
}
|
}
|
||||||
if (m_proceed && m_level == Level::Fatal
|
if (m_proceed && m_level == Level::Fatal
|
||||||
&& !ELPP->hasFlag(LoggingFlag::DisableApplicationAbortOnFatalLog)) {
|
&& !ELPP->hasFlag(LoggingFlag::DisableApplicationAbortOnFatalLog)) {
|
||||||
|
const std::string str = "Aborting application. Reason: Fatal log at [" + std::string(m_file) + ":" + std::to_string(m_line) + "]";
|
||||||
base::Writer(Level::Warning, Color::Default, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId)
|
base::Writer(Level::Warning, Color::Default, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId)
|
||||||
<< "Aborting application. Reason: Fatal log at [" << m_file << ":" << m_line << "]";
|
<< str;
|
||||||
std::stringstream reasonStream;
|
std::stringstream reasonStream;
|
||||||
reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]"
|
reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]"
|
||||||
<< " If you wish to disable 'abort on fatal log' please use "
|
<< " If you wish to disable 'abort on fatal log' please use "
|
||||||
|
|||||||
27
external/easylogging++/easylogging++.h
vendored
27
external/easylogging++/easylogging++.h
vendored
@@ -3275,9 +3275,7 @@ class Writer : base::NoCopy {
|
|||||||
processDispatch();
|
processDispatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
Writer& operator<<(const std::string &log) {
|
||||||
inline typename std::enable_if<std::is_integral<T>::value, Writer&>::type
|
|
||||||
operator<<(T log) {
|
|
||||||
#if ELPP_LOGGING_ENABLED
|
#if ELPP_LOGGING_ENABLED
|
||||||
if (m_proceed) {
|
if (m_proceed) {
|
||||||
m_messageBuilder << log;
|
m_messageBuilder << log;
|
||||||
@@ -3286,26 +3284,6 @@ class Writer : base::NoCopy {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline typename std::enable_if<!std::is_integral<T>::value, Writer&>::type
|
|
||||||
operator<<(const T& log) {
|
|
||||||
#if ELPP_LOGGING_ENABLED
|
|
||||||
if (m_proceed) {
|
|
||||||
m_messageBuilder << log;
|
|
||||||
}
|
|
||||||
#endif // ELPP_LOGGING_ENABLED
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Writer& operator<<(std::ostream& (*log)(std::ostream&)) {
|
|
||||||
#if ELPP_LOGGING_ENABLED
|
|
||||||
if (m_proceed) {
|
|
||||||
m_messageBuilder << log;
|
|
||||||
}
|
|
||||||
#endif // ELPP_LOGGING_ENABLED
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline operator bool() {
|
inline operator bool() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -3622,8 +3600,9 @@ class DefaultPerformanceTrackingCallback : public PerformanceTrackingCallback {
|
|||||||
ss << ELPP_LITERAL("]");
|
ss << ELPP_LITERAL("]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const std::string str = ss.str();
|
||||||
el::base::Writer(m_data->performanceTracker()->level(), m_data->file(), m_data->line(), m_data->func()).construct(1,
|
el::base::Writer(m_data->performanceTracker()->level(), m_data->file(), m_data->line(), m_data->func()).construct(1,
|
||||||
m_data->loggerId().c_str()) << ss.str();
|
m_data->loggerId().c_str()) << str;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
const PerformanceTrackingData* m_data;
|
const PerformanceTrackingData* m_data;
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
#include "net/network_throttle-detail.hpp"
|
#include "net/network_throttle-detail.hpp"
|
||||||
#include "common/pruning.h"
|
#include "common/pruning.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
#include "misc_log_ex.h"
|
||||||
|
|
||||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.cn"
|
#define MONERO_DEFAULT_LOG_CATEGORY "net.cn"
|
||||||
@@ -59,8 +60,10 @@
|
|||||||
const char *cat = "net.p2p.msg"; \
|
const char *cat = "net.p2p.msg"; \
|
||||||
if (ELPP->vRegistry()->allowed(level, cat)) { \
|
if (ELPP->vRegistry()->allowed(level, cat)) { \
|
||||||
init; \
|
init; \
|
||||||
if (test) \
|
if (test) { \
|
||||||
el::base::Writer(level, el::Color::Default, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(cat) << x; \
|
LOG_TO_STRING(x); \
|
||||||
|
el::base::Writer(level, el::Color::Default, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(cat) << str; \
|
||||||
|
} \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,10 @@
|
|||||||
//
|
//
|
||||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
// 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 <boost/filesystem.hpp>
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "file_io_utils.h"
|
#include "file_io_utils.h"
|
||||||
@@ -251,3 +255,55 @@ TEST(logging, empty_configuration)
|
|||||||
EXPECT_NO_THROW(log1.configure(cfg));
|
EXPECT_NO_THROW(log1.configure(cfg));
|
||||||
EXPECT_EQ(log1.typedConfigurations()->filename(el::Level::Info), "");
|
EXPECT_EQ(log1.typedConfigurations()->filename(el::Level::Info), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user