55
66#include < logging.h>
77#include < utiltime.h>
8+ #include < mutex>
9+ #include < condition_variable>
10+ #include < thread>
811
912const char * const DEFAULT_DEBUGLOGFILE = " debug.log" ;
1013
@@ -25,9 +28,75 @@ BCLog::Logger* const g_logger = new BCLog::Logger();
2528
2629bool fLogIPs = DEFAULT_LOGIPS;
2730
31+ #define LOG_LINE_BUFFER_SIZE 128
32+ static std::atomic_int g_next_pending_log_line (0 );
33+ static std::atomic_int g_next_undef_log_line (0 );
34+ static std::atomic_bool g_debug_log_flush_thread_exit;
35+ static std::mutex g_log_buff_mutex;
36+ static std::condition_variable g_log_buff_cv;
37+ static std::array<std::string, LOG_LINE_BUFFER_SIZE> g_debug_log_buff;
38+ static std::unique_ptr<std::thread> g_buff_flush_thread; // non-ptr fails to build in LTO?
39+ static std::once_flag g_buff_flush_thread_started;
40+
41+ static void DebugLogFlush ()
42+ {
43+ while (true ) {
44+ int next_pending_log = g_next_pending_log_line.load (std::memory_order_acquire);
45+ int next_undef_log = g_next_undef_log_line.load (std::memory_order_acquire);
46+ if (next_pending_log == next_undef_log) {
47+ if (g_debug_log_flush_thread_exit) return ;
48+ std::unique_lock<std::mutex> lock (g_log_buff_mutex);
49+ while (next_pending_log == next_undef_log && !g_debug_log_flush_thread_exit) {
50+ g_log_buff_cv.wait (lock);
51+ next_pending_log = g_next_pending_log_line.load (std::memory_order_acquire);
52+ next_undef_log = g_next_undef_log_line.load (std::memory_order_acquire);
53+ }
54+ }
55+
56+ while (next_pending_log != next_undef_log) {
57+ fwrite (g_debug_log_buff[next_pending_log].data (), 1 , g_debug_log_buff[next_pending_log].size (), g_logger->m_fileout );
58+ g_debug_log_buff[next_pending_log].clear ();
59+ g_debug_log_buff[next_pending_log].shrink_to_fit ();
60+ next_pending_log = (next_pending_log + 1 ) % LOG_LINE_BUFFER_SIZE;
61+ g_next_pending_log_line.store (next_pending_log, std::memory_order_release);
62+ g_log_buff_cv.notify_one ();
63+ }
64+ }
65+ }
66+
67+ void StopDebugLogFlushThread () {
68+ g_debug_log_flush_thread_exit = true ;
69+ {
70+ std::unique_lock<std::mutex> lock (g_log_buff_mutex);
71+ g_log_buff_cv.notify_all ();
72+ }
73+ if (g_buff_flush_thread) {
74+ g_buff_flush_thread->join ();
75+ }
76+ }
77+
2878static int FileWriteStr (const std::string &str, FILE *fp)
2979{
30- return fwrite (str.data (), 1 , str.size (), fp);
80+ std::call_once (g_buff_flush_thread_started, [] {
81+ g_buff_flush_thread.reset (new std::thread (DebugLogFlush));
82+ });
83+
84+ std::unique_lock<std::mutex> lock (g_log_buff_mutex);
85+ int next_pending_log = g_next_pending_log_line.load (std::memory_order_acquire);
86+ int next_undef_log = g_next_undef_log_line.load (std::memory_order_acquire);
87+ while (next_pending_log == (next_undef_log + 1 ) % LOG_LINE_BUFFER_SIZE && !g_debug_log_flush_thread_exit) {
88+ g_log_buff_cv.wait (lock);
89+ next_pending_log = g_next_pending_log_line.load (std::memory_order_acquire);
90+ next_undef_log = g_next_undef_log_line.load (std::memory_order_acquire);
91+ }
92+ if (g_debug_log_flush_thread_exit) {
93+ return fwrite (str.data (), 1 , str.size (), fp);
94+ } else {
95+ g_debug_log_buff[next_undef_log] = str;
96+ g_next_undef_log_line.store ((next_undef_log + 1 ) % LOG_LINE_BUFFER_SIZE, std::memory_order_release);
97+ g_log_buff_cv.notify_all ();
98+ return str.size ();
99+ }
31100}
32101
33102bool BCLog::Logger::OpenDebugLog ()
@@ -198,6 +267,7 @@ std::string BCLog::Logger::LogTimestampStr(const std::string &str)
198267 return strStamped;
199268}
200269
270+
201271void BCLog::Logger::LogPrintStr (const std::string &str)
202272{
203273 std::string strTimestamped = LogTimestampStr (str);
0 commit comments