Avoid a deadlock in the logger system

This commit is contained in:
Matthias Koefferlein 2021-03-23 22:45:45 +01:00
parent 536681f5e1
commit fa1719acc3
7 changed files with 69 additions and 18 deletions

View File

@ -84,6 +84,12 @@ LogReceiver::endl ()
} }
} }
void
LogReceiver::yield ()
{
mp_file->yield ();
}
void void
LogReceiver::end () LogReceiver::end ()
{ {
@ -223,30 +229,36 @@ LogFile::max_entries () const
void void
LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continued) LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continued)
{
QMutexLocker locker (&m_lock);
if (m_max_entries == 0) {
return;
}
if (m_messages.size () >= m_max_entries) {
m_messages.pop_front ();
}
if (mode == LogFileEntry::Warning || mode == LogFileEntry::WarningContinued) {
m_has_warnings = true;
} else if (mode == LogFileEntry::Error || mode == LogFileEntry::ErrorContinued) {
m_has_errors = true;
}
m_messages.push_back (LogFileEntry (mode, msg, continued));
++m_generation_id;
}
void
LogFile::yield ()
{ {
bool can_yield = false; bool can_yield = false;
{ {
QMutexLocker locker (&m_lock); QMutexLocker locker (&m_lock);
if (m_max_entries == 0) {
return;
}
if (m_messages.size () >= m_max_entries) {
m_messages.pop_front ();
}
if (mode == LogFileEntry::Warning || mode == LogFileEntry::WarningContinued) {
m_has_warnings = true;
} else if (mode == LogFileEntry::Error || mode == LogFileEntry::ErrorContinued) {
m_has_errors = true;
}
m_messages.push_back (LogFileEntry (mode, msg, continued));
++m_generation_id;
if (lay::ApplicationBase::instance ()->qapp_gui () && QThread::currentThread () == lay::ApplicationBase::instance ()->qapp_gui ()->thread () && (tl::Clock::current () - m_last_yield).seconds () > 0.1) { if (lay::ApplicationBase::instance ()->qapp_gui () && QThread::currentThread () == lay::ApplicationBase::instance ()->qapp_gui ()->thread () && (tl::Clock::current () - m_last_yield).seconds () > 0.1) {
m_last_yield = tl::Clock::current (); m_last_yield = tl::Clock::current ();
can_yield = true; can_yield = true;
@ -254,6 +266,9 @@ LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continu
} }
// use this opportunity to process events // use this opportunity to process events
// NOTE: as process events may trigger further log output, it's necessary to do process events outside any other
// method (e.g. add) which is subject to locking. Hence we avoid deadlocks.
// We accept the risk of recursion inside process_events as we have a timeout before accepting new yield calls.
if (can_yield) { if (can_yield) {
lay::ApplicationBase::instance ()->process_events (QEventLoop::AllEvents); lay::ApplicationBase::instance ()->process_events (QEventLoop::AllEvents);
} }

View File

@ -90,6 +90,7 @@ protected:
virtual void endl (); virtual void endl ();
virtual void end (); virtual void end ();
virtual void begin (); virtual void begin ();
virtual void yield ();
private: private:
LogFile *mp_file; LogFile *mp_file;
@ -193,6 +194,11 @@ public slots:
return m_log_receiver; return m_log_receiver;
} }
/**
* @brief Implementation of post-log action
*/
void yield ();
/** /**
* @brief Sets the maximum number of entries to show * @brief Sets the maximum number of entries to show
* *

View File

@ -1112,6 +1112,7 @@ protected:
virtual void endl () { mp_rec->errlog_endl (); } virtual void endl () { mp_rec->errlog_endl (); }
virtual void end () { mp_rec->errlog_end (); } virtual void end () { mp_rec->errlog_end (); }
virtual void begin () { mp_rec->errlog_begin (); } virtual void begin () { mp_rec->errlog_begin (); }
virtual void yield () { }
private: private:
Recorder *mp_rec; Recorder *mp_rec;

View File

@ -99,6 +99,9 @@ Channel::release_proxy ()
m_active = false; m_active = false;
m_no_endl = false; m_no_endl = false;
m_lock.unlock (); m_lock.unlock ();
// after we have released the lock we give the receivers an opportunity to process events
yield ();
} }
ChannelEndl endl; ChannelEndl endl;
@ -160,6 +163,18 @@ LogTee::puts (const char *s)
} }
} }
void
LogTee::yield ()
{
try {
for (tl::weak_collection<tl::Channel>::iterator c = m_channels.begin (); c != m_channels.end (); ++c) {
c->yield ();
}
} catch (...) {
// ignore exceptions here
}
}
void void
LogTee::endl () LogTee::endl ()
{ {
@ -270,6 +285,7 @@ protected:
virtual void endl (); virtual void endl ();
virtual void end (); virtual void end ();
virtual void begin (); virtual void begin ();
virtual void yield () { }
private: private:
int m_verbosity; int m_verbosity;
@ -342,6 +358,7 @@ protected:
virtual void endl (); virtual void endl ();
virtual void end (); virtual void end ();
virtual void begin (); virtual void begin ();
virtual void yield () { }
private: private:
bool m_colorized; bool m_colorized;
@ -406,6 +423,7 @@ protected:
virtual void endl (); virtual void endl ();
virtual void end (); virtual void end ();
virtual void begin (); virtual void begin ();
virtual void yield () { }
private: private:
bool m_colorized; bool m_colorized;

View File

@ -136,6 +136,7 @@ protected:
virtual void endl () = 0; virtual void endl () = 0;
virtual void end () = 0; virtual void end () = 0;
virtual void begin () = 0; virtual void begin () = 0;
virtual void yield () = 0;
tl::Mutex m_lock; tl::Mutex m_lock;
@ -265,6 +266,7 @@ protected:
virtual void endl (); virtual void endl ();
virtual void end (); virtual void end ();
virtual void begin (); virtual void begin ();
virtual void yield ();
private: private:
tl::weak_collection<tl::Channel> m_channels; tl::weak_collection<tl::Channel> m_channels;

View File

@ -208,6 +208,7 @@ protected:
virtual void endl (); virtual void endl ();
virtual void end (); virtual void end ();
virtual void begin (); virtual void begin ();
virtual void yield () { }
private: private:
std::ostringstream m_text; std::ostringstream m_text;

View File

@ -75,6 +75,8 @@ protected:
// .. nothing yet .. // .. nothing yet ..
} }
virtual void yield () { }
private: private:
int m_verbosity; int m_verbosity;
}; };
@ -108,6 +110,8 @@ protected:
{ {
TestConsole::instance ()->begin_warn (); TestConsole::instance ()->begin_warn ();
} }
virtual void yield () { }
}; };
class ErrorChannel : public tl::Channel class ErrorChannel : public tl::Channel
@ -139,6 +143,8 @@ protected:
{ {
TestConsole::instance ()->begin_error (); TestConsole::instance ()->begin_error ();
} }
virtual void yield () { }
}; };
class CtrlChannel : public tl::Channel class CtrlChannel : public tl::Channel
@ -180,6 +186,8 @@ protected:
} }
} }
virtual void yield () { }
private: private:
bool m_with_xml; bool m_with_xml;
}; };