[Libreoffice-commits] core.git: Branch 'private/jmux/scheduler-fixes' - 152 commits - android/Bootstrap android/source basic/source binaryurp/source bridges/inc bridges/source canvas/Library_canvastools.mk canvas/source chart2/source comphelper/source compilerplugins/clang config_host.mk.in configure.ac connectivity/inc cui/source dbaccess/Module_dbaccess.mk dbaccess/source desktop/source desktop/unx download.lst dtrans/test editeng/source emfio/inc external/libepubgen external/libqxp external/Module_external.mk filter/Configuration_filter.mk filter/source framework/source .gitignore hwpfilter/qa hwpfilter/source icon-themes/breeze icon-themes/breeze_dark icon-themes/breeze_svg include/basic include/comphelper include/editeng include/filter include/oox include/osl include/sal include/svl include/svtools include/svx include/test include/tools include/ucbhelper include/vcl jvmfwk/plugins Makefile.fetch odk/CustomTarget_build-examples.mk officecfg/registry onlineupdate/source oox/source opencl/sourc e qadevOOo/Jar_OOoRunner.mk qadevOOo/objdsc qadevOOo/tests reportdesign/source RepositoryExternal.mk sal/Library_sal.mk sal/osl sal/util sccomp/CppunitTest_sccomp_lpsolver.mk sccomp/CppunitTest_sccomp_solver.mk sccomp/Module_sccomp.mk sccomp/qa sc/CppunitTest_sc_datapilotitemobj.mk sc/inc sc/Library_sc.mk sc/Module_sc.mk scp2/inc scp2/source sc/qa sc/source sd/inc sd/qa sd/source sfx2/source soltools/mkdepend starmath/source stoc/source stoc/test svl/source svtools/inc svtools/source svx/inc svx/source sw/inc sw/qa sw/sdi sw/source test/Library_subsequenttest.mk test/source toolkit/source tools/source unotools/source uui/source vcl/android vcl/headless vcl/inc vcl/ios vcl/Library_vcl.mk vcl/osx vcl/qa vcl/README.scheduler vcl/source vcl/unx vcl/win writerfilter/source writerperfect/Library_wpftdraw.mk writerperfect/Module_writerperfect.mk writerperfect/qa writerperfect/source

Jan-Marek Glogowski glogow at fbihome.de
Tue Aug 29 18:28:05 UTC 2017


Rebased ref, commits from common ancestor:
commit 3834d1d99a40af351991d5449eb1c74a4f9f3526
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Tue Aug 29 10:29:51 2017 +0200

    Change Reschedule default and drop nMaxEvents
    
    Normally you just want to process all pending events, so make
    it the default. nMaxEvents was never implemented on OSX and
    for the KDE4 backend it's actually impossible to handle single
    events.
    
    Change-Id: I1ab95df89b079cc8c6319a808194fe3127144d1c

diff --git a/basic/source/runtime/methods1.cxx b/basic/source/runtime/methods1.cxx
index a67de7407a6b..47c531efafc8 100644
--- a/basic/source/runtime/methods1.cxx
+++ b/basic/source/runtime/methods1.cxx
@@ -615,7 +615,7 @@ void SbRtl_DoEvents(StarBASIC *, SbxArray & rPar, bool)
 // basic runtime pcode ( on a timed basis )
     // always return 0
     rPar.Get(0)->PutInteger( 0 );
-    Application::Reschedule( true );
+    Application::Reschedule();
 }
 
 void SbRtl_GetGUIVersion(StarBASIC *, SbxArray & rPar, bool)
diff --git a/basic/source/runtime/runtime.cxx b/basic/source/runtime/runtime.cxx
index 5d9764fa7581..cee3643a6c3e 100644
--- a/basic/source/runtime/runtime.cxx
+++ b/basic/source/runtime/runtime.cxx
@@ -733,7 +733,7 @@ bool SbiRuntime::Step()
             sal_uInt32 nTime = osl_getGlobalTimer();
             if (nTime - m_nLastTime > 5 ) // 20 ms
             {
-                Application::Reschedule();
+                Application::Reschedule( false );
                 m_nLastTime = nTime;
             }
         }
diff --git a/cui/source/dialogs/cuigaldlg.cxx b/cui/source/dialogs/cuigaldlg.cxx
index 599ec984b70f..c098f875e48a 100644
--- a/cui/source/dialogs/cuigaldlg.cxx
+++ b/cui/source/dialogs/cuigaldlg.cxx
@@ -483,8 +483,7 @@ IMPL_LINK( ActualizeProgress, TimeoutHdl, Timer*, _pTimer, void)
 
 IMPL_LINK( ActualizeProgress, ActualizeHdl, const INetURLObject&, rURL, void )
 {
-    for( long i = 0; i < 128; i++ )
-        Application::Reschedule();
+    Application::Reschedule();
 
     Flush();
 
diff --git a/framework/source/helper/statusindicatorfactory.cxx b/framework/source/helper/statusindicatorfactory.cxx
index 2d5563d1213c..dab31d0d6912 100644
--- a/framework/source/helper/statusindicatorfactory.cxx
+++ b/framework/source/helper/statusindicatorfactory.cxx
@@ -519,7 +519,7 @@ void StatusIndicatorFactory::impl_reschedule(bool bForce)
 
         {
             SolarMutexGuard g;
-            Application::Reschedule(true);
+            Application::Reschedule();
         }
 
         // SAFE ->
diff --git a/include/vcl/scheduler.hxx b/include/vcl/scheduler.hxx
index 5c9d8f0d0d6e..fb76e7571a86 100644
--- a/include/vcl/scheduler.hxx
+++ b/include/vcl/scheduler.hxx
@@ -53,7 +53,12 @@ public:
     static void       CallbackTaskScheduling();
     /// Process one pending task ahead of time with highest priority.
     static bool       ProcessTaskScheduling();
-    /// Process all events until we are idle
+    /**
+     * Process all events until we are idle
+     *
+     * Idle is defined as no mpre system events and no more pending LO tasks.
+     * This basically runs Application::Reschedule( true ), until it fails.
+     */
     static void       ProcessEventsToIdle();
     /**
      * Process events until the parameter turns true,
diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx
index d6e186350424..71829eb3fbe4 100644
--- a/include/vcl/svapp.hxx
+++ b/include/vcl/svapp.hxx
@@ -466,32 +466,34 @@ public:
     /** Attempt to process current pending event(s)
 
      It doesn't sleep if no events are available for processing.
+     It normally just processes all current events and ignores new tasks
+     added by the processing tasks, therefore you can't deadlock it by
+     restarting tasks.
 
      @param bAllEvents  If set to true, then try to process all the
         events. If set to false, then only process the current
-        event. Defaults to false.
+        event. Defaults to true.
 
      @returns true if any event was processed.
 
-     @see Execute, Quit, Yield, EndYield, GetSolarMutex,
-          GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
+     @see Yield, Scheduler::ProcessEventsToIdle,
      */
-    static bool                 Reschedule( bool bAllEvents = false );
+    static bool                 Reschedule( bool bAllEvents = true );
 
     /** Process the next event.
 
      It sleeps if no event is available for processing and just returns
      if an event was processed.
 
-     @see Execute, Quit, Reschedule, EndYield, GetSolarMutex,
-          GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
+     @see Reschedule, EndYield, Scheduler::ProcessEventsToIdle,
     */
     static void                 Yield();
 
-    /**
+    /** Wake up a yielding thread
 
-     @see Execute, Quit, Reschedule, Yield, GetSolarMutex,
-          GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
+     Basically generates a dummy event to wake up a yielding thread.
+
+     @see Execute, Reschedule, Yield
     */
     static void                 EndYield();
 
diff --git a/sc/qa/extras/macros-test.cxx b/sc/qa/extras/macros-test.cxx
index da4e30bfc20d..db962e08d134 100644
--- a/sc/qa/extras/macros-test.cxx
+++ b/sc/qa/extras/macros-test.cxx
@@ -308,7 +308,7 @@ void ScMacrosTest::testVba()
         // process all events such as OnLoad events etc.
         // otherwise the tend to arrive later at a random
         // time - while processing other StarBasic methods.
-        Application::Reschedule(true);
+        Application::Reschedule();
 
         Any aRet;
         Sequence< sal_Int16 > aOutParamIndex;
diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx
index 3d7aba5d1b26..64fae54b0958 100644
--- a/sc/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx
@@ -1400,7 +1400,6 @@ void ScTiledRenderingTest::testDisableUndoRepair()
     pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::RETURN);
     pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::RETURN);
     Scheduler::ProcessEventsToIdle();
