summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan-Marek Glogowski <glogow@fbihome.de>2017-08-28 19:58:32 +0200
committerJan-Marek Glogowski <glogow@fbihome.de>2017-09-26 09:42:11 +0200
commit4baec725e0dc0713f0d47003e9b10bc3b62f56ff (patch)
tree72f21c28416068e46133964e420ca094af8b7587
parentf633dcdfc0ad7a13d096d97b6753b55e8f8a3f07 (diff)
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 Reviewed-on: https://gerrit.libreoffice.org/42583 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de>
-rw-r--r--include/vcl/svapp.hxx8
-rw-r--r--vcl/README.scheduler25
-rw-r--r--vcl/headless/svpinst.cxx5
-rw-r--r--vcl/inc/headless/svpinst.hxx2
-rw-r--r--vcl/inc/osx/salinst.h3
-rw-r--r--vcl/inc/salinst.hxx2
-rw-r--r--vcl/inc/unx/gtk/gtkinst.hxx2
-rw-r--r--vcl/inc/unx/salinst.h2
-rw-r--r--vcl/inc/win/salinst.h5
-rw-r--r--vcl/osx/salinst.cxx4
-rw-r--r--vcl/qa/cppunit/timer.cxx2
-rw-r--r--vcl/source/app/svapp.cxx34
-rw-r--r--vcl/unx/generic/app/salinst.cxx4
-rw-r--r--vcl/unx/gtk/gtkinst.cxx4
-rw-r--r--vcl/win/app/salinst.cxx124
-rw-r--r--vcl/win/window/salframe.cxx13
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--;
}