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 (silent && tl::DeferredMethodScheduler::instance ()) {
tl::DeferredMethodScheduler::instance ()->enable (false);
// prevent recursive process_events
if (mp_mw->is_busy ()) {
return;
}
#if QT_VERSION < 0x050000
QApplication::syncX ();
#endif
if (silent) {
tl::DeferredMethodScheduler::enable (false);
}
mp_mw->enter_busy_mode (true);
try {
#if QT_VERSION < 0x050000
QApplication::syncX ();
#endif
QApplication::processEvents (flags);
// 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.
@ -1505,8 +1509,8 @@ GuiApplication::process_events_impl (QEventLoop::ProcessEventsFlags flags, bool
}
mp_mw->enter_busy_mode (false);
if (silent && tl::DeferredMethodScheduler::instance ()) {
tl::DeferredMethodScheduler::instance ()->enable (true);
if (silent) {
tl::DeferredMethodScheduler::enable (true);
}
}

View File

@ -41,7 +41,7 @@ namespace lay
// LogReceiver implementation
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 ..
}
@ -64,7 +64,9 @@ LogReceiver::puts (const char *s)
}
if (*s == '\n') {
endl ();
QMutexLocker locker (&m_lock);
(mp_file->*m_method) (m_text, true);
m_text.clear ();
++s;
}
@ -78,9 +80,8 @@ LogReceiver::endl ()
{
if (tl::verbosity () >= m_verbosity) {
QMutexLocker locker (&m_lock);
(mp_file->*m_method) (m_text, m_continued);
(mp_file->*m_method) (m_text, false);
m_text.clear ();
m_continued = true;
}
}
@ -99,9 +100,7 @@ LogReceiver::end ()
void
LogReceiver::begin ()
{
QMutexLocker locker (&m_lock);
m_continued = false;
m_text.clear ();
// .. nothing yet ..
}
// -----------------------------------------------------------------
@ -254,6 +253,12 @@ LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continu
void
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;
{
@ -268,10 +273,10 @@ LogFile::yield ()
// 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) {
lay::ApplicationBase::instance ()->process_events (QEventLoop::AllEvents);
lay::ApplicationBase::instance ()->process_events (QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers, true /*silent*/);
}
#endif
}
int

View File

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

View File

@ -408,6 +408,14 @@ public:
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
*

View File

@ -396,6 +396,13 @@ BitmapRedrawThreadCanvas::initialize_plane (lay::CanvasPlane *plane, unsigned in
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)
{
if (width > m_width) {
width = m_width;
}
if (height > m_height) {
height = m_height;
}
// convert the plane data to image data
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::Channel ()
: m_no_endl (false), m_active (false)
: m_no_endl (false), m_active (false), m_in_yield (false)
{
// .. nothing else ..
}
@ -98,10 +98,19 @@ Channel::release_proxy ()
end ();
m_active = false;
m_no_endl = false;
bool in_yield = m_in_yield;
m_in_yield = true;
m_lock.unlock ();
// after we have released the lock we give the receivers an opportunity to process events
yield ();
// after we have released the lock we give the receivers an opportunity to process events. Note that we allow only one thread to 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;

View File

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