-    Scheduler::ProcessEventsToIdle();
     {
         SfxItemSet aSet1(pView1->GetPool(), svl::Items<SID_UNDO, SID_UNDO>{});
         SfxItemSet aSet2(pView2->GetPool(), svl::Items<SID_UNDO, SID_UNDO>{});
diff --git a/sc/source/ui/miscdlgs/optsolver.cxx b/sc/source/ui/miscdlgs/optsolver.cxx
index 7c7eb3fd5704..f462c3874602 100644
--- a/sc/source/ui/miscdlgs/optsolver.cxx
+++ b/sc/source/ui/miscdlgs/optsolver.cxx
@@ -836,7 +836,7 @@ bool ScOptSolverDlg::CallSolver()       // return true -> close dialog after cal
     aProgress->Update();
     aProgress->Flush();
     // try to make sure the progress dialog is painted before continuing
-    Application::Reschedule(true);
+    Application::Reschedule();
 
     // collect solver parameters
 
diff --git a/sd/source/ui/dlg/animobjs.cxx b/sd/source/ui/dlg/animobjs.cxx
index d047d6a39f02..2b0a85286fb3 100644
--- a/sd/source/ui/dlg/animobjs.cxx
+++ b/sd/source/ui/dlg/animobjs.cxx
@@ -635,7 +635,7 @@ void AnimationWindow::WaitInEffect( sal_uLong nMilliSeconds, sal_uLong nTime,
         if( pProgress )
             pProgress->SetState( nTime + nMilliSeconds + aCurrent - aEnd );
 
-        Application::Reschedule();
+        Application::Reschedule( false );
 
         if( !bMovie )
             return;
diff --git a/svx/source/form/fmsrcimp.cxx b/svx/source/form/fmsrcimp.cxx
index eb05a3676639..bc75918fa587 100644
--- a/svx/source/form/fmsrcimp.cxx
+++ b/svx/source/form/fmsrcimp.cxx
@@ -312,12 +312,6 @@ FmSearchEngine::SearchResult FmSearchEngine::SearchSpecial(bool _bSearchForNull,
     do
     {
         Application::Reschedule();
-        Application::Reschedule();
-        // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
-        // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
-        // or anything like that. So within each loop we create one user event and handle one user event (and no
-        // paintings and these), so the office seems to be frozen while searching.
-        // FS - 70226 - 02.12.99
 
         // the content to be compared currently
         iterFieldLoop->xContents->getString();  // needed for wasNull
@@ -377,12 +371,6 @@ FmSearchEngine::SearchResult FmSearchEngine::SearchWildcard(const OUString& strE
     do
     {
         Application::Reschedule();
-        Application::Reschedule();
-        // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
-        // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
-        // or anything like that. So within each loop we create one user event and handle one user event (and no
-        // paintings and these), so the office seems to be frozen while searching.
-        // FS - 70226 - 02.12.99
 
         // the content to be compared currently
         OUString sCurrentCheck;
@@ -477,12 +465,6 @@ FmSearchEngine::SearchResult FmSearchEngine::SearchRegularApprox(const OUString&
     do
     {
         Application::Reschedule();
-        Application::Reschedule();
-        // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event
-        // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings
-        // or anything like that. So within each loop we create one user event and handle one user event (and no
-        // paintings and these), so the office seems to be frozen while searching.
-        // FS - 70226 - 02.12.99
 
         // the content to be compared currently
         OUString sCurrentCheck;
diff --git a/sw/source/ui/dbui/addresslistdialog.cxx b/sw/source/ui/dbui/addresslistdialog.cxx
index 96c77cd9edd7..a0e3a4468d58 100644
--- a/sw/source/ui/dbui/addresslistdialog.cxx
+++ b/sw/source/ui/dbui/addresslistdialog.cxx
@@ -487,8 +487,7 @@ IMPL_LINK(SwAddressListDialog, StaticListBoxSelectHdl_Impl, void*, p, void)
             m_pListLB->SetEntryText(m_sConnecting, pSelect, ITEMID_TABLE - 1);
             // allow painting of the new entry
             m_pListLB->Window::Invalidate(InvalidateFlags::Update);
-            for (int i = 0; i < 10; ++i)
-                Application::Reschedule();
+            Application::Reschedule();
         }
 
         pUserData = static_cast<AddressUserData_Impl*>(pSelect->GetUserData());
diff --git a/sw/source/ui/dbui/mmresultdialogs.cxx b/sw/source/ui/dbui/mmresultdialogs.cxx
index 1c3f17b4b52a..b8b1697bd73d 100644
--- a/sw/source/ui/dbui/mmresultdialogs.cxx
+++ b/sw/source/ui/dbui/mmresultdialogs.cxx
@@ -719,8 +719,7 @@ IMPL_LINK(SwMMResultSaveDialog, SaveOutputHdl_Impl, Button*, pButton, void)
             while(true)
             {
                 //time for other slots is needed
-                for(sal_Int16 r = 0; r < 10; ++r)
-                    Application::Reschedule();
+                Application::Reschedule();
                 bool bFailed = false;
                 try
                 {
@@ -1088,8 +1087,7 @@ IMPL_LINK(SwMMResultEmailDialog, SendDocumentsHdl_Impl, Button*, pButton, void)
     //help to force painting the dialog
     //TODO/CLEANUP
     //predetermined breaking point
-    for ( sal_Int16 i = 0; i < 25; i++)
-        Application::Reschedule();
+    Application::Reschedule();
     for(sal_uInt32 nDoc = nBegin; nDoc < nEnd; ++nDoc)
     {
         SwDocMergeInfo& rInfo = xConfigItem->GetDocumentMergeInfo(nDoc);
@@ -1231,8 +1229,7 @@ IMPL_LINK(SwMMResultEmailDialog, SendDocumentsHdl_Impl, Button*, pButton, void)
         aDesc.sBCC = m_sBCC;
         pDlg->AddDocument( aDesc );
         //help to force painting the dialog
-        for ( sal_Int16 i = 0; i < 25; i++)
-            Application::Reschedule();
+        Application::Reschedule();
         //stop creating of data when dialog has been closed
         if(!pDlg->IsVisible())
         {
diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index 1d691bff3bed..4616aebea6d5 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -147,11 +147,6 @@ using namespace ::com::sun::star;
 
 namespace {
 
-void rescheduleGui() {
-    for( sal_uInt16 i = 0; i < 25; i++)
-        Application::Reschedule();
-}
-
 void lcl_emitEvent(SfxEventHintId nEventId, sal_Int32 nStrId, SfxObjectShell* pDocShell)
 {
     SfxGetpApp()->NotifyEvent(SfxEventHint(nEventId,
@@ -1257,7 +1252,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
         pProgressDlg->SetCancelHdl( LINK(this, SwDBManager, PrtCancelHdl) );
         pProgressDlg->Show();
 
-        rescheduleGui();
+        Application::Reschedule();
     }
 
     if( bCreateSingleFile && !pTargetView )
@@ -1400,7 +1395,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                 pProgressDlg->Update();
             }
 
-            rescheduleGui();
+            Application::Reschedule();
 
             // Create a copy of the source document and work with that one instead of the source.
             // If we're not in the single file mode (which requires modifying the document for the merging),
@@ -1570,7 +1565,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
     }
     else if( IsMergeOk() ) // && bCreateSingleFile
     {
-        rescheduleGui();
+        Application::Reschedule();
 
         // sw::DocumentLayoutManager::CopyLayoutFormat() did not generate
         // unique fly names, do it here once.
@@ -1589,7 +1584,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
             aLayout->AllCheckPageDescs();
         }
 
-        rescheduleGui();
+        Application::Reschedule();
 
         if( IsMergeOk() && bMT_FILE )
         {
@@ -1627,7 +1622,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
     else if( xTargetDocShell.is() )
         xTargetDocShell->DoClose();
 
-    rescheduleGui();
+    Application::Reschedule();
 
     pProgressDlg.disposeAndClear();
 
diff --git a/toolkit/source/awt/vclxtoolkit.cxx b/toolkit/source/awt/vclxtoolkit.cxx
index eb888f6f0872..5161c4422676 100644
--- a/toolkit/source/awt/vclxtoolkit.cxx
+++ b/toolkit/source/awt/vclxtoolkit.cxx
@@ -1890,7 +1890,7 @@ void VCLXToolkit::callFocusListeners(::VclSimpleEvent const * pEvent,
 void SAL_CALL VCLXToolkit::reschedule()
 {
     SolarMutexGuard aSolarGuard;
-    Application::Reschedule(true);
+    Application::Reschedule();
 }
 
 // css::awt::XToolkitExperimental
diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx
index 1966727ac936..8a805ea345b1 100644
--- a/vcl/headless/svpinst.cxx
+++ b/vcl/headless/svpinst.cxx
@@ -180,7 +180,7 @@ bool SvpSalInstance::PostedEventsInQueue()
     bool result = false;
     {
         osl::MutexGuard g(m_aEventGuard);
-        result = m_aUserEvents.size() > 0;
+        result = !m_aUserEvents.empty();
     }
     return result;
 }
diff --git a/vcl/inc/headless/svpinst.hxx b/vcl/inc/headless/svpinst.hxx
index 0883981c4406..1db4f1ac0025 100644
--- a/vcl/inc/headless/svpinst.hxx
+++ b/vcl/inc/headless/svpinst.hxx
@@ -70,6 +70,7 @@ class VCL_DLLPUBLIC SvpSalInstance : public SalGenericInstance
         ImplSVEvent*        m_pData;
         SalEvent            m_nEvent;
 
+        SalUserEvent() : m_pFrame( nullptr ), m_pData( nullptr ), m_nEvent( SalEvent::NONE ) {}
         SalUserEvent( const SalFrame* pFrame, ImplSVEvent* pData, SalEvent nEvent )
                 : m_pFrame( pFrame ),
                   m_pData( pData ),
diff --git a/vcl/qa/cppunit/timer.cxx b/vcl/qa/cppunit/timer.cxx
index 7b712bd76c04..e454698a14d1 100644
--- a/vcl/qa/cppunit/timer.cxx
+++ b/vcl/qa/cppunit/timer.cxx
@@ -326,7 +326,7 @@ void TimerTest::testAutoTimerStop()
     while (nMaxCount != nTimerCount)
         Application::Yield();
     CPPUNIT_ASSERT( !aAutoTimer.IsActive() );
-    CPPUNIT_ASSERT( !Application::Reschedule() );
+    CPPUNIT_ASSERT( !Application::Reschedule( false ) );
 }
 
 
@@ -525,7 +525,7 @@ void TimerTest::testRoundRobin()
     sal_uInt32 nCount1 = 0, nCount2 = 0;
     TestAutoIdleRR aIdle1( nCount1, "TestAutoIdleRR aIdle1" ),
                    aIdle2( nCount2, "TestAutoIdleRR aIdle2" );
-    while ( Application::Reschedule() )
+    while ( Application::Reschedule( false ) )
     {
         CPPUNIT_ASSERT( nCount1 == nCount2 || nCount1 - 1 == nCount2 );
         CPPUNIT_ASSERT( nCount1 <= 3 );
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
index fdfc02a684d4..895d068c2601 100644
--- a/vcl/source/app/svapp.cxx
+++ b/vcl/source/app/svapp.cxx
@@ -486,11 +486,6 @@ bool Application::Reschedule( bool i_bAllEvents )
     return ImplYield(false, i_bAllEvents);
 }
 
-void Scheduler::ProcessEventsToSignal(bool& bSignal)
-{
-    while (!bSignal && Application::Reschedule( false ) );
-}
-
 void Scheduler::ProcessEventsToIdle()
 {
     int nSanity = 1;
@@ -516,7 +511,8 @@ void Scheduler::ProcessEventsToIdle()
             Idle *pIdle = dynamic_cast<Idle*>( pSchedulerData->mpTask );
             if ( pIdle && pIdle->IsActive() )
             {
-                SAL_WARN( "vcl.schedule", "Unprocessed Idle: " << pIdle->GetDebugName() );
+                SAL_WARN( "vcl.schedule", "Unprocessed Idle: "
+                          << pIdle << " " << pIdle->GetDebugName() );
             }
         }
         pSchedulerData = pSchedulerData->mpNext;
@@ -524,6 +520,11 @@ void Scheduler::ProcessEventsToIdle()
 #endif
 }
 
+void Scheduler::ProcessEventsToSignal(bool& bSignal)
+{
+    while (!bSignal && Application::Reschedule( false ) );
+}
+
 extern "C" {
 /// used by unit tests that test only via the LOK API
 SAL_DLLPUBLIC_EXPORT void unit_lok_process_events_to_idle()
diff --git a/vcl/source/gdi/print2.cxx b/vcl/source/gdi/print2.cxx
index 2ccb80ce2a36..129b716670db 100644
--- a/vcl/source/gdi/print2.cxx
+++ b/vcl/source/gdi/print2.cxx
@@ -1232,8 +1232,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf,
                                             pCurrAct->Execute( aPaintVDev.get() );
                                         }
 
-                                        if( !( nActionNum % 8 ) )
-                                            Application::Reschedule();
+                                        Application::Reschedule();
                                     }
 
                                     const bool bOldMap = mbMap;
diff --git a/vcl/source/gdi/print3.cxx b/vcl/source/gdi/print3.cxx
index e70c4d02dd82..358ede2c79ab 100644
--- a/vcl/source/gdi/print3.cxx
+++ b/vcl/source/gdi/print3.cxx
@@ -966,7 +966,7 @@ PrinterController::PageSize PrinterController::getPageFile( int i_nUnfilteredPag
         if( mpImplData->mpProgress->isCanceled() )
             return PrinterController::PageSize();
         mpImplData->mpProgress->tick();
-        Application::Reschedule( true );
+        Application::Reschedule();
     }
 
     if( i_bMayUseCache )
diff --git a/vcl/unx/generic/app/saldata.cxx b/vcl/unx/generic/app/saldata.cxx
index fb5131473e5a..33cee0888019 100644
--- a/vcl/unx/generic/app/saldata.cxx
+++ b/vcl/unx/generic/app/saldata.cxx
@@ -660,23 +660,20 @@ SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
     if (p_prioritize_timer != nullptr)
         bHandledEvent = CheckTimeout();
 
-    const int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
-
     // first, check for already queued events.
     for ( int nFD = 0; nFD < nFDs_; nFD++ )
     {
         YieldEntry* pEntry = &(yieldTable[nFD]);
-        if ( pEntry->fd )
+        if ( pEntry->fd && pEntry->HasPendingEvent() )
         {
             SAL_WARN_IF( nFD != pEntry->fd, "vcl", "wrong fd in Yield()" );
-            for( int i = 0; i < nMaxEvents && pEntry->HasPendingEvent(); i++ )
+            do
             {
                 pEntry->HandleNextEvent();
-                if( ! bHandleAllCurrentEvents )
-                {
+                if ( !bHandleAllCurrentEvents )
                     return true;
-                }
             }
+            while ( pEntry->HasPendingEvent() );
         }
     }
 
@@ -689,7 +686,6 @@ SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
     timeval  Timeout      = noyield_;
     timeval *pTimeout     = &Timeout;
 
-
     if (bWait)
     {
         pTimeout = nullptr;
@@ -765,12 +761,14 @@ SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
                 }
                 if ( FD_ISSET( nFD, &ReadFDS ) )
                 {
-                    for( int i = 0; pEntry->IsEventQueued() && i < nMaxEvents; i++ )
+                    if ( pEntry->IsEventQueued() )
                     {
-                        pEntry->HandleNextEvent();
-                        bHandledEvent = true;
-                        // if a recursive call has done the job
-                        // so abort here
+                        do
+                        {
+                            pEntry->HandleNextEvent();
+                            bHandledEvent = true;
+                        }
+                        while ( bHandleAllCurrentEvents && pEntry->IsEventQueued() );
                     }
                     nFound--;
                 }
diff --git a/vcl/unx/generic/dtrans/X11_selection.cxx b/vcl/unx/generic/dtrans/X11_selection.cxx
index 7c89186505e0..637e32075408 100644
--- a/vcl/unx/generic/dtrans/X11_selection.cxx
+++ b/vcl/unx/generic/dtrans/X11_selection.cxx
@@ -3739,7 +3739,7 @@ void SelectionManager::shutdown() throw()
         {
             {   // drop mutex before write - otherwise may deadlock
                 SolarMutexGuard guard2;
-                Application::Reschedule();
+                Application::Reschedule( false );
             }
             // trigger poll()'s wait end by writing a dummy value
             char dummy=0;
diff --git a/vcl/unx/gtk/gtkdata.cxx b/vcl/unx/gtk/gtkdata.cxx
index 19ea9f2f0fcd..aa0f4ae28a39 100644
--- a/vcl/unx/gtk/gtkdata.cxx
+++ b/vcl/unx/gtk/gtkdata.cxx
@@ -481,14 +481,14 @@ bool GtkData::Yield( bool bWait, bool bHandleAllCurrentEvents )
 
         if( bDispatchThread )
         {
-            int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
-            gboolean wasOneEvent = TRUE;
-            while( nMaxEvents-- && wasOneEvent )
+            bool wasOneEvent = false;
+            do
             {
                 wasOneEvent = g_main_context_iteration( nullptr, bWait && !bWasEvent );
                 if( wasOneEvent )
                     bWasEvent = true;
             }
+            while ( bHandleAllCurrentEvents && wasOneEvent );
         }
         else if( bWait )
         {
diff --git a/vcl/unx/gtk3/gtk3gtkdata.cxx b/vcl/unx/gtk3/gtk3gtkdata.cxx
index 2690c2614ae6..4739479cc99a 100644
--- a/vcl/unx/gtk3/gtk3gtkdata.cxx
+++ b/vcl/unx/gtk3/gtk3gtkdata.cxx
@@ -457,14 +457,14 @@ bool GtkData::Yield( bool bWait, bool bHandleAllCurrentEvents )
 
         if( bDispatchThread )
         {
-            int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
-            gboolean wasOneEvent = TRUE;
-            while( nMaxEvents-- && wasOneEvent )
+            bool wasOneEvent = false;
+            do
             {
                 wasOneEvent = g_main_context_iteration( nullptr, bWait && !bWasEvent );
                 if( wasOneEvent )
                     bWasEvent = true;
             }
+            while ( bHandleAllCurrentEvents && wasOneEvent );
             if (m_aException.hasValue())
                 ::cppu::throwException(m_aException);
         }
diff --git a/vcl/unx/kde4/KDEXLib.cxx b/vcl/unx/kde4/KDEXLib.cxx
index a44b9f1a3233..d56c67e008cb 100644
--- a/vcl/unx/kde4/KDEXLib.cxx
+++ b/vcl/unx/kde4/KDEXLib.cxx
@@ -293,8 +293,7 @@ bool KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
         // (it's ok to release it here, since even normal processYield() would
         // temporarily do it while checking for new events)
         SalYieldMutexReleaser aReleaser;
-        Q_EMIT processYieldSignal( bWait, bHandleAllCurrentEvents );
-        return false;
+        return Q_EMIT processYieldSignal( bWait, bHandleAllCurrentEvents );
     }
 }
 
diff --git a/vcl/unx/kde4/KDEXLib.hxx b/vcl/unx/kde4/KDEXLib.hxx
index 01076286c429..2fe497d019fa 100644
--- a/vcl/unx/kde4/KDEXLib.hxx
+++ b/vcl/unx/kde4/KDEXLib.hxx
@@ -68,7 +68,7 @@ class KDEXLib : public QObject, public SalXLib
 
     Q_SIGNALS:
         void startTimeoutTimerSignal();
-        void processYieldSignal( bool bWait, bool bHandleAllCurrentEvents );
+        bool processYieldSignal( bool bWait, bool bHandleAllCurrentEvents );
         css::uno::Reference< css::ui::dialogs::XFilePicker2 >
             createFilePickerSignal( const css::uno::Reference< css::uno::XComponentContext >& );
 
diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx
index f2e337c3244b..1e69ec2c075a 100644
--- a/vcl/win/app/salinst.cxx
+++ b/vcl/win/app/salinst.cxx
@@ -510,7 +510,6 @@ static bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
     ImplSVData *const pSVData = ImplGetSVData();
     WinSalTimer* pTimer = static_cast<WinSalTimer*>( pSVData->maSchedCtx.mpSalTimer );
 
-    int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
     do
     {
         bOneEvent = PeekMessageW( &aMsg, nullptr, 0, 0, PM_REMOVE );
@@ -527,11 +526,11 @@ static bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
             if ( pTimer && pTimer->WantBusyLoop() && !bWait )
             {
                 SwitchToThread();
-                nMaxEvents++;
                 bOneEvent = true;
                 bWasMsg = true;
             }
-    } while( --nMaxEvents && bOneEvent );
+    }
+    while( bHandleAllCurrentEvents && bOneEvent );
 
     // Also check that we don't wait when application already has quit
     if ( bWait && !bWasMsg && !pSVData->maAppData.mbAppQuit )
diff --git a/vcl/win/gdi/salprn.cxx b/vcl/win/gdi/salprn.cxx
index 7847c5465ec3..ca8de12d44f6 100644
--- a/vcl/win/gdi/salprn.cxx
+++ b/vcl/win/gdi/salprn.cxx
@@ -1291,7 +1291,7 @@ BOOL CALLBACK SalPrintAbortProc( HDC hPrnDC, int /* nError */ )
     do
     {
         // process messages
-        bWhile = Application::Reschedule( true );
+        bWhile = Application::Reschedule();
 
         pPrinter = pSalData->mpFirstPrinter;
         while ( pPrinter )
@@ -1454,7 +1454,7 @@ bool WinSalPrinter::StartJob( const OUString* pFileName,
 
     // As the Telecom Balloon Fax driver tends to send messages repeatedly
     // we try to process first all, and then insert a dummy message
-    while ( Application::Reschedule( true ) );
+    while ( Application::Reschedule() );
     BOOL const ret = PostMessageW(GetSalData()->mpFirstInstance->mhComWnd, SAL_MSG_DUMMY, 0, 0);
     SAL_WARN_IF(0 == ret, "vcl", "ERROR: PostMessage() failed!");
 
diff --git a/vcl/win/window/salframe.cxx b/vcl/win/window/salframe.cxx
index 7195b3b91fb0..c00ab908820f 100644
--- a/vcl/win/window/salframe.cxx
+++ b/vcl/win/window/salframe.cxx
@@ -5710,7 +5710,7 @@ LRESULT CALLBACK SalFrameWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lP
                 // messages in the message queue and dispatch them before we return control to the system.
 
                 if ( nRet )
-                    while ( Application::Reschedule( true ) );
+                    while ( Application::Reschedule() );
             }
             else
             {
commit 3a47d529bda4e6c588549d5f15bca7c16851358d
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Tue Aug 29 09:40:01 2017 +0200

    Don't wait-yield non-main threads in the main thread
    
    This prevents blocking the main thread by a yielding non-main thread.
    The current solution is to wait on a condition, which is set by the
    main thread on wakeup.
    
    Change-Id: I8d680bb51a36ce1e0d3d4713d47d8e2ef93d7297

diff --git a/vcl/README.scheduler b/vcl/README.scheduler
index e960b9c8a697..7a7dee3c4c7a 100644
--- a/vcl/README.scheduler
+++ b/vcl/README.scheduler
@@ -104,6 +104,14 @@ normally wait for the SolarMutex.
 Eventually this will move into the GenericSolarMutex. KDE / Qt also does main
 thread redirects using Qt::BlockingQueuedConnection.
 
+= General: non-main thread yield =
+
+Yielding from a non-main thread must not wait in the main thread, as this
+may block the main thread until some events happen.
+
+Currently we wait on an extra conditional, which is cleared by the main event
+loop.
+
 == MacOS implementation details ==
 
 Generally the Scheduler is handled as expected, except on resize, which is
diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h
index 32434325dd3e..5ebcbf977fe6 100644
--- a/vcl/inc/osx/salinst.h
+++ b/vcl/inc/osx/salinst.h
@@ -72,6 +72,8 @@ class AquaSalInstance : public SalInstance
         {}
     };
 
+    bool RunInMainYield( bool bHandleAllCurrentEvents );
+
 public:
     SalYieldMutex*                          mpSalYieldMutex;        // Sal-Yield-Mutex
     OUString                                maDefaultPrinter;
diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx
index 0b5e4a68d4dc..cfb981401459 100644
--- a/vcl/osx/salinst.cxx
+++ b/vcl/osx/salinst.cxx
@@ -548,6 +548,13 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent )
     };
 }
 
+bool RunInMainYield( bool bHandleAllCurrentEvents )
+{
+    OSX_SALDATA_RUNINMAIN_UNION( DoYield( false, bHandleAllCurrentEvents), boolean )
+    assert( false && "Don't call this from the main thread!" );
+    return false;
+}
+
 bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
 {
     bool bHadEvent = false;
@@ -620,13 +627,17 @@ SAL_WNODEPRECATED_DECLARATIONS_POP
         }
         maWaitingYieldCond.set();
     }
-    else if( bWait )
+    else
     {
-        // #i103162#
-        // wait until the main thread has dispatched an event
-        maWaitingYieldCond.reset();
-        SolarMutexReleaser aReleaser;
-        maWaitingYieldCond.wait();
+        bHadEvent = RunInMainYield( bHandleAllCurrentEvents );
+        if ( !bHadEvent && bWait )
+        {
+            // #i103162#
+            // wait until the main thread has dispatched an event
+            maWaitingYieldCond.reset();
+            SolarMutexReleaser aReleaser;
+            maWaitingYieldCond.wait();
+        }
     }
 
     // we get some apple events way too early
diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx
index 8ad33066ebaf..f2e337c3244b 100644
--- a/vcl/win/app/salinst.cxx
+++ b/vcl/win/app/salinst.cxx
@@ -558,31 +558,16 @@ bool WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
     SolarMutexReleaser aReleaser;
     if ( !IsMainThread() )
     {
-        if ( bWait )
+        // If you change the SendMessageW function, you might need to update
+        // the PeekMessage( ... PM_QS_POSTMESSAGE) calls!
+        bDidWork = SendMessageW( mhComWnd, SAL_MSG_THREADYIELD,
+                                 (WPARAM) false, (LPARAM) bHandleAllCurrentEvents );
+        if ( !bDidWork && bWait )
         {
             maWaitingYieldCond.reset();
             maWaitingYieldCond.wait();
             bDidWork = true;
         }
-        else {
-            // #97739# A SendMessage call blocks until the called thread (here: the main thread)
-            // returns. During a yield however, messages are processed in the main thread that might
-            // result in a new message loop due to opening a dialog. Thus, SendMessage would not
-            // return which will block this thread!
-            // Solution: just give up the time slice and hope that messages are processed
-            // by the main thread anyway (where all windows are created)
-            // If the mainthread is not currently handling messages, then our SendMessage would
-            // also do nothing, so this seems to be reasonable.
-
-            // #i18883# only sleep if potential deadlock scenario, ie, when a dialog is open
-            if( ImplGetSVData()->maAppData.mnModalMode )
-                Sleep(1);
-            else
-                // If you change the SendMessageW function, you might need to update
-                // the PeekMessage( ... PM_QS_POSTMESSAGE) calls!
-                bDidWork = SendMessageW( mhComWnd, SAL_MSG_THREADYIELD,
-                                         (WPARAM)bWait, (LPARAM)bHandleAllCurrentEvents );
-        }
     }
     else
     {
@@ -601,7 +586,8 @@ LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, i
     switch ( nMsg )
     {
         case SAL_MSG_THREADYIELD:
-            nRet = static_cast<LRESULT>(ImplSalYield( (bool)wParam, (bool)lParam ));
+            assert( !(bool)wParam );
+            nRet = static_cast<LRESULT>(ImplSalYield( false, (bool)lParam ));
             rDef = FALSE;
             break;
         case SAL_MSG_STARTTIMER:
commit 35e109b27f3f0f6091d140169d99c6338c55250c
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Mon Aug 28 19:58:32 2017 +0200

    WIN run main thread redirects ignoring SolarMutex
    
    This way we can drop all the special nReleased handling. Instead we use
    the same mechanism as on Mac, where we keep the lock, but disable it for
    the main thread. As a security measure we assert on duplicate redirects,
    which should not happen.
    
    As a result we can't use SendMessage on the main thread itself, which
    would normally just call the WinProc directly. This could be accomplished
    by converting the redirect bool into a counter, which should be safe, as
    no other thread could acquire the SolarMutex, as we don't release it.
    
    Change-Id: Icd87b3da37a2489f3cad2bc80215bf93fc41d388

diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx
index be6ea6f8a53c..d6e186350424 100644
--- a/include/vcl/svapp.hxx
+++ b/include/vcl/svapp.hxx
@@ -495,12 +495,6 @@ public:
     */
     static void                 EndYield();
 
-    /** Acquire SolarMutex after it has been temporarily dropped completely.
-
-        This will Reschedule() on WNT and just acquire on other platforms.
-    */
-    static void                 ReAcquireSolarMutex(sal_uLong nReleased);
-
     /** @brief Get the Solar Mutex for this thread.
 
      Get the Solar Mutex that prevents other threads from accessing VCL
@@ -1491,7 +1485,7 @@ public:
     ~SolarMutexReleaser()
     {
         if ( mnReleased )
-            Application::ReAcquireSolarMutex( mnReleased );
+            Application::AcquireSolarMutex( mnReleased );
     }
 };
 
diff --git a/vcl/README.scheduler b/vcl/README.scheduler
index 0389dc94d723..e960b9c8a697 100644
--- a/vcl/README.scheduler
+++ b/vcl/README.scheduler
@@ -89,6 +89,21 @@ can be added to the scheduler reasonably.
 
 = Implementation details =
 
+= General: main thread deferral =
+
+Currently for Mac and Windows, we run main thread deferrals by disabling the
+SolarMutex using a boolean. In the case of the redirect, this makes 
+tryToaAcquire and doAcquire return true or 1, while a release is ignored.
+Also the IsCurrentThread() mutex check function will act accordingly, so all
+the DBG_TESTSOLARMUTEX won't fail.
+
+Since we just disable the locks when we start running the deferred code in the
+main thread, we won't let the main thread run into stuff, where it would
+normally wait for the SolarMutex.
+
+Eventually this will move into the GenericSolarMutex. KDE / Qt also does main
+thread redirects using Qt::BlockingQueuedConnection.
+
 == MacOS implementation details ==
 
 Generally the Scheduler is handled as expected, except on resize, which is
@@ -100,9 +115,8 @@ Like the Windows backend, all Cocoa / GUI handling also has to be run in
 the main thread. We're emulating Windows out-of-order PeekMessage processing,
 via a YieldWakeupEvent and two conditionals. When in a RUNINMAIN call, all
 the DBG_TESTSOLARMUTEX calls are disabled, as we can't release the SolarMutex,
-but we can prevent running any other SolarMutex based code. Same for all the
-SolarMutex acquire and release calls, so the calling and the main thread
-don't deadlock.
+but we can prevent running any other SolarMutex based code. For more info
+read the "General: main thread deferral" section.
 
 We can neigher rely on MacOS dispatch_sync code block execution nor the
 message handling, as both can't be priorized or filtered and the first
@@ -136,6 +150,10 @@ the timer callback message, which is checked before starting the Scheduler.
 This way we can end with multiple timer callback message in the queue, which
 we were asserting.
 
+To run the required GUI code in the main thread without unlocking the
+SolarMutex, we "disable" it. For more infos read the "General: main thread
+deferral" section.
+
 == KDE implementation details ==
 
 This implementation also works as intended. But there is a different Yield
diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx
index b75a035466f1..1966727ac936 100644
--- a/vcl/headless/svpinst.cxx
+++ b/vcl/headless/svpinst.cxx
@@ -304,12 +304,9 @@ SalBitmap* SvpSalInstance::CreateSalBitmap()
 #endif
 }
 
-bool SvpSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
+bool SvpSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
 {
-    (void) nReleased;
-    assert(nReleased == 0); // not implemented
     // first, check for already queued events.
-
     std::list< SalUserEvent > aEvents;
     {
         osl::MutexGuard g(m_aEventGuard);
diff --git a/vcl/inc/headless/svpinst.hxx b/vcl/inc/headless/svpinst.hxx
index e8bb96ab68ac..0883981c4406 100644
--- a/vcl/inc/headless/svpinst.hxx
+++ b/vcl/inc/headless/svpinst.hxx
@@ -155,7 +155,7 @@ public:
     // wait next event and dispatch
     // must returned by UserEvent (SalFrame::PostEvent)
     // and timer
-    virtual bool            DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) override;
+    virtual bool            DoYield(bool bWait, bool bHandleAllCurrentEvents) override;
     virtual bool            AnyInput( VclInputFlags nType ) override;
     virtual bool            IsMainThread() const override { return true; }
 
diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h
index e80818a36eb5..32434325dd3e 100644
--- a/vcl/inc/osx/salinst.h
+++ b/vcl/inc/osx/salinst.h
@@ -114,8 +114,7 @@ public:
     virtual comphelper::SolarMutex* GetYieldMutex() override;
     virtual sal_uInt32      ReleaseYieldMutex( bool bUnlockAll = false ) override;
     virtual void            AcquireYieldMutex( sal_uInt32 nCount = 1 ) override;
-    virtual bool            DoYield(bool bWait, bool bHandleAllCurrentEvents,
-                                    sal_uLong nReleased) override;
+    virtual bool            DoYield(bool bWait, bool bHandleAllCurrentEvents) override;
     virtual bool            AnyInput( VclInputFlags nType ) override;
     virtual SalMenu*        CreateMenu( bool bMenuBar, Menu* pVCLMenu ) override;
     virtual void            DestroyMenu( SalMenu* ) override;
diff --git a/vcl/inc/salinst.hxx b/vcl/inc/salinst.hxx
index 12959cc44280..8418a1ed8126 100644
--- a/vcl/inc/salinst.hxx
+++ b/vcl/inc/salinst.hxx
@@ -133,7 +133,7 @@ public:
      * If bHandleAllCurrentEvents - dispatch multiple posted
      * user events. Returns true if events were processed.
      */
-    virtual bool           DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) = 0;
+    virtual bool           DoYield(bool bWait, bool bHandleAllCurrentEvents) = 0;
     virtual bool           AnyInput( VclInputFlags nType ) = 0;
 
     // menus
diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx
index 1585c778afac..595a7adb7089 100644
--- a/vcl/inc/unx/gtk/gtkinst.hxx
+++ b/vcl/inc/unx/gtk/gtkinst.hxx
@@ -208,7 +208,7 @@ public:
                                                      const SystemGraphicsData* = nullptr ) override;
     virtual SalBitmap*          CreateSalBitmap() override;
 
-    virtual bool                DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) override;
+    virtual bool                DoYield(bool bWait, bool bHandleAllCurrentEvents) override;
     virtual bool                AnyInput( VclInputFlags nType ) override;
     // impossible to handle correctly, as "main thread" depends on the dispatch mutex
     virtual bool                IsMainThread() const override { return false; }
diff --git a/vcl/inc/unx/salinst.h b/vcl/inc/unx/salinst.h
index 2307410fe69e..59464b4c60e5 100644
--- a/vcl/inc/unx/salinst.h
+++ b/vcl/inc/unx/salinst.h
@@ -74,7 +74,7 @@ public:
     virtual SalSession*         CreateSalSession() override;
     virtual OpenGLContext*      CreateOpenGLContext() override;
 
-    virtual bool                DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) override;
+    virtual bool                DoYield(bool bWait, bool bHandleAllCurrentEvents) override;
     virtual bool                AnyInput( VclInputFlags nType ) override;
     virtual bool                IsMainThread() const override { return true; }
 
diff --git a/vcl/inc/win/salinst.h b/vcl/inc/win/salinst.h
index 6efecbd6bd5e..8772ee00fa22 100644
--- a/vcl/inc/win/salinst.h
+++ b/vcl/inc/win/salinst.h
@@ -34,6 +34,9 @@ public:
     /// The Yield mutex ensures that only one thread calls into VCL
     SalYieldMutex*      mpSalYieldMutex;
 
+    osl::Condition      maWaitingYieldCond;
+    bool                mbNoYieldLock;
+
 public:
     WinSalInstance();
     virtual ~WinSalInstance() override;
@@ -63,7 +66,7 @@ public:
     virtual void                AcquireYieldMutex( sal_uInt32 nCount = 1 ) override;
     virtual bool                IsMainThread() const override;
 
-    virtual bool                DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) override;
+    virtual bool                DoYield(bool bWait, bool bHandleAllCurrentEvents) override;
     virtual bool                AnyInput( VclInputFlags nType ) override;
     virtual SalMenu*            CreateMenu( bool bMenuBar, Menu* ) override;
     virtual void                DestroyMenu( SalMenu* ) override;
diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx
index 9de49e33c215..0b5e4a68d4dc 100644
--- a/vcl/osx/salinst.cxx
+++ b/vcl/osx/salinst.cxx
@@ -548,10 +548,8 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent )
     };
 }
 
-bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
+bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
 {
-    (void) nReleased;
-    assert(nReleased == 0); // not implemented
     bool bHadEvent = false;
 
     // ensure that the per thread autorelease pool is top level and
diff --git a/vcl/qa/cppunit/timer.cxx b/vcl/qa/cppunit/timer.cxx
index 28f4284f1430..7b712bd76c04 100644
--- a/vcl/qa/cppunit/timer.cxx
+++ b/vcl/qa/cppunit/timer.cxx
@@ -148,7 +148,7 @@ void TimerTest::testIdleMainloop()
         // can't test this via Application::Yield since this
         // also processes all tasks directly via the scheduler.
         pSVData->maAppData.mnDispatchLevel++;
-        pSVData->mpDefInst->DoYield(true, false, 0);
+        pSVData->mpDefInst->DoYield(true, false);
         pSVData->maAppData.mnDispatchLevel--;
     }
     CPPUNIT_ASSERT_MESSAGE("mainloop idle triggered", bTriggered);
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
index 5959b3f5b1cb..fdfc02a684d4 100644
--- a/vcl/source/app/svapp.cxx
+++ b/vcl/source/app/svapp.cxx
@@ -451,12 +451,12 @@ void Application::Execute()
     pSVData->maAppData.mbInAppExecute = false;
 }
 
