diff options
-rw-r--r-- | include/vcl/svapp.hxx | 8 | ||||
-rw-r--r-- | vcl/README.scheduler | 25 | ||||
-rw-r--r-- | vcl/headless/svpinst.cxx | 5 | ||||
-rw-r--r-- | vcl/inc/headless/svpinst.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/osx/salinst.h | 3 | ||||
-rw-r--r-- | vcl/inc/salinst.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/unx/gtk/gtkinst.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/unx/salinst.h | 2 | ||||
-rw-r--r-- | vcl/inc/win/salinst.h | 5 | ||||
-rw-r--r-- | vcl/osx/salinst.cxx | 4 | ||||
-rw-r--r-- | vcl/qa/cppunit/timer.cxx | 2 | ||||
-rw-r--r-- | vcl/source/app/svapp.cxx | 34 | ||||
-rw-r--r-- | vcl/unx/generic/app/salinst.cxx | 4 | ||||
-rw-r--r-- | vcl/unx/gtk/gtkinst.cxx | 4 | ||||
-rw-r--r-- | vcl/win/app/salinst.cxx | 124 | ||||
-rw-r--r-- | vcl/win/window/salframe.cxx | 13 |
16 files changed, 139 insertions, 100 deletions
diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx index 89a375ca9e4f..3e3938498b75 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 @@ -1481,7 +1475,7 @@ class SolarMutexReleaser const sal_uInt32 mnReleased; public: SolarMutexReleaser(): mnReleased(Application::ReleaseSolarMutex()) {} - ~SolarMutexReleaser() { Application::ReAcquireSolarMutex(mnReleased); } + ~SolarMutexReleaser() { Application::AcquireSolarMutex( mnReleased ); } }; VCL_DLLPUBLIC Application* GetpApp(); diff --git a/vcl/README.scheduler b/vcl/README.scheduler index 05684cef8150..a7d2cbb04682 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,9 @@ 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. Those wakeup events must be ignored to prevent busy-locks. +but we can prevent running any other SolarMutex based code. Those wakeup +events must be ignored to prevent busy-locks. For more info read the "General: +main thread deferral" section. We can neither rely on MacOS dispatch_sync code block execution nor the message handling, as both can't be prioritized or filtered and the first @@ -136,6 +151,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 d64d944a8802..302405f8f59d 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 1f456f737901..65db0d0b0f2a 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 54f6ffdd7021..947e484b5c1d 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -533,10 +533,8 @@ SAL_WNODEPRECATED_DECLARATIONS_PUSH SAL_WNODEPRECATED_DECLARATIONS_POP } -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 3107e88d3c91..612fce86bc2f 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 98d56c6cd86e..e38164ee247b 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 2cd8b11c44d1..bc6fe03c9c2d 100644 --- a/vcl/unx/gtk/gtkinst.cxx +++ b/vcl/unx/gtk/gtkinst.cxx @@ -411,10 +411,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 92ed7faa14fd..be96ed17c654 100644 --- a/vcl/win/app/salinst.cxx +++ b/vcl/win/app/salinst.cxx @@ -112,6 +112,7 @@ public: explicit SalYieldMutex(); virtual bool IsCurrentThread() const override; + virtual bool tryToAcquire() override; }; SalYieldMutex::SalYieldMutex() @@ -139,6 +140,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 @@ -167,15 +170,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_uInt32 nCount ) { WinSalInstance* pInst = GetSalData()->mpFirstInstance; @@ -186,10 +205,7 @@ void ImplSalYieldMutexAcquireWithWait( sal_uInt32 nCount ) bool ImplSalYieldMutexTryToAcquire() { WinSalInstance* pInst = GetSalData()->mpFirstInstance; - if ( pInst ) - return pInst->mpSalYieldMutex->tryToAcquire(); - else - return false; + return pInst ? pInst->mpSalYieldMutex->tryToAcquire() : false; } void ImplSalYieldMutexRelease() @@ -204,8 +220,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() @@ -443,9 +462,10 @@ void DestroySalInstance( SalInstance* pInst ) } WinSalInstance::WinSalInstance() + : mhComWnd( nullptr ) + , mbNoYieldLock( false ) { - mhComWnd = nullptr; - mpSalYieldMutex = new SalYieldMutex(); + mpSalYieldMutex = new SalYieldMutex(); mpSalYieldMutex->acquire(); } @@ -484,8 +504,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; @@ -535,38 +554,44 @@ 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 ); + if ( bDidWork ) + maWaitingYieldCond.set(); } - mpSalYieldMutex->acquire( nCount ); return bDidWork; } @@ -574,6 +599,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 ) { @@ -596,19 +622,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: @@ -624,19 +662,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: @@ -646,7 +696,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 e2c444a3e182..8a9c6066c461 100644 --- a/vcl/win/window/salframe.cxx +++ b/vcl/win/window/salframe.cxx @@ -1054,10 +1054,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--; } |