[Libreoffice-commits] core.git: vcl/inc vcl/source

Jan-Marek Glogowski glogow at fbihome.de
Thu Dec 21 08:18:21 UTC 2017


 vcl/inc/salusereventlist.hxx        |    8 ++++---
 vcl/source/app/salusereventlist.cxx |   41 +++++++++++++++++++++++-------------
 2 files changed, 32 insertions(+), 17 deletions(-)

New commits:
commit 5469ac13b13e458904900539e6542d4a83d44c4e
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Fri Dec 15 13:39:32 2017 +0100

    Prevent out-of-order LO event processing
    
    There's a callback processing loop, introduced by
    a7c84375db517769035080c8fed33b2f303fc42f, which releases the
    SolarMutex and is triggered by a queued user event. Such a
    scenario can easily be reproduced by any LOK client resulting in
    hitting the empty user event processing list assertion.
    I'm not sure this should be handled via LO events at all.
    
    So this - again - gets rid of the the assertion and tries to
    prevent processing the user events out-of-order.
    In the case of giving up the SolarMutex while processing a user
    event an other thread or even nested loop can "steal" the user
    event list and continue processing.
    
    Most VCL backends run the event loop just in the main process,
    so for them this scenario is guaranteed. But the headless
    backend - running without UI or from LOK - is still allowed to
    process events in any thread. This is harder to fix and probably
    should use the same solution the gtk* backends use.
    
    This also changes the dequeues into lists to use splice for
    appending them.
    
    Change-Id: Id4a93a01dea415271ad96098830f18f06d4a75b9
    Reviewed-on: https://gerrit.libreoffice.org/46550
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Henry Castro <hcastro at collabora.com>
    Reviewed-by: pranavk <pranavk at collabora.co.uk>
    Tested-by: pranavk <pranavk at collabora.co.uk>

diff --git a/vcl/inc/salusereventlist.hxx b/vcl/inc/salusereventlist.hxx
index 123b9dadd1c7..52a195a68f82 100644
--- a/vcl/inc/salusereventlist.hxx
+++ b/vcl/inc/salusereventlist.hxx
@@ -23,10 +23,11 @@
 #include <sal/config.h>
 #include <vcl/dllapi.h>
 #include <osl/mutex.hxx>
+#include <osl/thread.hxx>
 
 #include <assert.h>
 
-#include <deque>
+#include <list>
 #include <unordered_set>
 
 class SalFrame;
@@ -65,10 +66,11 @@ public:
 
 protected:
     mutable osl::Mutex         m_aUserEventsMutex;
-    std::deque< SalUserEvent > m_aUserEvents;
-    std::deque< SalUserEvent > m_aProcessingUserEvents;
+    std::list< SalUserEvent >  m_aUserEvents;
+    std::list< SalUserEvent >  m_aProcessingUserEvents;
     bool                       m_bAllUserEventProcessedSignaled;
     SalFrameSet                m_aFrames;
+    oslThreadIdentifier        m_aProcessingThread;
 
     virtual void ProcessEvent( SalUserEvent aEvent ) = 0;
     virtual void TriggerUserEventProcessing() = 0;
diff --git a/vcl/source/app/salusereventlist.cxx b/vcl/source/app/salusereventlist.cxx
index 50ef1f892002..bd58a508464f 100644
--- a/vcl/source/app/salusereventlist.cxx
+++ b/vcl/source/app/salusereventlist.cxx
@@ -33,6 +33,7 @@
 
 SalUserEventList::SalUserEventList()
     : m_bAllUserEventProcessedSignaled( true )
+    , m_aProcessingThread(0)
 {
 }
 
@@ -57,30 +58,40 @@ void SalUserEventList::eraseFrame( SalFrame* pFrame )
 bool SalUserEventList::DispatchUserEvents( bool bHandleAllCurrentEvents )
 {
     bool bWasEvent = false;
+    oslThreadIdentifier aCurId = osl::Thread::getCurrentIdentifier();
 
+    DBG_TESTSOLARMUTEX();
+    // cleared after we pop a single event and are save in the 2nd guard.
+    // this way we guarantee to process at least one event, if available.
+    osl::ResettableMutexGuard aResettableGuard(m_aUserEventsMutex);
+
+    if (!m_aUserEvents.empty())
     {
-        osl::MutexGuard aGuard( m_aUserEventsMutex );
-        assert( m_aProcessingUserEvents.empty() );
-        if( ! m_aUserEvents.empty() )
+        if (bHandleAllCurrentEvents)
         {
-            if( bHandleAllCurrentEvents )
-                m_aProcessingUserEvents.swap( m_aUserEvents );
+            if (m_aProcessingUserEvents.empty())
+                m_aProcessingUserEvents.swap(m_aUserEvents);
             else
-            {
-                m_aProcessingUserEvents.push_back( m_aUserEvents.front() );
-                m_aUserEvents.pop_front();
-            }
-            bWasEvent = true;
+                m_aProcessingUserEvents.splice(m_aProcessingUserEvents.end(), m_aUserEvents);
+        }
+        else if (m_aProcessingUserEvents.empty())
+        {
+            m_aProcessingUserEvents.push_back( m_aUserEvents.front() );
+            m_aUserEvents.pop_front();
         }
     }
 
-    if( bWasEvent )
+    if (HasUserEvents())
     {
+        bWasEvent = true;
+        m_aProcessingThread = aCurId;
+
         SalUserEvent aEvent( nullptr, nullptr, SalEvent::NONE );
         do {
             {
-                osl::MutexGuard aGuard( m_aUserEventsMutex );
-                if ( m_aProcessingUserEvents.empty() )
+                osl::MutexGuard aGuard(m_aUserEventsMutex);
+                aResettableGuard.clear();
+                if (m_aProcessingUserEvents.empty() || aCurId != m_aProcessingThread)
                     break;
                 aEvent = m_aProcessingUserEvents.front();
                 m_aProcessingUserEvents.pop_front();
@@ -113,11 +124,13 @@ bool SalUserEventList::DispatchUserEvents( bool bHandleAllCurrentEvents )
                 SAL_WARN("vcl", "Uncaught exception during DispatchUserEvents!");
                 std::abort();
             }
+            if (!bHandleAllCurrentEvents)
+                break;
         }
         while( true );
+        aResettableGuard.reset();
     }
 
-    osl::MutexGuard aGuard( m_aUserEventsMutex );
     if ( !m_bAllUserEventProcessedSignaled && !HasUserEvents() )
     {
         m_bAllUserEventProcessedSignaled = true;


More information about the Libreoffice-commits mailing list