-inline bool ImplYield(bool i_bWait, bool i_bAllEvents, sal_uLong const nReleased)
+inline bool ImplYield(bool i_bWait, bool i_bAllEvents)
 {
     ImplSVData* pSVData = ImplGetSVData();
 
     SAL_INFO("vcl.schedule", "Enter ImplYield: " << (i_bWait ? "wait" : "no wait") <<
-             ": " << (i_bAllEvents ? "all events" : "one event") << ": " << nReleased);
+             ": " << (i_bAllEvents ? "all events" : "one event"));
 
     // TODO: there's a data race here on WNT only because ImplYield may be
     // called without SolarMutex; if we can get rid of LazyDelete (with VclPtr)
@@ -466,10 +466,8 @@ inline bool ImplYield(bool i_bWait, bool i_bAllEvents, sal_uLong const nReleased
 
     // do not wait for events if application was already quit; in that
     // case only dispatch events already available
-    bool bProcessedEvent =
-        pSVData->mpDefInst->DoYield(
-            i_bWait && !pSVData->maAppData.mbAppQuit,
-            i_bAllEvents, nReleased);
+    bool bProcessedEvent = pSVData->mpDefInst->DoYield(
+            i_bWait && !pSVData->maAppData.mbAppQuit, i_bAllEvents );
 
     pSVData->maAppData.mnDispatchLevel--;
 
@@ -485,7 +483,7 @@ inline bool ImplYield(bool i_bWait, bool i_bAllEvents, sal_uLong const nReleased
 
 bool Application::Reschedule( bool i_bAllEvents )
 {
-    return ImplYield(false, i_bAllEvents, 0);
+    return ImplYield(false, i_bAllEvents);
 }
 
 void Scheduler::ProcessEventsToSignal(bool& bSignal)
@@ -537,27 +535,7 @@ SAL_DLLPUBLIC_EXPORT void unit_lok_process_events_to_idle()
 
 void Application::Yield()
 {
-    ImplYield(true, false, 0);
-}
-
-void Application::ReAcquireSolarMutex(sal_uLong const nReleased)
-{
-    // 0 would mean that events/timers will be handled without locking
-    // SolarMutex (racy)
-    SAL_WARN_IF(nReleased == 0, "vcl", "SolarMutexReleaser without SolarMutex");
-#ifdef _WIN32
-    if (nReleased == 0 || ImplGetSVData()->mbDeInit) //do not Yield in DeInitVCL
-        AcquireSolarMutex(nReleased);
-    else
-        ImplYield(false, false, nReleased);
-#else
-    // a) Yield is not needed on non-WNT platforms
-    // b) some Yield implementations for X11 (e.g. kde4) make it non-obvious
-    //    how to use nReleased
-    // c) would require a review of what all Yield implementations do
-    //    currently _before_ releasing SolarMutex that would run without lock
-    AcquireSolarMutex(nReleased);
-#endif
+    ImplYield(true, false);
 }
 
 IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplQuitMsg, void*, void )
diff --git a/vcl/unx/generic/app/salinst.cxx b/vcl/unx/generic/app/salinst.cxx
index 456c238a1d08..897d955ddccb 100644
--- a/vcl/unx/generic/app/salinst.cxx
+++ b/vcl/unx/generic/app/salinst.cxx
@@ -166,10 +166,8 @@ bool X11SalInstance::AnyInput(VclInputFlags nType)
     return bRet;
 }
 
-bool X11SalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
+bool X11SalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
 {
-    (void) nReleased;
-    assert(nReleased == 0); // not implemented
     return mpXLib->Yield( bWait, bHandleAllCurrentEvents );
 }
 
diff --git a/vcl/unx/gtk/gtkinst.cxx b/vcl/unx/gtk/gtkinst.cxx
index 080b2a9c0345..1caee7f637aa 100644
--- a/vcl/unx/gtk/gtkinst.cxx
+++ b/vcl/unx/gtk/gtkinst.cxx
@@ -409,10 +409,8 @@ void GtkInstance::RemoveTimer ()
     m_pTimer = nullptr;
 }
 
-bool GtkInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
+bool GtkInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
 {
-    (void) nReleased;
-    assert(nReleased == 0); // not implemented
     EnsureInit();
     return GetGtkSalData()->Yield( bWait, bHandleAllCurrentEvents );
 }
diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx
index d1bce72f7328..8ad33066ebaf 100644
--- a/vcl/win/app/salinst.cxx
+++ b/vcl/win/app/salinst.cxx
@@ -111,6 +111,7 @@ public:
     explicit SalYieldMutex();
 
     virtual bool              IsCurrentThread() const override;
+    virtual bool              tryToAcquire() override;
 };
 
 SalYieldMutex::SalYieldMutex()
@@ -138,6 +139,8 @@ void SalYieldMutex::doAcquire( sal_uInt32 nLockCount )
     WinSalInstance* pInst = GetSalData()->mpFirstInstance;
     if ( pInst && pInst->IsMainThread() )
     {
+        if ( pInst->mbNoYieldLock )
+            return;
         // tdf#96887 If this is the main thread, then we must wait for two things:
         // - the mpSalYieldMutex being freed
         // - SendMessage() being triggered
@@ -166,15 +169,31 @@ void SalYieldMutex::doAcquire( sal_uInt32 nLockCount )
 
 sal_uInt32 SalYieldMutex::doRelease( const bool bUnlockAll )
 {
-    sal_uInt32 nCount = comphelper::GenericSolarMutex::doRelease( bUnlockAll );
+    WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+    if ( pInst && pInst->mbNoYieldLock && pInst->IsMainThread() )
+        return 1;
 
+    sal_uInt32 nCount = comphelper::GenericSolarMutex::doRelease( bUnlockAll );
     // wake up ImplSalYieldMutexAcquireWithWait() after release
     if ( 0 == m_nCount )
         m_condition.set();
-
     return nCount;
 }
 
+bool SalYieldMutex::tryToAcquire()
+{
+    WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+    if ( pInst )
+    {
+        if ( pInst->mbNoYieldLock && pInst->IsMainThread() )
+            return true;
+        else
+            return comphelper::GenericSolarMutex::tryToAcquire();
+    }
+    else
+        return false;
+}
+
 void ImplSalYieldMutexAcquireWithWait( sal_uLong nCount )
 {
     WinSalInstance* pInst = GetSalData()->mpFirstInstance;
@@ -185,10 +204,7 @@ void ImplSalYieldMutexAcquireWithWait( sal_uLong nCount )
 bool ImplSalYieldMutexTryToAcquire()
 {
     WinSalInstance* pInst = GetSalData()->mpFirstInstance;
-    if ( pInst )
-        return pInst->mpSalYieldMutex->tryToAcquire();
-    else
-        return false;
+    return pInst ? pInst->mpSalYieldMutex->tryToAcquire() : false;
 }
 
 void ImplSalYieldMutexRelease()
@@ -203,8 +219,11 @@ void ImplSalYieldMutexRelease()
 
 bool SalYieldMutex::IsCurrentThread() const
 {
-    // For the Windows backend, the LO identifier is the system thread ID
-    return m_nThreadId == GetCurrentThreadId();
+    if ( !GetSalData()->mpFirstInstance->mbNoYieldLock )
+        // For the Windows backend, the LO identifier is the system thread ID
+        return m_nThreadId == GetCurrentThreadId();
+    else
+        return GetSalData()->mpFirstInstance->IsMainThread();
 }
 
 void SalData::initKeyCodeMap()
@@ -442,9 +461,10 @@ void DestroySalInstance( SalInstance* pInst )
 }
 
 WinSalInstance::WinSalInstance()
+    : mhComWnd( nullptr )
+    , mbNoYieldLock( false )
 {
-    mhComWnd                 = nullptr;
-    mpSalYieldMutex          = new SalYieldMutex();
+    mpSalYieldMutex = new SalYieldMutex();
     mpSalYieldMutex->acquire();
 }
 
@@ -483,8 +503,7 @@ static void ImplSalDispatchMessage( MSG* pMsg )
         ImplSalPostDispatchMsg( pMsg, lResult );
 }
 
