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>
This commit is contained in:
parent
f633dcdfc0
commit
4baec725e0
16 changed files with 138 additions and 99 deletions
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
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 );
|
||||
// #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" );
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue