Merge pull request #797 from KLayout/issue-795

Issue 795
This commit is contained in:
Matthias Köfferlein 2021-05-13 13:05:37 +02:00 committed by GitHub
commit ea3bfabd90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 53 additions and 20 deletions

View File

@ -1486,16 +1486,20 @@ GuiApplication::process_events_impl (QEventLoop::ProcessEventsFlags flags, bool
{ {
if (mp_mw) { if (mp_mw) {
if (silent && tl::DeferredMethodScheduler::instance ()) { // prevent recursive process_events
tl::DeferredMethodScheduler::instance ()->enable (false); if (mp_mw->is_busy ()) {
return;
} }
#if QT_VERSION < 0x050000 if (silent) {
QApplication::syncX (); tl::DeferredMethodScheduler::enable (false);
#endif }
mp_mw->enter_busy_mode (true); mp_mw->enter_busy_mode (true);
try { try {
#if QT_VERSION < 0x050000
QApplication::syncX ();
#endif
QApplication::processEvents (flags); QApplication::processEvents (flags);
// Qt seems not to send posted UserEvents in some cases (e.g. in the unit test application with GLib? // Qt seems not to send posted UserEvents in some cases (e.g. in the unit test application with GLib?
// Glib not doing this without a main window visible?). Hence we do this explicitly here. // Glib not doing this without a main window visible?). Hence we do this explicitly here.
@ -1505,8 +1509,8 @@ GuiApplication::process_events_impl (QEventLoop::ProcessEventsFlags flags, bool
} }
mp_mw->enter_busy_mode (false); mp_mw->enter_busy_mode (false);
if (silent && tl::DeferredMethodScheduler::instance ()) { if (silent) {
tl::DeferredMethodScheduler::instance ()->enable (true); tl::DeferredMethodScheduler::enable (true);
} }
} }

View File

@ -41,7 +41,7 @@ namespace lay
// LogReceiver implementation // LogReceiver implementation
LogReceiver::LogReceiver (LogFile *file, int verbosity, void (LogFile::*method)(const std::string &, bool)) LogReceiver::LogReceiver (LogFile *file, int verbosity, void (LogFile::*method)(const std::string &, bool))
: mp_file (file), m_method (method), m_continued (false), m_verbosity (verbosity) : mp_file (file), m_method (method), m_verbosity (verbosity)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
@ -64,7 +64,9 @@ LogReceiver::puts (const char *s)
} }
if (*s == '\n') { if (*s == '\n') {
endl (); QMutexLocker locker (&m_lock);
(mp_file->*m_method) (m_text, true);
m_text.clear ();
++s; ++s;
} }
@ -78,9 +80,8 @@ LogReceiver::endl ()
{ {
if (tl::verbosity () >= m_verbosity) { if (tl::verbosity () >= m_verbosity) {
QMutexLocker locker (&m_lock); QMutexLocker locker (&m_lock);
(mp_file->*m_method) (m_text, m_continued); (mp_file->*m_method) (m_text, false);
m_text.clear (); m_text.clear ();
m_continued = true;
} }
} }
@ -99,9 +100,7 @@ LogReceiver::end ()
void void
LogReceiver::begin () LogReceiver::begin ()
{ {
QMutexLocker locker (&m_lock); // .. nothing yet ..
m_continued = false;
m_text.clear ();
} }
// ----------------------------------------------------------------- // -----------------------------------------------------------------
@ -254,6 +253,12 @@ LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continu
void void
LogFile::yield () LogFile::yield ()
{ {
#if 0
// This looked like a good idea, but in fact it introduces a hell lot of instability
// as it potentially leads to a recursion of events inside innocent functions. Remember
// that log output may be generated from every function called in response of an event
// and not every such function may process further events
bool can_yield = false; bool can_yield = false;
{ {
@ -268,10 +273,10 @@ LogFile::yield ()
// 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 // 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. // 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::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers, true /*silent*/);
} }
#endif
} }
int int

View File

@ -96,7 +96,6 @@ private:
LogFile *mp_file; LogFile *mp_file;
void (LogFile::*m_method)(const std::string &, bool); void (LogFile::*m_method)(const std::string &, bool);
std::string m_text; std::string m_text;
bool m_continued;
int m_verbosity; int m_verbosity;
QMutex m_lock; QMutex m_lock;
}; };

View File

@ -408,6 +408,14 @@ public:
m_busy = bm; m_busy = bm;
} }
/**
* @brief Returns true if the application is busy
*/
bool is_busy () const
{
return m_busy;
}
/** /**
* @brief Enable synchronous mode or disable it * @brief Enable synchronous mode or disable it
* *

View File

@ -396,6 +396,13 @@ BitmapRedrawThreadCanvas::initialize_plane (lay::CanvasPlane *plane, unsigned in
void void
BitmapRedrawThreadCanvas::to_image (const std::vector <lay::ViewOp> &view_ops, const lay::DitherPattern &dp, const lay::LineStyles &ls, QColor background, QColor foreground, QColor active, const lay::Drawings *drawings, QImage &img, unsigned int width, unsigned int height) BitmapRedrawThreadCanvas::to_image (const std::vector <lay::ViewOp> &view_ops, const lay::DitherPattern &dp, const lay::LineStyles &ls, QColor background, QColor foreground, QColor active, const lay::Drawings *drawings, QImage &img, unsigned int width, unsigned int height)
{ {
if (width > m_width) {
width = m_width;
}
if (height > m_height) {
height = m_height;
}
// convert the plane data to image data // convert the plane data to image data
bitmaps_to_image (view_ops, mp_plane_buffers, dp, ls, &img, width, height, true, &mutex ()); bitmaps_to_image (view_ops, mp_plane_buffers, dp, ls, &img, width, height, true, &mutex ());

View File

@ -67,7 +67,7 @@ verbosity ()
// Channel implementation // Channel implementation
Channel::Channel () Channel::Channel ()
: m_no_endl (false), m_active (false) : m_no_endl (false), m_active (false), m_in_yield (false)
{ {
// .. nothing else .. // .. nothing else ..
} }
@ -98,10 +98,19 @@ Channel::release_proxy ()
end (); end ();
m_active = false; m_active = false;
m_no_endl = false; m_no_endl = false;
bool in_yield = m_in_yield;
m_in_yield = true;
m_lock.unlock (); m_lock.unlock ();
// after we have released the lock we give the receivers an opportunity to process events // after we have released the lock we give the receivers an opportunity to process events. Note that we allow only one thread to yield
yield (); // at the same time and no recursive yields.
if (! in_yield) {
yield ();
// this should be atomic, but execution reordering may place it before yield(). Hence the lock.
m_lock.lock ();
m_in_yield = false;
m_lock.unlock ();
}
} }
ChannelEndl endl; ChannelEndl endl;

View File

@ -154,6 +154,7 @@ private:
bool m_no_endl; bool m_no_endl;
bool m_active; bool m_active;
bool m_in_yield;
}; };
/** /**