-bool
-ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
+static bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
 {
     MSG aMsg;
     bool bWasMsg = false, bOneEvent = false;
@@ -533,38 +552,43 @@ bool WinSalInstance::IsMainThread() const
     return pSalData->mnAppThreadId == GetCurrentThreadId();
 }
 
-bool WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
+bool WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
 {
     bool bDidWork = false;
-    // NOTE: if nReleased != 0 this will be called without SolarMutex
-    //       so don't do anything dangerous before releasing it here
-    sal_uInt32 const nCount = (nReleased != 0)
-                              ? nReleased : mpSalYieldMutex->release( true );
+    SolarMutexReleaser aReleaser;
     if ( !IsMainThread() )
     {
-        // #97739# A SendMessage call blocks until the called thread (here: the main thread)
-        // returns. During a yield however, messages are processed in the main thread that might
-        // result in a new message loop due to opening a dialog. Thus, SendMessage would not
-        // return which will block this thread!
-        // Solution: just give up the time slice and hope that messages are processed
-        // by the main thread anyway (where all windows are created)
-        // If the mainthread is not currently handling messages, then our SendMessage would
-        // also do nothing, so this seems to be reasonable.
-
-        // #i18883# only sleep if potential deadlock scenario, ie, when a dialog is open
-        if( ImplGetSVData()->maAppData.mnModalMode )
-            Sleep(1);
-        else
-            // If you change the SendMessageW function, you might need to update
-            // the PeekMessage( ... PM_QS_POSTMESSAGE) calls!
-            bDidWork = SendMessageW( mhComWnd, SAL_MSG_THREADYIELD, (WPARAM)bWait, (LPARAM)bHandleAllCurrentEvents );
+        if ( bWait )
+        {
+            maWaitingYieldCond.reset();
+            maWaitingYieldCond.wait();
+            bDidWork = true;
+        }
+        else {
+            // #97739# A SendMessage call blocks until the called thread (here: the main thread)
+            // returns. During a yield however, messages are processed in the main thread that might
+            // result in a new message loop due to opening a dialog. Thus, SendMessage would not
+            // return which will block this thread!
+            // Solution: just give up the time slice and hope that messages are processed
+            // by the main thread anyway (where all windows are created)
+            // If the mainthread is not currently handling messages, then our SendMessage would
+            // also do nothing, so this seems to be reasonable.
+
+            // #i18883# only sleep if potential deadlock scenario, ie, when a dialog is open
+            if( ImplGetSVData()->maAppData.mnModalMode )
+                Sleep(1);
+            else
+                // If you change the SendMessageW function, you might need to update
+                // the PeekMessage( ... PM_QS_POSTMESSAGE) calls!
+                bDidWork = SendMessageW( mhComWnd, SAL_MSG_THREADYIELD,
+                                         (WPARAM)bWait, (LPARAM)bHandleAllCurrentEvents );
+        }
     }
     else
     {
-        if (nReleased == 0) // tdf#99383 ReAcquireSolarMutex shouldn't Yield
-            bDidWork = ImplSalYield( bWait, bHandleAllCurrentEvents );
+        bDidWork = ImplSalYield( bWait, bHandleAllCurrentEvents );
+        maWaitingYieldCond.set();
     }
-    mpSalYieldMutex->acquire( nCount );
 
     return bDidWork;
 }
@@ -572,6 +596,7 @@ bool WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong
 LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
 {
     LRESULT nRet = 0;
+    WinSalInstance *pInst = GetSalData()->mpFirstInstance;
 
     switch ( nMsg )
     {
@@ -594,19 +619,31 @@ LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, i
             static_cast<WinSalTimer*>(ImplGetSVData()->maSchedCtx.mpSalTimer)->ImplStop();
             break;
         case SAL_MSG_CREATEFRAME:
+            assert( !pInst->mbNoYieldLock );
+            pInst->mbNoYieldLock = true;
             nRet = reinterpret_cast<LRESULT>(ImplSalCreateFrame( GetSalData()->mpFirstInstance, reinterpret_cast<HWND>(lParam), (SalFrameStyleFlags)wParam ));
+            pInst->mbNoYieldLock = false;
             rDef = FALSE;
             break;
         case SAL_MSG_RECREATEHWND:
+            assert( !pInst->mbNoYieldLock );
+            pInst->mbNoYieldLock = true;
             nRet = reinterpret_cast<LRESULT>(ImplSalReCreateHWND( reinterpret_cast<HWND>(wParam), reinterpret_cast<HWND>(lParam), false ));
+            pInst->mbNoYieldLock = false;
             rDef = FALSE;
             break;
         case SAL_MSG_RECREATECHILDHWND:
+            assert( !pInst->mbNoYieldLock );
+            pInst->mbNoYieldLock = true;
             nRet = reinterpret_cast<LRESULT>(ImplSalReCreateHWND( reinterpret_cast<HWND>(wParam), reinterpret_cast<HWND>(lParam), true ));
+            pInst->mbNoYieldLock = false;
             rDef = FALSE;
             break;
         case SAL_MSG_DESTROYFRAME:
+            assert( !pInst->mbNoYieldLock );
+            pInst->mbNoYieldLock = true;
             delete reinterpret_cast<SalFrame*>(lParam);
+            pInst->mbNoYieldLock = false;
             rDef = FALSE;
             break;
         case SAL_MSG_DESTROYHWND:
@@ -622,19 +659,31 @@ LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, i
             rDef = FALSE;
             break;
         case SAL_MSG_CREATEOBJECT:
+            assert( !pInst->mbNoYieldLock );
+            pInst->mbNoYieldLock = true;
             nRet = reinterpret_cast<LRESULT>(ImplSalCreateObject( GetSalData()->mpFirstInstance, reinterpret_cast<WinSalFrame*>(lParam) ));
+            pInst->mbNoYieldLock = false;
             rDef = FALSE;
             break;
         case SAL_MSG_DESTROYOBJECT:
+            assert( !pInst->mbNoYieldLock );
+            pInst->mbNoYieldLock = true;
             delete reinterpret_cast<SalObject*>(lParam);
+            pInst->mbNoYieldLock = false;
             rDef = FALSE;
             break;
         case SAL_MSG_GETDC:
+            assert( !pInst->mbNoYieldLock );
+            pInst->mbNoYieldLock = true;
             nRet = reinterpret_cast<LRESULT>(GetDCEx( reinterpret_cast<HWND>(wParam), nullptr, DCX_CACHE ));
+            pInst->mbNoYieldLock = false;
             rDef = FALSE;
             break;
         case SAL_MSG_RELEASEDC:
+            assert( !pInst->mbNoYieldLock );
+            pInst->mbNoYieldLock = true;
             ReleaseDC( reinterpret_cast<HWND>(wParam), reinterpret_cast<HDC>(lParam) );
+            pInst->mbNoYieldLock = false;
             rDef = FALSE;
             break;
         case SAL_MSG_TIMER_CALLBACK:
@@ -644,7 +693,7 @@ LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, i
             MSG aMsg;
             bool bValidMSG = pTimer->IsValidWPARAM( wParam );
             // PM_QS_POSTMESSAGE is needed, so we don't process the SendMessage from DoYield!
-            while ( PeekMessageW(&aMsg, GetSalData()->mpFirstInstance->mhComWnd, SAL_MSG_TIMER_CALLBACK,
+            while ( PeekMessageW(&aMsg, pInst->mhComWnd, SAL_MSG_TIMER_CALLBACK,
                                  SAL_MSG_TIMER_CALLBACK, PM_REMOVE | PM_NOYIELD | PM_QS_POSTMESSAGE) )
             {
                 assert( !bValidMSG && "Unexpected non-last valid message" );
diff --git a/vcl/win/window/salframe.cxx b/vcl/win/window/salframe.cxx
index 4bcb1d6e09da..7195b3b91fb0 100644
--- a/vcl/win/window/salframe.cxx
+++ b/vcl/win/window/salframe.cxx
@@ -1051,10 +1051,15 @@ void WinSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
             if ( mpGraphics2->getDefPal() )
                 SelectPalette( mpGraphics2->getHDC(), mpGraphics2->getDefPal(), TRUE );
             mpGraphics2->DeInitGraphics();
-            SendMessageW( pSalData->mpFirstInstance->mhComWnd,
-                             SAL_MSG_RELEASEDC,
-                             reinterpret_cast<WPARAM>(mhWnd),
-                             reinterpret_cast<LPARAM>(mpGraphics2->getHDC()) );
+            // we don't want to run the WinProc in the main thread directly
+            // so we don't hit the mbNoYieldLock assert
+            if ( !pSalData->mpFirstInstance->IsMainThread() )
+                SendMessageW( pSalData->mpFirstInstance->mhComWnd,
+                              SAL_MSG_RELEASEDC,
+                              reinterpret_cast<WPARAM>(mhWnd),
+                              reinterpret_cast<LPARAM>(mpGraphics2->getHDC()) );
+            else
+                ReleaseDC( mhWnd, mpGraphics2->getHDC() );
             mpGraphics2->setHDC(nullptr);
             pSalData->mnCacheDCInUse--;
         }
commit 67aad01063113cf5cec38e1a89774df7d7715b95
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Fri Aug 25 22:03:47 2017 +0200

    OSX fix ODK example builds with enabled SIP
    
    The "System Integrity Protection”, introduced in macOS El Capitan,
    strips DYLD_* environment variables from all calls of software in
    /bin and /usr/bin.
    
    As a workaround we copy the shell to a temporary file and use it
    in our "sub-make" calls to build the examples.
    
    Change-Id: I3f07492782d56e153e8fcdea605a042ec1898276

diff --git a/odk/CustomTarget_build-examples.mk b/odk/CustomTarget_build-examples.mk
index 81ac3a1437c6..f7dc1db1e30d 100644
--- a/odk/CustomTarget_build-examples.mk
+++ b/odk/CustomTarget_build-examples.mk
@@ -93,6 +93,11 @@ ifneq ($(gb_SUPPRESS_TESTS),)
 	@true
 else
 	$(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),CHK,1)
+ifeq (MACOSX,$(OS))
+	$(eval ODK_BUILD_SHELL := $(shell $(gb_MKTEMP)))
+	cp /bin/sh "$(ODK_BUILD_SHELL)"
+	chmod 0700 "$(ODK_BUILD_SHELL)"
+endif
 	(saved_library_path=$${$(gb_Helper_LIBRARY_PATH_VAR)} && . $< \
         $(if $(filter MACOSX,$(OS)),, \
             && $(gb_Helper_LIBRARY_PATH_VAR)=$$saved_library_path) \
@@ -100,11 +105,16 @@ else
             UserInstallation=$(call gb_Helper_make_url,$(call gb_CustomTarget_get_workdir,odk/build-examples)/user) \
         $(foreach my_dir,$(my_example_dirs), \
             && (cd $(INSTDIR)/$(SDKDIRNAME)/examples/$(my_dir) \
-                && printf 'yes\n' | LC_ALL=C make))) \
+                && printf 'yes\n' | LC_ALL=C make \
+                    $(if $(filter MACOSX,$(OS)), SHELL=$(ODK_BUILD_SHELL), )))) \
             >$(call gb_CustomTarget_get_workdir,odk/build-examples)/log 2>&1 \
         || (RET=$$? \
+            $(if $(filter MACOSX,$(OS)), && rm -f $(ODK_BUILD_SHELL) , ) \
             && cat $(call gb_CustomTarget_get_workdir,odk/build-examples)/log \
             && exit $$RET)
+ifeq (MACOSX,$(OS))
+	-rm -f $(ODK_BUILD_SHELL)
+endif
 endif
 
 $(call gb_CustomTarget_get_workdir,odk/build-examples)/setsdkenv: \
commit 6ee9010baa0ccd82affd60070ed209d1d8022cae
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Fri Aug 25 14:52:38 2017 +0200

    Disable ScHeaderFooterTextCursor scenario test
    
    Just like the ScHeaderFooterTextObj, it depends on weak referenced
    objects, which might be gone / cleaned up at test time.
    
    Change-Id: I52503646c51b0915df11f5c7f90c16208e45879a

diff --git a/sc/qa/unoapi/sc_4.sce b/sc/qa/unoapi/sc_4.sce
index d631ac99878b..ce879cc83272 100644
--- a/sc/qa/unoapi/sc_4.sce
+++ b/sc/qa/unoapi/sc_4.sce
@@ -36,6 +36,8 @@
 # The css::text::XTextRange test fails often when the weak SHF_ContentObj is
 # already gone. If just this test is disabled, later tests of this object fail
 # too, so this disables the whole interface.
+# Same for ScHeaderFooterTextCursor.
+# -o sc.ScHeaderFooterTextCursor
 # -o sc.ScHeaderFooterTextObj
 -o sc.ScIndexEnumeration_CellAnnotationsEnumeration
 -o sc.ScIndexEnumeration_CellAreaLinksEnumeration
commit 1dff1eeaef2209b4ea3b12d6140a42169dde7b2a
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Fri Aug 25 11:12:24 2017 +0200

    Cleanup dbaccess module makefile
    
    Change-Id: Ic379a8362bb25fb1635c9900bbf247c8f2943c74

diff --git a/dbaccess/Module_dbaccess.mk b/dbaccess/Module_dbaccess.mk
index d9f80fc11540..4d1b9f44d623 100644
--- a/dbaccess/Module_dbaccess.mk
+++ b/dbaccess/Module_dbaccess.mk
@@ -32,36 +32,29 @@ $(eval $(call gb_Module_add_l10n_targets,dbaccess,\
 ))
 
 ifneq ($(OS),IOS)
-ifeq ($(ENABLE_FIREBIRD_SDBC),TRUE)
-$(eval $(call gb_Module_add_check_targets,dbaccess,\
-    CppunitTest_dbaccess_firebird_test \
-))
-endif
 
 $(eval $(call gb_Module_add_check_targets,dbaccess,\
 	CppunitTest_dbaccess_dialog_save \
 	CppunitTest_dbaccess_empty_stdlib_save \
 	CppunitTest_dbaccess_nolib_save \
 	CppunitTest_dbaccess_macros_test \
-	$(if $(ENABLE_JAVA), \
-		CppunitTest_dbaccess_RowSetClones) \
 ))
 
 ifeq ($(ENABLE_JAVA),TRUE)
+
 $(eval $(call gb_Module_add_check_targets,dbaccess,\
+    CppunitTest_dbaccess_RowSetClones \
     CppunitTest_dbaccess_hsqldb_test \
 ))
-endif
 
 # This runs a suite of performance tests on embedded firebird and HSQLDB.
 # Instructions on running the test can be found in qa/unit/embeddedb_performancetest
 ifeq ($(ENABLE_FIREBIRD_SDBC),TRUE)
-ifeq ($(ENABLE_JAVA),TRUE)
 $(eval $(call gb_Module_add_check_targets,dbaccess,\
+    CppunitTest_dbaccess_firebird_test \
     CppunitTest_dbaccess_embeddeddb_performancetest \
 ))
 endif
-endif
 
 $(eval $(call gb_Module_add_subsequentcheck_targets,dbaccess,\
 	JunitTest_dbaccess_complex \
@@ -69,19 +62,20 @@ $(eval $(call gb_Module_add_subsequentcheck_targets,dbaccess,\
 ))
 
 ifneq ($(DISABLE_PYTHON),TRUE)
-ifneq ($(ENABLE_JAVA),)
 $(eval $(call gb_Module_add_subsequentcheck_targets,dbaccess,\
 	PythonTest_dbaccess_python \
 ))
 endif
-endif
+
+endif # ifeq ($(ENABLE_JAVA),TRUE)
 
 # screenshots
 $(eval $(call gb_Module_add_screenshot_targets,dbaccess,\
     CppunitTest_dbaccess_dialogs_test \
 ))
 
-endif
+endif # ifneq ($(OS),IOS)
+
 endif
 
 # vim: set noet sw=4 ts=4:
commit 45fe444c7e85dcc22461560d7f7b682f707aa218
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Thu Aug 24 13:41:37 2017 +0200

    tdf#111994 WIN workaround PostMessage delays
    
    Fixes the "Multiple timers in queue" assertion by effectively
    removing it.
    
    When debugging it became obvious, that PostMessage returns, even
    if the message was not yet added to the message queue.
    
    The assert happens, because we start the timer in the Scheduler
    before Invoke(), so it fires, if we block in Invoke(), and then
    reset the timer after Invoke, if there were changes to the Task
    list.
    
    In this case it fires during Invoke(), the message is added. We
    restart the timer, first by stopping it (we wait in
    DeleteTimerQueueTimer, to be sure the timer function has either
    finished or was not run). And the try to remove the message with
    PeekMessageW, which doesn't remove the posted message.
    
    Then the timer is restarted, and when the event is processed, we
    end up with an additional timer event, which was asserted.
    
    As a fix this adds a (microsecond) timestamp to the timer message,
    which is validated in the WinProc function. So if we stop the
    timer too fast, the event is ignored based on the timestamp.
    
    And while at it, the patch moves timer related variables from
    SalData into WinSalTimer.
    
    Change-Id: Ib840a421e8bd040d40f39473e1d44491e5b332bd

diff --git a/vcl/README.scheduler b/vcl/README.scheduler
index 0cd5a24d5f83..0389dc94d723 100644
--- a/vcl/README.scheduler
+++ b/vcl/README.scheduler
@@ -129,6 +129,13 @@ Therefore the current solution always starts a (threaded) timer even for the
 instant Idles and syncs to this timer message in the main dispatch loop.
 Using SwitchToThread(), this seem to work reasonably well.
 
+An additional workaround is implemented for the delayed queuing of posted
+messages, where PeekMessage in WinSalTimer::Stop() won't be able remove the
+just posted timer callback message. We handle this by adding a timestamp to
+the timer callback message, which is checked before starting the Scheduler.
+This way we can end with multiple timer callback message in the queue, which
+we were asserting.
+
 == KDE implementation details ==
 
 This implementation also works as intended. But there is a different Yield
@@ -183,3 +190,11 @@ mbStatic workaround from the Task class.
 
 This would probably get rid of most of the MacOS and Windows implementation
 details / workarounds, but is quite probably a large amount of work.
+
+== Re-evaluate the MacOS ImplNSAppPostEvent ==
+
+Probably a solution comparable to the Windows backends delayed PostMessage
+workaround using a validation timestamp is better then the current peek,
+remove, re-postEvent, which has to run in the main thread.
+
+Originally I didn't evaluate, if the event is actually lost or just delayed.
diff --git a/vcl/inc/win/saldata.hxx b/vcl/inc/win/saldata.hxx
index bc5b9c5db1eb..245d986915b1 100644
--- a/vcl/inc/win/saldata.hxx
+++ b/vcl/inc/win/saldata.hxx
@@ -84,8 +84,6 @@ public:
     long*                   mpDitherDiff;           // Dither mapping table
     BYTE*                   mpDitherLow;            // Dither mapping table
     BYTE*                   mpDitherHigh;           // Dither mapping table
-    HANDLE                  mnTimerId;              ///< Windows timer id
-    bool                    mbOnIdleRunScheduler;   ///< Run yield until the scheduler processed the idle
     HHOOK                   mhSalObjMsgHook;        // hook to get interesting msg for SalObject
     HWND                    mhWantLeaveMsg;         // window handle, that want a MOUSELEAVE message
     AutoTimer*              mpMouseLeaveTimer;      // Timer for MouseLeave Test
@@ -178,8 +176,6 @@ void ImplSalYieldMutexRelease();
 
 LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
 
-void EmitTimerCallback();
-
 void SalTestMouseLeave();
 
 bool ImplHandleSalObjKeyMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
diff --git a/vcl/inc/win/saltimer.h b/vcl/inc/win/saltimer.h
index 084a25745b87..614de61445b2 100644
--- a/vcl/inc/win/saltimer.h
+++ b/vcl/inc/win/saltimer.h
@@ -24,16 +24,45 @@
 
 class WinSalTimer : public SalTimer
 {
+    HANDLE       m_nTimerId;             ///< Windows timer id
+    sal_uInt32   m_nTimerStartTicks;     ///< system ticks at timer start % SAL_MAX_UINT32
+    bool         m_bOnIdleRunScheduler;  ///< Run yield until the scheduler processed the idle
+
 public:
-    WinSalTimer() {}
+    WinSalTimer();
     virtual ~WinSalTimer() override;
 
     virtual void Start(sal_uIntPtr nMS) override;
     virtual void Stop() override;
+
+    inline bool IsValidWPARAM( WPARAM wParam ) const;
+
+    inline bool WantBusyLoop() const;
+    inline void ResetBusyLoop();
+
+    // The Impl functions are just public to be called from the static
+    // SalComWndProc on main thread redirect! Otherwise they would be private.
+    // They must be called from the main application thread only!
+
+    void ImplStart( sal_uIntPtr nMS );
+    void ImplStop();
+    void ImplEmitTimerCallback();
 };
 
-void ImplSalStartTimer( sal_uIntPtr nMS );
-void ImplSalStopTimer();
+inline bool WinSalTimer::IsValidWPARAM( WPARAM aWPARAM ) const
+{
+    return aWPARAM == m_nTimerStartTicks;
+}
+
+inline bool WinSalTimer::WantBusyLoop() const
+{
+    return m_bOnIdleRunScheduler;
+}
+
+inline void WinSalTimer::ResetBusyLoop()
+{
+    m_bOnIdleRunScheduler = false;
+}
 
 #endif
 
diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx
index 12f95aac31f2..d1bce72f7328 100644
--- a/vcl/win/app/salinst.cxx
+++ b/vcl/win/app/salinst.cxx
@@ -247,8 +247,6 @@ SalData::SalData()
     mpDitherDiff = nullptr;     // Dither mapping table
     mpDitherLow = nullptr;      // Dither mapping table
     mpDitherHigh = nullptr;     // Dither mapping table
-    mnTimerId = nullptr;        // windows timer id
-    mbOnIdleRunScheduler = false; // if yield is idle, run the scheduler
     mhSalObjMsgHook = nullptr;  // hook to get interesting msg for SalObject
     mhWantLeaveMsg = nullptr;   // window handle, that want a MOUSELEAVE message
     mpMouseLeaveTimer = nullptr; // Timer for MouseLeave Test
@@ -490,7 +488,8 @@ ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
 {
     MSG aMsg;
     bool bWasMsg = false, bOneEvent = false;
-    SalData *const pSalData = GetSalData();
+    ImplSVData *const pSVData = ImplGetSVData();
+    WinSalTimer* pTimer = static_cast<WinSalTimer*>( pSVData->maSchedCtx.mpSalTimer );
 
     int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
     do
@@ -506,7 +505,7 @@ ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
             // busy loop to catch the 0ms timeout
             // We don't need to busy loop, if we wait anyway.
             // Even if we didn't process the event directly, report it.
-            if ( pSalData->mbOnIdleRunScheduler && !bWait )
+            if ( pTimer && pTimer->WantBusyLoop() && !bWait )
             {
                 SwitchToThread();
                 nMaxEvents++;
@@ -516,7 +515,7 @@ ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
     } while( --nMaxEvents && bOneEvent );
 
     // Also check that we don't wait when application already has quit
-    if ( bWait && !bWasMsg && !ImplGetSVData()->maAppData.mbAppQuit )
+    if ( bWait && !bWasMsg && !pSVData->maAppData.mbAppQuit )
     {
         if ( GetMessageW( &aMsg, nullptr, 0, 0 ) )
         {
@@ -582,17 +581,17 @@ LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, i
             break;
         case SAL_MSG_STARTTIMER:
         {
-            sal_uLong nTime = GetTickCount();
-            if ( nTime < (sal_uLong) lParam )
-                nTime = (sal_uLong) lParam - nTime;
+            sal_uInt64 nTime = tools::Time::GetSystemTicks();
+            if ( nTime < (sal_uInt64) lParam )
+                nTime = (sal_uInt64) lParam - nTime;
             else
                 nTime = 0;
-            ImplSalStartTimer( nTime );
+            static_cast<WinSalTimer*>(ImplGetSVData()->maSchedCtx.mpSalTimer)->ImplStart( nTime );
             rDef = FALSE;
             break;
         }
         case SAL_MSG_STOPTIMER:
-            ImplSalStopTimer();
+            static_cast<WinSalTimer*>(ImplGetSVData()->maSchedCtx.mpSalTimer)->ImplStop();
             break;
         case SAL_MSG_CREATEFRAME:
             nRet = reinterpret_cast<LRESULT>(ImplSalCreateFrame( GetSalData()->mpFirstInstance, reinterpret_cast<HWND>(lParam), (SalFrameStyleFlags)wParam ));
@@ -639,14 +638,25 @@ LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, i
             rDef = FALSE;
             break;
         case SAL_MSG_TIMER_CALLBACK:
+        {
+            WinSalTimer *const pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
+            assert( pTimer != nullptr );
             MSG aMsg;
+            bool bValidMSG = pTimer->IsValidWPARAM( wParam );
             // PM_QS_POSTMESSAGE is needed, so we don't process the SendMessage from DoYield!
-            while ( PeekMessageW(&aMsg, nullptr, SAL_MSG_TIMER_CALLBACK,
+            while ( PeekMessageW(&aMsg, GetSalData()->mpFirstInstance->mhComWnd, SAL_MSG_TIMER_CALLBACK,
                                  SAL_MSG_TIMER_CALLBACK, PM_REMOVE | PM_NOYIELD | PM_QS_POSTMESSAGE) )
-                assert(! "Multiple timer messages in queue" );
-            GetSalData()->mbOnIdleRunScheduler = false;
-            EmitTimerCallback();
+            {
+                assert( !bValidMSG && "Unexpected non-last valid message" );
+                bValidMSG = pTimer->IsValidWPARAM( aMsg.wParam );
+            }
+            if ( bValidMSG )
+            {
+                pTimer->ResetBusyLoop();
+                pTimer->ImplEmitTimerCallback();
+            }
             break;
+        }
     }
 
     return nRet;
diff --git a/vcl/win/app/saltimer.cxx b/vcl/win/app/saltimer.cxx
index d57eefd63efc..f220ae8ca33e 100644
--- a/vcl/win/app/saltimer.cxx
+++ b/vcl/win/app/saltimer.cxx
@@ -31,31 +31,28 @@ static void CALLBACK SalTimerProc(PVOID pParameter, BOOLEAN bTimerOrWaitFired);
 // deletion of timer (which is extremely likely, given that
 // INVALID_HANDLE_VALUE waits for the callback to run on the main thread),
 // this must run on the main thread too
-void ImplSalStopTimer()
+void WinSalTimer::ImplStop()
 {
     SalData *const pSalData = GetSalData();
-    assert( !pSalData->mpFirstInstance || pSalData->mnAppThreadId == GetCurrentThreadId() );
+    const WinSalInstance *pInst = pSalData->mpFirstInstance;
+    assert( !pInst || pSalData->mnAppThreadId == GetCurrentThreadId() );
 
-    HANDLE hTimer = pSalData->mnTimerId;
-    if (hTimer)
-    {
-        pSalData->mnTimerId = nullptr;
-        DeleteTimerQueueTimer(nullptr, hTimer, INVALID_HANDLE_VALUE);
-    }
+    const HANDLE hTimer = m_nTimerId;
+    if ( nullptr == hTimer )
+        return;
 
-    // remove all pending SAL_MSG_TIMER_CALLBACK messages
-    // we always have to do this, since ImplSalStartTimer with 0ms just queues
-    // a new SAL_MSG_TIMER_CALLBACK message
+    m_nTimerId = nullptr;
+    m_nTimerStartTicks = 0;
+    DeleteTimerQueueTimer( nullptr, hTimer, INVALID_HANDLE_VALUE );
+
+    // remove as many pending SAL_MSG_TIMER_CALLBACK messages as possible
     // PM_QS_POSTMESSAGE is needed, so we don't process the SendMessage from DoYield!
     MSG aMsg;
-    int nMsgCount = 0;
-    while ( PeekMessageW(&aMsg, nullptr, SAL_MSG_TIMER_CALLBACK,
-                         SAL_MSG_TIMER_CALLBACK, PM_REMOVE | PM_NOYIELD | PM_QS_POSTMESSAGE) )
-        nMsgCount++;
-    assert( nMsgCount <= 1 );
+    while ( PeekMessageW(&aMsg, pInst->mhComWnd, SAL_MSG_TIMER_CALLBACK,
+                         SAL_MSG_TIMER_CALLBACK, PM_REMOVE | PM_NOYIELD | PM_QS_POSTMESSAGE) );
 }
 
-void ImplSalStartTimer( sal_uLong nMS )
+void WinSalTimer::ImplStart( sal_uLong nMS )
 {
     SalData* pSalData = GetSalData();
     assert( !pSalData->mpFirstInstance || pSalData->mnAppThreadId == GetCurrentThreadId() );
@@ -65,17 +62,26 @@ void ImplSalStartTimer( sal_uLong nMS )
         nMS = SAL_MAX_UINT32;
 
     // cannot change a one-shot timer, so delete it and create a new one
-    ImplSalStopTimer();
+    ImplStop();
 
     // keep the scheduler running, if a 0ms timer / Idle is scheduled
-    pSalData->mbOnIdleRunScheduler = ( 0 == nMS );
+    m_bOnIdleRunScheduler = ( 0 == nMS );
+    m_nTimerStartTicks = osl_getMonotonicTicks() % SAL_MAX_UINT32;
     // probably WT_EXECUTEONLYONCE is not needed, but it enforces Period
     // to be 0 and should not hurt; also see
     // https://www.microsoft.com/msj/0499/pooling/pooling.aspx
-    CreateTimerQueueTimer(&pSalData->mnTimerId, nullptr, SalTimerProc, nullptr,
+    CreateTimerQueueTimer(&m_nTimerId, nullptr, SalTimerProc,
+                          (void*) m_nTimerStartTicks,
                           nMS, 0, WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE);
 }
 
+WinSalTimer::WinSalTimer()
+    : m_nTimerId( nullptr )
+    , m_nTimerStartTicks( 0 )
+    , m_bOnIdleRunScheduler( false )
+{
+}
+
 WinSalTimer::~WinSalTimer()
 {
     Stop();
@@ -83,28 +89,28 @@ WinSalTimer::~WinSalTimer()
 
 void WinSalTimer::Start( sal_uLong nMS )
 {
-    SalData* pSalData = GetSalData();
-    if ( pSalData->mpFirstInstance && pSalData->mnAppThreadId != GetCurrentThreadId() )
+    WinSalInstance *pInst = GetSalData()->mpFirstInstance;
+    if ( pInst && !pInst->IsMainThread() )
     {
-        BOOL const ret = PostMessageW(pSalData->mpFirstInstance->mhComWnd,
-            SAL_MSG_STARTTIMER, 0, (LPARAM)GetTickCount() + nMS);
+        BOOL const ret = PostMessageW(pInst->mhComWnd,
+            SAL_MSG_STARTTIMER, 0, (LPARAM) tools::Time::GetSystemTicks() + nMS);
         SAL_WARN_IF(0 == ret, "vcl", "ERROR: PostMessage() failed!");
     }
     else
-        ImplSalStartTimer( nMS );
+        ImplStart( nMS );
 }
 
 void WinSalTimer::Stop()
 {
-    SalData* pSalData = GetSalData();
-    if ( pSalData->mpFirstInstance && pSalData->mnAppThreadId != GetCurrentThreadId() )
+    WinSalInstance *pInst = GetSalData()->mpFirstInstance;
+    if ( pInst && !pInst->IsMainThread() )
     {
-        BOOL const ret = PostMessageW(pSalData->mpFirstInstance->mhComWnd,
+        BOOL const ret = PostMessageW(pInst->mhComWnd,
             SAL_MSG_STOPTIMER, 0, 0);
         SAL_WARN_IF(0 == ret, "vcl", "ERROR: PostMessage() failed!");
     }
     else
-        ImplSalStopTimer();
+        ImplStop();
 }
 
 /** This gets invoked from a Timer Queue thread.
@@ -112,20 +118,18 @@ void WinSalTimer::Stop()
 Don't acquire the SolarMutex to avoid deadlocks, just wake up the main thread
 at better resolution than 10ms.
 */
-static void CALLBACK SalTimerProc(PVOID, BOOLEAN)
+static void CALLBACK SalTimerProc(PVOID data, BOOLEAN)
 {
     __try
     {
-        SalData* pSalData = GetSalData();
-
         // always post message when the timer fires, we will remove the ones
         // that happened during execution of the callback later directly from
         // the message queue
-        BOOL const ret = PostMessageW(pSalData->mpFirstInstance->mhComWnd,
-                                      SAL_MSG_TIMER_CALLBACK, 0, 0);
+        BOOL const ret = PostMessageW(GetSalData()->mpFirstInstance->mhComWnd,
+                                      SAL_MSG_TIMER_CALLBACK, (WPARAM) data, 0);
 #if OSL_DEBUG_LEVEL > 0
         if (0 == ret) // SEH prevents using SAL_WARN here?
-            fputs("ERROR: PostMessage() failed!", stderr);
+            fputs("ERROR: PostMessage() failed!\n", stderr);
 #endif
     }
     __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
@@ -133,22 +137,13 @@ static void CALLBACK SalTimerProc(PVOID, BOOLEAN)
     }
 }
 
-/** Called in the main thread.
-
-We assured that by posting the message from the SalTimeProc only, the real
-call then happens when the main thread gets SAL_MSG_TIMER_CALLBACK.
-*/
-void EmitTimerCallback()
+void WinSalTimer::ImplEmitTimerCallback()
 {
     // Test for MouseLeave
     SalTestMouseLeave();
 
-    ImplSVData *pSVData = ImplGetSVData();
-    if ( ! pSVData->maSchedCtx.mpSalTimer )
-        return;
-
     ImplSalYieldMutexAcquireWithWait();
-    pSVData->maSchedCtx.mpSalTimer->CallCallback();
+    CallCallback();
     ImplSalYieldMutexRelease();
 }
 
commit 3b835b431bc4476cd44edc3ef3407345df609401
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Thu Aug 24 18:54:21 2017 +0200

    Don't run the OLEObjCache timer for an empty cache
    
    Change-Id: I210f6bdec14491bea6d15bca133011059091f21b

diff --git a/svx/source/svdraw/svdetc.cxx b/svx/source/svdraw/svdetc.cxx
index 9cc6708020bb..61a9fbb5c797 100644
--- a/svx/source/svdraw/svdetc.cxx
+++ b/svx/source/svdraw/svdetc.cxx
@@ -113,8 +113,6 @@ OLEObjCache::OLEObjCache()
     pTimer->SetInvokeHandler( LINK(this, OLEObjCache, UnloadCheckHdl) );
     pTimer->SetTimeout(20000);
     pTimer->SetStatic();
-    pTimer->Invoke();
-    pTimer->Start();
 }
 
 OLEObjCache::~OLEObjCache()
@@ -196,6 +194,9 @@ void OLEObjCache::InsertObj(SdrOle2Obj* pObj)
         // a new object was inserted, recalculate the cache
         UnloadOnDemand();
     }
+
+    if ( !pTimer->IsActive() )
+        pTimer->Start();
 }
 
 void OLEObjCache::RemoveObj(SdrOle2Obj* pObj)
@@ -203,6 +204,8 @@ void OLEObjCache::RemoveObj(SdrOle2Obj* pObj)
     std::vector<SdrOle2Obj*>::iterator it = std::find(maObjs.begin(), maObjs.end(), pObj);
     if (it != maObjs.end())
         maObjs.erase(it);
+    if (maObjs.empty())
+        pTimer->Stop();
 }
 
 size_t OLEObjCache::size() const
commit 72ba101882b2b4a0cf50d15d4c5bf87a22b93fb1
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Wed Aug 23 16:07:50 2017 +0200

    Workaround static Task destruction error
    
    A task has to get the SchedulerLock to remove itself from the
    Scheduler list. This doesn't work, if the Task is static, as the
    static Scheduler might be destroyed earlier. In this case we fail
    with the following backtrace:
    
     #0 SchedulerMutex::acquire
     #1 Task::~Task
     #2 __run_exit_handlers
    
    Thanks to Michael Stahl to catching this backtrace.
    
    As a workaround this marks static tasks, so they ignore the
    SchedulerMutex in the destructor, We also mark all scheduled Tasks
    as "static" in DeInitScheduler, as their cleanup was already done.
    
    In the end all Tasks should be removed from static objects.
    
    Change-Id: I38be3206378b9449193efaccbc96896ac8de9478

diff --git a/include/vcl/task.hxx b/include/vcl/task.hxx
index e45fe3f5ae73..2711d4343932 100644
--- a/include/vcl/task.hxx
+++ b/include/vcl/task.hxx
@@ -47,6 +47,7 @@ class VCL_DLLPUBLIC Task
     const sal_Char    *mpDebugName;     ///< Useful for debugging
     TaskPriority       mePriority;      ///< Task priority
     bool               mbActive;        ///< Currently in the scheduler
+    bool               mbStatic;        ///< Is a static object
 
 protected:
     static void StartTimer( sal_uInt64 nMS );
@@ -88,6 +89,15 @@ public:
     void            Stop();
 
     bool            IsActive() const { return mbActive; }
+
+    /**
+     * This function must be called for static tasks, so the Task destructor
+     * ignores the SchedulerMutex, as it may not be available anymore.
+     * The cleanup is still correct, as it has already happened in
+     * DeInitScheduler call well before the static destructor calls.
+     */
+    void            SetStatic() { mbStatic = true; }
+    bool            IsStatic() const { return mbStatic; }
 };
 
 #endif // INCLUDED_VCL_TASK_HXX
diff --git a/svx/source/svdraw/svdetc.cxx b/svx/source/svdraw/svdetc.cxx
index 7ea0e0b686ba..9cc6708020bb 100644
--- a/svx/source/svdraw/svdetc.cxx
+++ b/svx/source/svdraw/svdetc.cxx
@@ -112,6 +112,7 @@ OLEObjCache::OLEObjCache()
     pTimer = new AutoTimer( "svx OLEObjCache pTimer UnloadCheck" );
     pTimer->SetInvokeHandler( LINK(this, OLEObjCache, UnloadCheckHdl) );
     pTimer->SetTimeout(20000);
+    pTimer->SetStatic();
     pTimer->Invoke();
     pTimer->Start();
 }
diff --git a/vcl/README.scheduler b/vcl/README.scheduler
index 0059e6ebdc57..0cd5a24d5f83 100644
--- a/vcl/README.scheduler
+++ b/vcl/README.scheduler
@@ -172,6 +172,13 @@ Since the Scheduler is always handled by the system message queue, there is
 really no more reasoning to stop after 100 events to prevent LO Scheduler
 starvation.
 
+== Drop static inherited or composed Task objects ==
+
+The sequence of destruction of static objects is not defined. So a static Task
+can not be guaranteed to happen before the Scheduler. When dynamic unloading
+is involved, this becomes an even worse problem. This way we could drop the
+mbStatic workaround from the Task class.
+
 == Run the LO application in its own thread ==
 
 This would probably get rid of most of the MacOS and Windows implementation
diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx
index c1960fb2f6e7..6e01bc55980c 100644
--- a/vcl/source/app/scheduler.cxx
+++ b/vcl/source/app/scheduler.cxx
@@ -159,6 +159,7 @@ void Scheduler::ImplDeInitScheduler()
                 pTask->mbActive = false;
             }
             pTask->mpSchedulerData = nullptr;
+            pTask->SetStatic();
         }
         ImplSchedulerData* pDeleteSchedulerData = pSchedulerData;
         pSchedulerData = pSchedulerData->mpNext;
@@ -545,6 +546,7 @@ Task::Task( const sal_Char *pDebugName )
     , mpDebugName( pDebugName )
     , mePriority( TaskPriority::DEFAULT )
     , mbActive( false )
+    , mbStatic( false )
 {
 }
 
@@ -553,6 +555,7 @@ Task::Task( const Task& rTask )
     , mpDebugName( rTask.mpDebugName )
     , mePriority( rTask.mePriority )
     , mbActive( false )
+    , mbStatic( false )
 {
     if ( rTask.IsActive() )
         Start();
@@ -560,9 +563,14 @@ Task::Task( const Task& rTask )
 
 Task::~Task() COVERITY_NOEXCEPT_FALSE
 {
-    SchedulerGuard aSchedulerGuard;
-    if ( mpSchedulerData )
-        mpSchedulerData->mpTask = nullptr;
+    if ( !IsStatic() )
+    {
+        SchedulerGuard aSchedulerGuard;
+        if ( mpSchedulerData )
+            mpSchedulerData->mpTask = nullptr;
+    }
+    else
+        assert( nullptr == mpSchedulerData );
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/gdi/salbmp.cxx b/vcl/win/gdi/salbmp.cxx
index c9216bfd0109..fb8fb10d8055 100644
--- a/vcl/win/gdi/salbmp.cxx
+++ b/vcl/win/gdi/salbmp.cxx
@@ -80,7 +80,7 @@ public:
         maEntries()
     {
         SetTimeout(1000);
-        Stop();
+        SetStatic();
     }
 
     ~GdiPlusBuffer() override
commit ed30a3c8a5b721becdc71cf0e0fc150e4fef42da
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Tue Aug 8 15:03:37 2017 +0200

    tdf#99784 OSX run GUI stuff in the main thread
    
    The extension manager starts dialogs from its own thread. But the
    OSX backend currently doesn't defer these calls to the main thread.
    This implements the deference by running the called function
    in the main thread, using a code ^Block, and returning the result
    via a SalYieldMutex member.
    
    Change-Id: Id8977991e3eda91da27c23d8021e028d4f4cefe5

diff --git a/include/vcl/pointr.hxx b/include/vcl/pointr.hxx
index c82fb2236db0..8370b9f9d296 100644
--- a/include/vcl/pointr.hxx
+++ b/include/vcl/pointr.hxx
@@ -23,8 +23,6 @@
 #include <vcl/dllapi.h>
 #include <vcl/ptrstyle.hxx>
 
-class Point;
-
 class VCL_DLLPUBLIC Pointer
 {
     PointerStyle    meStyle;
diff --git a/vcl/README.scheduler b/vcl/README.scheduler
index 0251ab88fcab..0059e6ebdc57 100644
--- a/vcl/README.scheduler
+++ b/vcl/README.scheduler
@@ -94,7 +94,19 @@ can be added to the scheduler reasonably.
 Generally the Scheduler is handled as expected, except on resize, which is
 handled with different runloop-modes in MacOS. In case of a resize, the normal
 runloop is suspended in sendEvent, so we can't call the scheduler via posted
-main loop-events. Instead the schedule the timer again.
+main loop-events. Instead the scheduler uses the timer again.
+
+Like the Windows backend, all Cocoa / GUI handling also has to be run in
+the main thread. We're emulating Windows out-of-order PeekMessage processing,
+via a YieldWakeupEvent and two conditionals. When in a RUNINMAIN call, all
+the DBG_TESTSOLARMUTEX calls are disabled, as we can't release the SolarMutex,
+but we can prevent running any other SolarMutex based code. Same for all the
+SolarMutex acquire and release calls, so the calling and the main thread
+don't deadlock.
+
+We can neigher rely on MacOS dispatch_sync code block execution nor the
+message handling, as both can't be priorized or filtered and the first
+does also not allow nested execution and is just processed in sequence.
 
 There is also a workaround for a problem for pushing tasks to an empty queue,
 as [NSApp postEvent: ... atStart: NO] doesn't append the event, if the
@@ -159,3 +171,8 @@ easy way to process just a single event).
 Since the Scheduler is always handled by the system message queue, there is
 really no more reasoning to stop after 100 events to prevent LO Scheduler
 starvation.
+
+== Run the LO application in its own thread ==
+
+This would probably get rid of most of the MacOS and Windows implementation
+details / workarounds, but is quite probably a large amount of work.
diff --git a/vcl/inc/osx/runinmain.hxx b/vcl/inc/osx/runinmain.hxx
new file mode 100644
index 000000000000..e9ef9113d041
--- /dev/null
+++ b/vcl/inc/osx/runinmain.hxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX
+#define INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX
+
+/**
+ * Runs a command in the main thread.
+ *
+ * These macros are always used like a recursive calls, so they work like
+ * a closure.
+ *
+ * Uses two conditionals for a two way communication.
+ * The data (code block + result) is protected by the SolarMutex.
+ *
+ * There are three main macros, which act as function initializers:
+ *  - OSX_RUNINMAIN - for all functions without return values
+ *  - OSX_RUNINMAIN_POINTER - for all functions returning a pointer
+ *  - OSX_RUNINMAIN_UNION - for all other return types
+ *
+ * All types used via OSX_RUNINMAIN_UNION must implement a move constructor,
+ * so there is no memory leak!
+ */
+
+#include <unordered_map>
+
+#include <Block.h>
+
+#include <osl/thread.h>
+
+#include "saltimer.h"
+#include "salframe.hxx"
+
+union RuninmainResult
+{
+    void*                            pointer;
+    bool                             boolean;
+    struct SalFrame::SalPointerState state;
+
+    RuninmainResult() {}
+};
+
+#define OSX_RUNINMAIN_MEMBERS \
+    osl::Condition          m_aInMainCondition; \
+    osl::Condition          m_aResultCondition; \
+    RuninmainBlock          m_aCodeBlock; \
+    RuninmainResult         m_aResult;
+
+#define OSX_RUNINMAIN( instance, command ) \
+    if ( !instance->IsMainThread() ) \
+    { \
+        DBG_TESTSOLARMUTEX(); \
+        SalYieldMutex *aMutex = static_cast<SalYieldMutex*>(instance->GetYieldMutex()); \
+        assert( !aMutex->m_aCodeBlock ); \
+        aMutex->m_aCodeBlock = Block_copy(^{ \
+            command; \
+        }); \
+        aMutex->m_aResultCondition.reset(); \
+        dispatch_async(dispatch_get_main_queue(),^{ \
+            ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); \
+            }); \
+        aMutex->m_aInMainCondition.set(); \
+        osl::Condition::Result res =  aMutex->m_aResultCondition.wait(); \
+        assert(osl::Condition::Result::result_ok == res); \
+        return; \
+    }
+
+#define OSX_RUNINMAIN_POINTER( instance, command, type ) \
+    if ( !instance->IsMainThread() ) \
+    { \
+        DBG_TESTSOLARMUTEX(); \
+        SalYieldMutex *aMutex = static_cast<SalYieldMutex*>(instance->GetYieldMutex()); \
+        assert( !aMutex->m_aCodeBlock ); \
+        aMutex->m_aCodeBlock = Block_copy(^{ \
+            aMutex->m_aResult.pointer = static_cast<void*>( command ); \
+        }); \
+        aMutex->m_aResultCondition.reset(); \
+        dispatch_async(dispatch_get_main_queue(),^{ \
+            ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); \
+            }); \
+        aMutex->m_aInMainCondition.set(); \
+        osl::Condition::Result res =  aMutex->m_aResultCondition.wait(); \
+        assert(osl::Condition::Result::result_ok == res); \
+        return static_cast<type>( aMutex->m_aResult.pointer ); \
+    }
+
+#define OSX_RUNINMAIN_UNION( instance, command, member ) \
+    if ( !instance->IsMainThread() ) \
+    { \
+        DBG_TESTSOLARMUTEX(); \
+        SalYieldMutex *aMutex = static_cast<SalYieldMutex*>(instance->GetYieldMutex()); \
+        assert( !aMutex->m_aCodeBlock ); \
+        aMutex->m_aCodeBlock = Block_copy(^{ \
+            aMutex->m_aResult.member = command; \
+        }); \
+        aMutex->m_aResultCondition.reset(); \
+        dispatch_async(dispatch_get_main_queue(),^{ \
+            ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); \
+            }); \
+        aMutex->m_aInMainCondition.set(); \
+        osl::Condition::Result res =  aMutex->m_aResultCondition.wait(); \
+        assert(osl::Condition::Result::result_ok == res); \
+        return std::move( aMutex->m_aResult.member ); \
+    }
+
+/**
+ * convenience macros used from SalInstance
+ */
+
+#define OSX_INST_RUNINMAIN( command ) \
+    OSX_RUNINMAIN( this, command )
+
+#define OSX_INST_RUNINMAIN_POINTER( command, type ) \
+    OSX_RUNINMAIN_POINTER( this, command, type )
+
+#define OSX_INST_RUNINMAIN_UNION( command, member ) \
+    OSX_RUNINMAIN_UNION( this, command, member )
+
+/**
+ * convenience macros using global SalData
+ */
+
+#define OSX_SALDATA_RUNINMAIN( command ) \
+    OSX_RUNINMAIN( GetSalData()->mpFirstInstance, command )
+
+#define OSX_SALDATA_RUNINMAIN_POINTER( command, type ) \
+    OSX_RUNINMAIN_POINTER( GetSalData()->mpFirstInstance, command, type )
+
+#define OSX_SALDATA_RUNINMAIN_UNION( command, member ) \
+    OSX_RUNINMAIN_UNION( GetSalData()->mpFirstInstance, command, member )
+
+#endif // INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/osx/saldata.hxx b/vcl/inc/osx/saldata.hxx
index fbc28e05391d..1cbdabb88563 100644
--- a/vcl/inc/osx/saldata.hxx
+++ b/vcl/inc/osx/saldata.hxx
@@ -45,6 +45,8 @@
 
 #include "apple_remote/RemoteMainController.h"
 
+#include "osx/runinmain.hxx"
+
 class AquaSalInstance;
 class SalObject;
 class SalFrame;
diff --git a/vcl/inc/osx/salframe.h b/vcl/inc/osx/salframe.h
index 4b6d486f6be6..307356c76caa 100644
--- a/vcl/inc/osx/salframe.h
+++ b/vcl/inc/osx/salframe.h
@@ -29,6 +29,7 @@
 #include "osx/salmenu.h"
 #include "osx/saldata.hxx"
 #include "osx/osxvcltypes.h"
+#include "osx/runinmain.hxx"
 
 #include "salframe.hxx"
 
@@ -183,22 +184,22 @@ public:
     void VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen = true );
     void CocoaToVCL( NSPoint& io_Point, bool bRelativeToScreen = true );
 
-    NSCursor* getCurrentCursor() const;
+    NSCursor* getCurrentCursor();
 
     CGMutablePathRef getClipPath() const { return mrClippingPath; }
 
     // called by VCL_NSApplication to indicate screen settings have changed
     void screenParametersChanged();
 
- private: // methods
+private: // methods
     /** do things on initial show (like centering on parent or on screen)
     */
     void initShow();
 
     void initWindowAndView();
 
- private: // data
-    static AquaSalFrame*                   s_pCaptureFrame;
+private: // data
+    static AquaSalFrame*       s_pCaptureFrame;
 
     AquaSalFrame( const AquaSalFrame& ) = delete;
     AquaSalFrame& operator=(const AquaSalFrame&) = delete;
diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h
index 70a66775a575..e80818a36eb5 100644
--- a/vcl/inc/osx/salinst.h
+++ b/vcl/inc/osx/salinst.h
@@ -32,13 +32,22 @@
 #endif
 #include "salinst.hxx"
 
+#include "osx/runinmain.hxx"
+
 class AquaSalFrame;
+class SalFrame;
+class SalObject;
 class ApplicationEvent;
 class Image;
 enum class SalEvent;
 
+typedef void(^RuninmainBlock)(void);
+
 class SalYieldMutex : public comphelper::GenericSolarMutex
 {
+public:
+    OSX_RUNINMAIN_MEMBERS
+
 protected:
     virtual void            doAcquire( sal_uInt32 nLockCount ) override;
     virtual sal_uInt32      doRelease( bool bUnlockAll ) override;
@@ -46,6 +55,8 @@ protected:
 public:
     SalYieldMutex();
     virtual ~SalYieldMutex();
+
+    virtual bool IsCurrentThread() const override;
 };
 
 class AquaSalInstance : public SalInstance
@@ -70,6 +81,7 @@ public:
     osl::Mutex                              maUserEventListMutex;
     osl::Condition                          maWaitingYieldCond;
     bool                                    mbIsLiveResize;
+    bool                                    mbNoYieldLock;
 
     static std::list<const ApplicationEvent*> aAppEventList;
 
@@ -145,8 +157,9 @@ public:
     static const short AppExecuteSVMain   = 0x7fff;
     static const short AppEndLoopEvent    = 1;
     static const short AppStartTimerEvent = 10;
-    static const short PostedUserEvent    = 20;
+    static const short YieldWakeupEvent   = 20;
     static const short DispatchTimerEvent = 30;
+    static const short PostedUserEvent    = 40;
 
     static NSMenu* GetDynamicDockMenu();
 };
diff --git a/vcl/osx/a11ytextwrapper.mm b/vcl/osx/a11ytextwrapper.mm
index a46ffd6e7fd9..14a63aa8fd9e 100644
--- a/vcl/osx/a11ytextwrapper.mm
+++ b/vcl/osx/a11ytextwrapper.mm
@@ -203,8 +203,8 @@ using namespace ::com::sun::star::uno;
 
 +(id)rangeForPositionAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)point {
     NSValue * value = nil;
-    Point aPoint( [ AquaA11yUtil nsPointToVclPoint: point ]);
-    const Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen();
+    css::awt::Point aPoint( [ AquaA11yUtil nsPointToVclPoint: point ]);
+    const css::awt::Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen();
     aPoint.X -= screenPos.X;
     aPoint.Y -= screenPos.Y;

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list