Rebased ref, commits from common ancestor: commit e6c29a0585237ebea3b2b962ff517f202ce6154d Author: Jan-Marek Glogowski <glo...@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 b3792403105376c68b23b4309d5aec6b8db80d76 Author: Jan-Marek Glogowski <glo...@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 bf05df96ac04..cb40680ac35f 100644 --- a/sc/qa/unoapi/sc_4.sce +++ b/sc/qa/unoapi/sc_4.sce @@ -29,12 +29,13 @@ # ported to cppunit -o sc.ScHeaderFieldObj -o sc.ScHeaderFieldsObj -o sc.ScHeaderFooterContentObj --o sc.ScHeaderFooterTextCursor # SHF_TextObj is composed of SHF_TextData, which has a weak reference to # SHF_ContentObj, which itself has three references to SHF_TextObj. # 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 6de0719d840158f31c54e3259db4f3e23469acb7 Author: Jan-Marek Glogowski <glo...@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..cb0292beb748 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 9a73bfabd84fe4d27a1d65388de05a5f731fc13c Author: Jan-Marek Glogowski <glo...@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 21f33d3187e0..85f6a0f8e092 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 b7606d0c33e3351f4451e3e98cf54c7b71a1ee85 Author: Jan-Marek Glogowski <glo...@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 a0094b0022e8d37671a3b0fd3c47123729a69eae Author: Jan-Marek Glogowski <glo...@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 7923c39b1e25..21f33d3187e0 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 b43b269156c6..5345fc67b235 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -141,6 +141,7 @@ void Scheduler::ImplDeInitScheduler() pTask->mbActive = false; } pTask->mpSchedulerData = nullptr; + pTask->SetStatic(); } ImplSchedulerData* pDeleteSchedulerData = pSchedulerData; pSchedulerData = pSchedulerData->mpNext; @@ -524,6 +525,7 @@ Task::Task( const sal_Char *pDebugName ) , mpDebugName( pDebugName ) , mePriority( TaskPriority::DEFAULT ) , mbActive( false ) + , mbStatic( false ) { } @@ -532,6 +534,7 @@ Task::Task( const Task& rTask ) , mpDebugName( rTask.mpDebugName ) , mePriority( rTask.mePriority ) , mbActive( false ) + , mbStatic( false ) { if ( rTask.IsActive() ) Start(); @@ -539,9 +542,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 f67579b1f672c0b6479b614b86191a92506aedf9 Author: Jan-Marek Glogowski <glo...@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 using dispatch_*. Since dispatch_* can't return any values, we're using a thread-id based map to transfer the return values from the main thread to the callers. One major problem is the missing equivalent of Windows WaitForMultipleObjects function, which we have to emulate by try-locking the SolarMutex and waiting for an unlock message. Using an unprotected boolean isn't race free, therefore we use a 0.1s timout in the event lookup function. Our out-of-order SendMessage processing works fine with the processing of queued dispatch_* code blocks while waiting for new events. Then there is the problem of the notifications, where we have to disable the SolarMutex locking, because we generate these events ourself, but must not release it. Just ignoring the notifications currently results in GUI update failures. The runinmain implementation uses macros, so it can rely on guard objects for async calls. 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..7923c39b1e25 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. 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 f7e5c219175d..e80818a36eb5 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -32,14 +32,21 @@ #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 { - bool mbInAquireWithTry; +public: + OSX_RUNINMAIN_MEMBERS protected: virtual void doAcquire( sal_uInt32 nLockCount ) override; @@ -48,6 +55,8 @@ protected: public: SalYieldMutex(); virtual ~SalYieldMutex(); + + virtual bool IsCurrentThread() const override; }; class AquaSalInstance : public SalInstance @@ -72,6 +81,7 @@ public: osl::Mutex maUserEventListMutex; osl::Condition maWaitingYieldCond; bool mbIsLiveResize; + bool mbNoYieldLock; static std::list<const ApplicationEvent*> aAppEventList; @@ -147,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; sal_Int32 index = [ wrapper accessibleText ] -> getIndexAtPoint( aPoint ); @@ -239,9 +239,9 @@ using namespace ::com::sun::star::uno; } if ( [ wrapper accessibleComponent ] ) { // get location on screen (must be added since get CharacterBounds returns values relative to parent) - Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen(); - Point pos ( minx + screenPos.X, miny + screenPos.Y ); - Point size ( maxx - minx, maxy - miny ); + css::awt::Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen(); + css::awt::Point pos ( minx + screenPos.X, miny + screenPos.Y ); + css::awt::Point size ( maxx - minx, maxy - miny ); NSValue * nsPos = [ AquaA11yUtil vclPointToNSPoint: pos ]; rect = [ NSValue valueWithRect: NSMakeRect ( [ nsPos pointValue ].x, [ nsPos pointValue ].y - size.Y, size.X, size.Y ) ]; //printf("Range: %s --- Rect: %s\n", [ NSStringFromRange ( [ range rangeValue ] ) UTF8String ], [ NSStringFromRect ( [ rect rectValue ] ) UTF8String ]); diff --git a/vcl/osx/salframe.cxx b/vcl/osx/salframe.cxx index a29eba5eb766..e54073cdf4f1 100644 --- a/vcl/osx/salframe.cxx +++ b/vcl/osx/salframe.cxx @@ -36,6 +36,7 @@ #include "osx/salinst.h" #include "osx/salframeview.h" #include "osx/a11yfactory.h" +#include "osx/runinmain.hxx" #include "quartz/utils.h" #include "salwtype.hxx" @@ -92,6 +93,8 @@ AquaSalFrame::AquaSalFrame( SalFrame* pParent, SalFrameStyleFlags salFrameStyle AquaSalFrame::~AquaSalFrame() { + assert( GetSalData()->mpFirstInstance->IsMainThread() ); + // if the frame is destroyed and has the current menubar // set the default menubar if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu ) @@ -134,6 +137,8 @@ AquaSalFrame::~AquaSalFrame() void AquaSalFrame::initWindowAndView() { + OSX_SALDATA_RUNINMAIN( initWindowAndView() ) + // initialize mirroring parameters // FIXME: screens changing NSScreen* pNSScreen = [mpNSWindow screen]; @@ -259,6 +264,8 @@ void AquaSalFrame::VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen ) void AquaSalFrame::screenParametersChanged() { + OSX_SALDATA_RUNINMAIN( screenParametersChanged() ) + UpdateFrameGeometry(); if( mpGraphics ) @@ -298,6 +305,8 @@ void AquaSalFrame::SetTitle(const OUString& rTitle) if ( !mpNSWindow ) return; + OSX_SALDATA_RUNINMAIN( SetTitle(rTitle) ) + // #i113170# may not be the main thread if called from UNO API SalData::ensureThreadAutoreleasePool(); @@ -342,8 +351,7 @@ void AquaSalFrame::SetIcon( sal_uInt16 ) void AquaSalFrame::SetRepresentedURL( const OUString& i_rDocURL ) { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetRepresentedURL( i_rDocURL ) ) if( comphelper::isFileUrl(i_rDocURL) ) { @@ -360,6 +368,8 @@ void AquaSalFrame::SetRepresentedURL( const OUString& i_rDocURL ) void AquaSalFrame::initShow() { + OSX_SALDATA_RUNINMAIN( initShow() ) + mbInitShow = false; if( ! mbPositioned && ! mbFullScreen ) { @@ -397,6 +407,8 @@ void AquaSalFrame::initShow() void AquaSalFrame::SendPaintEvent( const tools::Rectangle* pRect ) { + OSX_SALDATA_RUNINMAIN( SendPaintEvent( pRect ) ) + SalPaintEvent aPaintEvt( 0, 0, maGeometry.nWidth, maGeometry.nHeight, true ); if( pRect ) { @@ -414,8 +426,7 @@ void AquaSalFrame::Show(bool bVisible, bool bNoActivate) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( Show(bVisible, bNoActivate) ) mbShown = bVisible; if(bVisible) @@ -472,8 +483,7 @@ void AquaSalFrame::Show(bool bVisible, bool bNoActivate) void AquaSalFrame::SetMinClientSize( long nWidth, long nHeight ) { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetMinClientSize( nWidth, nHeight ) ) mnMinWidth = nWidth; mnMinHeight = nHeight; @@ -495,8 +505,7 @@ void AquaSalFrame::SetMinClientSize( long nWidth, long nHeight ) void AquaSalFrame::SetMaxClientSize( long nWidth, long nHeight ) { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetMaxClientSize( nWidth, nHeight ) ) mnMaxWidth = nWidth; mnMaxHeight = nHeight; @@ -536,46 +545,45 @@ void AquaSalFrame::GetClientSize( long& rWidth, long& rHeight ) void AquaSalFrame::SetWindowState( const SalFrameState* pState ) { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetWindowState( pState ) ) if ( mpNSWindow ) { - // set normal state - NSRect aStateRect = [mpNSWindow frame]; - aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask]; - CocoaToVCL( aStateRect ); - if( pState->mnMask & WindowStateMask::X ) - aStateRect.origin.x = float(pState->mnX); - if( pState->mnMask & WindowStateMask::Y ) - aStateRect.origin.y = float(pState->mnY); - if( pState->mnMask & WindowStateMask::Width ) - aStateRect.size.width = float(pState->mnWidth); - if( pState->mnMask & WindowStateMask::Height ) - aStateRect.size.height = float(pState->mnHeight); - VCLToCocoa( aStateRect ); - aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask]; - - [mpNSWindow setFrame: aStateRect display: NO]; - if( pState->mnState == WindowStateState::Minimized ) - [mpNSWindow miniaturize: NSApp]; - else if( [mpNSWindow isMiniaturized] ) - [mpNSWindow deminiaturize: NSApp]; - - /* ZOOMED is not really maximized (actually it toggles between a user set size and - the program specified one), but comes closest since the default behavior is - "maximized" if the user did not intervene - */ - if( pState->mnState == WindowStateState::Maximized ) - { - if(! [mpNSWindow isZoomed]) - [mpNSWindow zoom: NSApp]; - } - else - { - if( [mpNSWindow isZoomed] ) - [mpNSWindow zoom: NSApp]; - } + // set normal state + NSRect aStateRect = [mpNSWindow frame]; + aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask]; + CocoaToVCL( aStateRect ); + if( pState->mnMask & WindowStateMask::X ) + aStateRect.origin.x = float(pState->mnX); + if( pState->mnMask & WindowStateMask::Y ) + aStateRect.origin.y = float(pState->mnY); + if( pState->mnMask & WindowStateMask::Width ) + aStateRect.size.width = float(pState->mnWidth); + if( pState->mnMask & WindowStateMask::Height ) + aStateRect.size.height = float(pState->mnHeight); + VCLToCocoa( aStateRect ); + aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask]; + + [mpNSWindow setFrame: aStateRect display: NO]; + if( pState->mnState == WindowStateState::Minimized ) + [mpNSWindow miniaturize: NSApp]; + else if( [mpNSWindow isMiniaturized] ) + [mpNSWindow deminiaturize: NSApp]; + + /* ZOOMED is not really maximized (actually it toggles between a user set size and + the program specified one), but comes closest since the default behavior is + "maximized" if the user did not intervene + */ + if( pState->mnState == WindowStateState::Maximized ) + { + if(! [mpNSWindow isZoomed]) + [mpNSWindow zoom: NSApp]; + } + else + { + if( [mpNSWindow isZoomed] ) + [mpNSWindow zoom: NSApp]; + } } // get new geometry @@ -612,8 +620,7 @@ bool AquaSalFrame::GetWindowState( SalFrameState* pState ) if ( !mpNSWindow ) return FALSE; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN_UNION( GetWindowState( pState ), boolean ) pState->mnMask = WindowStateMask::X | WindowStateMask::Y | @@ -644,8 +651,7 @@ void AquaSalFrame::SetScreenNumber(unsigned int nScreen) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetScreenNumber( nScreen ) ) NSArray* pScreens = [NSScreen screens]; NSScreen* pScreen = nil; @@ -682,14 +688,13 @@ void AquaSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay ) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); - SAL_INFO("vcl.osx", OSL_THIS_FUNC << ": mbFullScreen=" << mbFullScreen << ", bFullScreen=" << bFullScreen); if( mbFullScreen == bFullScreen ) return; + OSX_SALDATA_RUNINMAIN( ShowFullScreen( bFullScreen, nDisplay ) ) + mbFullScreen = bFullScreen; if( bFullScreen ) @@ -777,8 +782,7 @@ void AquaSalFrame::StartPresentation( bool bStart ) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( StartPresentation( bStart ) ) if( bStart ) { @@ -808,8 +812,7 @@ void AquaSalFrame::ToTop(SalFrameToTop nFlags) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( ToTop( nFlags ) ) if( ! (nFlags & SalFrameToTop::RestoreWhenMin) ) { @@ -822,8 +825,10 @@ void AquaSalFrame::ToTop(SalFrameToTop nFlags) [mpNSWindow orderFront: NSApp]; } -NSCursor* AquaSalFrame::getCurrentCursor() const +NSCursor* AquaSalFrame::getCurrentCursor() { + OSX_SALDATA_RUNINMAIN_POINTER( getCurrentCursor(), NSCursor* ) + NSCursor* pCursor = nil; switch( mePointerStyle ) { @@ -864,12 +869,11 @@ void AquaSalFrame::SetPointer( PointerStyle ePointerStyle ) { if ( !mpNSWindow ) return; - - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); - if( ePointerStyle == mePointerStyle ) return; + + OSX_SALDATA_RUNINMAIN( SetPointer( ePointerStyle ) ) + mePointerStyle = ePointerStyle; [mpNSWindow invalidateCursorRectsForView: mpNSView]; @@ -877,8 +881,9 @@ void AquaSalFrame::SetPointer( PointerStyle ePointerStyle ) void AquaSalFrame::SetPointerPos( long nX, long nY ) { - // FIXME: use Cocoa functions + OSX_SALDATA_RUNINMAIN( SetPointerPos( nX, nY ) ) + // FIXME: use Cocoa functions // FIXME: multiscreen support CGPoint aPoint = { static_cast<CGFloat>(nX + maGeometry.nX), static_cast<CGFloat>(nY + maGeometry.nY) }; CGDirectDisplayID mainDisplayID = CGMainDisplayID(); @@ -890,8 +895,7 @@ void AquaSalFrame::Flush() if( !(mbGraphics && mpGraphics && mpNSView && mbShown) ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( Flush() ) [mpNSView setNeedsDisplay: YES]; @@ -909,8 +913,7 @@ void AquaSalFrame::Flush( const tools::Rectangle& rRect ) if( !(mbGraphics && mpGraphics && mpNSView && mbShown) ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( Flush( rRect ) ) NSRect aNSRect = { { static_cast<CGFloat>(rRect.Left()), static_cast<CGFloat>(rRect.Top()) }, { static_cast<CGFloat>(rRect.GetWidth()), static_cast<CGFloat>(rRect.GetHeight()) } }; VCLToCocoa( aNSRect, false ); @@ -1118,6 +1121,8 @@ static vcl::Font getFont( NSFont* pFont, long nDPIY, const vcl::Font& rDefault ) void AquaSalFrame::getResolution( sal_Int32& o_rDPIX, sal_Int32& o_rDPIY ) { + OSX_SALDATA_RUNINMAIN( getResolution( o_rDPIX, o_rDPIY ) ) + if( ! mpGraphics ) { AcquireGraphics(); @@ -1137,8 +1142,7 @@ void AquaSalFrame::UpdateSettings( AllSettings& rSettings ) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( UpdateSettings( rSettings ) ) [mpNSView lockFocus]; @@ -1242,6 +1246,7 @@ const SystemEnvData* AquaSalFrame::GetSystemData() const void AquaSalFrame::Beep() { + OSX_SALDATA_RUNINMAIN( Beep() ) NSBeep(); } @@ -1250,8 +1255,7 @@ void AquaSalFrame::SetPosSize(long nX, long nY, long nWidth, long nHeight, sal_u if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetPosSize( nX, nY, nWidth, nHeight, nFlags ) ) SalEvent nEvent = SalEvent::NONE; @@ -1340,8 +1344,7 @@ void AquaSalFrame::GetWorkArea( tools::Rectangle& rRect ) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( GetWorkArea( rRect ) ) NSScreen* pScreen = [mpNSWindow screen]; if( pScreen == nil ) @@ -1356,8 +1359,7 @@ void AquaSalFrame::GetWorkArea( tools::Rectangle& rRect ) SalPointerState AquaSalFrame::GetPointerState() { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN_UNION( GetPointerState(), state ) SalPointerState state; state.mnState = 0; @@ -1492,8 +1494,7 @@ void AquaSalFrame::DrawMenuBar() void AquaSalFrame::SetMenu( SalMenu* pSalMenu ) { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetMenu( pSalMenu ) ) AquaSalMenu* pMenu = static_cast<AquaSalMenu*>(pSalMenu); SAL_WARN_IF( pMenu && !pMenu->mbMenuBar, "vcl", "setting non menubar on frame" ); @@ -1504,14 +1505,16 @@ void AquaSalFrame::SetMenu( SalMenu* pSalMenu ) void AquaSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle ) { - if ( mpNSWindow ) + if ( !mpNSWindow ) { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + mnExtStyle = nStyle; + return; + } + + OSX_SALDATA_RUNINMAIN( SetExtendedFrameStyle( nStyle ) ) if( (mnExtStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) != (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ) [mpNSWindow setDocumentEdited: (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ? YES : NO]; - } mnExtStyle = nStyle; } @@ -1534,9 +1537,9 @@ void AquaSalFrame::SetParent( SalFrame* pNewParent ) void AquaSalFrame::UpdateFrameGeometry() { if ( !mpNSWindow ) - { return; - } + + OSX_SALDATA_RUNINMAIN( UpdateFrameGeometry() ) // keep in mind that view and window coordinates are lower left // whereas vcl's are upper left @@ -1609,12 +1612,9 @@ void AquaSalFrame::CaptureMouse( bool bCapture ) void AquaSalFrame::ResetClipRegion() { if ( !mpNSWindow ) - { return; - } - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( ResetClipRegion() ) // release old path and indicate no clipping CGPathRelease( mrClippingPath ); @@ -1632,12 +1632,9 @@ void AquaSalFrame::ResetClipRegion() void AquaSalFrame::BeginSetClipRegion( sal_uLong nRects ) { if ( !mpNSWindow ) - { return; - } - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( BeginSetClipRegion( nRects ) ) // release old path if( mrClippingPath ) @@ -1671,12 +1668,9 @@ void AquaSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight void AquaSalFrame::EndSetClipRegion() { if ( !mpNSWindow ) - { return; - } - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( EndSetClipRegion() ) if( ! maClippingRects.empty() ) { diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index 721a32ac2298..0b2489c6239a 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -46,6 +46,7 @@ #include "osx/salprn.h" #include "osx/saltimer.h" #include "osx/vclnsapp.h" +#include "osx/runinmain.hxx" #include "print.h" #include "impbmp.hxx" @@ -259,7 +260,7 @@ void InitSalMain() } SalYieldMutex::SalYieldMutex() - : mbInAquireWithTry( false ) + : m_aCodeBlock( nullptr ) { } @@ -269,22 +270,31 @@ SalYieldMutex::~SalYieldMutex() void SalYieldMutex::doAcquire( sal_uInt32 nLockCount ) { - if ( GetSalData()->mpFirstInstance && GetSalData()->mpFirstInstance->IsMainThread() ) + AquaSalInstance *pInst = GetSalData()->mpFirstInstance; + if ( pInst && pInst->IsMainThread() ) { - while ( !m_aMutex.tryToAcquire() ) - { - mbInAquireWithTry = true; -SAL_WNODEPRECATED_DECLARATIONS_PUSH - // 'NSApplicationDefinedMask' is deprecated: first deprecated in macOS 10.12 - NSEvent* pPeekEvent = [NSApp nextEventMatchingMask: NSApplicationDefinedMask -SAL_WNODEPRECATED_DECLARATIONS_POP - untilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1] - inMode: NSDefaultRunLoopMode - dequeue: YES]; - if ( AquaSalInstance::UnlockedYieldMutexEvent != (int) [pPeekEvent subtype] ) - [NSApp postEvent: pPeekEvent atStart: YES]; + if ( pInst->mbNoYieldLock ) + return; + do { + m_aInMainCondition.reset(); + if ( m_aCodeBlock ) + { + assert( !pInst->mbNoYieldLock ); + pInst->mbNoYieldLock = true; + m_aCodeBlock(); + pInst->mbNoYieldLock = false; + Block_release( m_aCodeBlock ); + m_aCodeBlock = nullptr; + m_aResultCondition.set(); + } + // reset condition *before* acquiring! + if (m_aMutex.tryToAcquire()) + break; + // wait for doRelease() or RUNINMAIN_* to set the condition + osl::Condition::Result res = m_aInMainCondition.wait(); + assert(osl::Condition::Result::result_ok == res); } - mbInAquireWithTry = false; + while ( true ); } else m_aMutex.acquire(); @@ -296,17 +306,25 @@ SAL_WNODEPRECATED_DECLARATIONS_POP sal_uInt32 SalYieldMutex::doRelease( const bool bUnlockAll ) { + AquaSalInstance *pInst = GetSalData()->mpFirstInstance; + if ( pInst->mbNoYieldLock && pInst->IsMainThread() ) + return 1; sal_uInt32 nCount = comphelper::GenericSolarMutex::doRelease( bUnlockAll ); - if ( mbInAquireWithTry && 0 == m_nCount - && !GetSalData()->mpFirstInstance->IsMainThread() ) - dispatch_async(dispatch_get_main_queue(),^{ - ImplNSAppPostEvent( AquaSalInstance::UnlockedYieldMutexEvent, NO ); - }); + if ( 0 == m_nCount && !pInst->IsMainThread() ) + m_aInMainCondition.set(); return nCount; } +bool SalYieldMutex::IsCurrentThread() const +{ + if ( !GetSalData()->mpFirstInstance->mbNoYieldLock ) + return comphelper::GenericSolarMutex::IsCurrentThread(); + else + return GetSalData()->mpFirstInstance->IsMainThread(); +} + // some convenience functions regarding the yield mutex, aka solar mutex bool ImplSalYieldMutexTryToAcquire() @@ -359,6 +377,7 @@ AquaSalInstance::AquaSalInstance() : maUserEventListMutex() , maWaitingYieldCond() , mbIsLiveResize( false ) + , mbNoYieldLock( false ) { mpSalYieldMutex = new SalYieldMutex; mpSalYieldMutex->acquire(); @@ -454,6 +473,9 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) } break; } + case YieldWakeupEvent: + // do nothing + break; #if !HAVE_FEATURE_MACOSX_SANDBOX case AppleRemoteControlEvent: // Defined in <apple_remote/RemoteMainController.h> { @@ -579,7 +601,10 @@ SAL_WNODEPRECATED_DECLARATIONS_POP inMode: NSDefaultRunLoopMode dequeue: YES]; if( pEvent ) + { [NSApp sendEvent: pEvent]; + bHadEvent = true; + } [NSApp updateWindows]; } @@ -641,6 +666,8 @@ bool AquaSalInstance::AnyInput( VclInputFlags nType ) return false; } + OSX_INST_RUNINMAIN_UNION( AnyInput( nType ), boolean ) + if( nType & VclInputFlags::TIMER ) { if( AquaSalTimer::pRunningTimer ) @@ -653,9 +680,6 @@ bool AquaSalInstance::AnyInput( VclInputFlags nType ) } } - if (!IsMainThread()) - return false; - unsigned/*NSUInteger*/ nEventMask = 0; SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'NSFlagsChangedMask' is deprecated: first deprecated in macOS 10.12 @@ -703,29 +727,28 @@ SalFrame* AquaSalInstance::CreateChildFrame( SystemParentData*, SalFrameStyleFla SalFrame* AquaSalInstance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags nSalFrameStyle ) { - SalData::ensureThreadAutoreleasePool(); - - SalFrame* pFrame = new AquaSalFrame( pParent, nSalFrameStyle ); - return pFrame; + OSX_INST_RUNINMAIN_POINTER( CreateFrame( pParent, nSalFrameStyle ), SalFrame* ) + return new AquaSalFrame( pParent, nSalFrameStyle ); } void AquaSalInstance::DestroyFrame( SalFrame* pFrame ) { + OSX_INST_RUNINMAIN( DestroyFrame( pFrame ) ) delete pFrame; } SalObject* AquaSalInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool /* bShow */ ) { - AquaSalObject *pObject = nullptr; - - if ( pParent ) - pObject = new AquaSalObject( static_cast<AquaSalFrame*>(pParent), pWindowData ); + if ( !pParent ) + return nullptr; - return pObject; + OSX_INST_RUNINMAIN_POINTER( CreateObject( pParent, pWindowData, false ), SalObject* ) + return new AquaSalObject( static_cast<AquaSalFrame*>(pParent), pWindowData ); } void AquaSalInstance::DestroyObject( SalObject* pObject ) { + OSX_INST_RUNINMAIN( DestroyObject( pObject ) ) delete pObject; } diff --git a/vcl/osx/salobj.cxx b/vcl/osx/salobj.cxx index 957f017363fc..4113d43caf3c 100644 --- a/vcl/osx/salobj.cxx +++ b/vcl/osx/salobj.cxx @@ -26,6 +26,7 @@ #include "osx/salframe.h" #include "osx/salinst.h" #include "osx/salobj.h" +#include "osx/runinmain.hxx" #include <AppKit/NSOpenGLView.h> @@ -105,6 +106,8 @@ AquaSalObject::AquaSalObject( AquaSalFrame* pFrame, SystemWindowData* pWindowDat AquaSalObject::~AquaSalObject() { + assert( GetSalData()->mpFirstInstance->IsMainThread() ); + if( maSysData.mpNSView ) { NSView *pView = maSysData.mpNSView; @@ -194,6 +197,8 @@ void AquaSalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight ) void AquaSalObject::setClippedPosSize() { + OSX_SALDATA_RUNINMAIN( setClippedPosSize() ) + NSRect aViewRect = { NSZeroPoint, NSMakeSize( mnWidth, mnHeight) }; if( maSysData.mpNSView ) { @@ -222,8 +227,12 @@ void AquaSalObject::setClippedPosSize() void AquaSalObject::Show( bool bVisible ) { - if( mpClipView ) - [mpClipView setHidden: (bVisible ? NO : YES)]; + if( !mpClipView ) + return; + + OSX_SALDATA_RUNINMAIN( Show( bVisible ) ) + + [mpClipView setHidden: (bVisible ? NO : YES)]; } const SystemEnvData* AquaSalObject::GetSystemData() const @@ -235,8 +244,10 @@ class AquaOpenGLContext : public OpenGLContext { public: virtual bool initWindow() override; + private: GLWindow m_aGLWin; + virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; } virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; } NSOpenGLView* getOpenGLView(); @@ -250,6 +261,8 @@ private: void AquaOpenGLContext::resetCurrent() { + OSX_SALDATA_RUNINMAIN( resetCurrent() ) + clearCurrent(); OpenGLZone aZone; @@ -260,6 +273,8 @@ void AquaOpenGLContext::resetCurrent() void AquaOpenGLContext::makeCurrent() { + OSX_SALDATA_RUNINMAIN( makeCurrent() ) + if (isCurrent()) return; @@ -275,6 +290,8 @@ void AquaOpenGLContext::makeCurrent() void AquaOpenGLContext::swapBuffers() { + OSX_SALDATA_RUNINMAIN( swapBuffers() ) + OpenGLZone aZone; NSOpenGLView* pView = getOpenGLView(); @@ -293,11 +310,14 @@ SystemWindowData AquaOpenGLContext::generateWinData(vcl::Window* /*pParent*/, bo void AquaOpenGLContext::destroyCurrentContext() { + OSX_SALDATA_RUNINMAIN( destroyCurrentContext() ) [NSOpenGLContext clearCurrentContext]; } bool AquaOpenGLContext::initWindow() { + OSX_SALDATA_RUNINMAIN_UNION( initWindow(), boolean ) + if( !m_pChildWindow ) { SystemWindowData winData = generateWinData(mpWindow, mbRequestLegacyContext); @@ -314,6 +334,8 @@ bool AquaOpenGLContext::initWindow() bool AquaOpenGLContext::ImplInit() { + OSX_SALDATA_RUNINMAIN_UNION( ImplInit(), boolean ) + OpenGLZone aZone; VCL_GL_INFO("OpenGLContext::ImplInit----start"); @@ -332,6 +354,7 @@ NSOpenGLView* AquaOpenGLContext::getOpenGLView() OpenGLContext* AquaSalInstance::CreateOpenGLContext() { + OSX_SALDATA_RUNINMAIN_POINTER( CreateOpenGLContext(), OpenGLContext* ) return new AquaOpenGLContext; } diff --git a/vcl/osx/saltimer.cxx b/vcl/osx/saltimer.cxx index e442fcf05335..23aa0f583707 100644 --- a/vcl/osx/saltimer.cxx +++ b/vcl/osx/saltimer.cxx @@ -131,9 +131,10 @@ static void ImplSalStopTimer() void AquaSalTimer::handleDispatchTimerEvent() { ImplSVData* pSVData = ImplGetSVData(); - SolarMutexGuard aGuard; + GetSalData()->mpFirstInstance->AcquireYieldMutex( 1 ); if( pSVData->maSchedCtx.mpSalTimer ) pSVData->maSchedCtx.mpSalTimer->CallCallback(); + GetSalData()->mpFirstInstance->ReleaseYieldMutex( false ); } void AquaSalTimer::handleStartTimerEvent( NSEvent* pEvent ) commit 11318229c37c73a3475341a1132b83a64a2fd4cf Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 15 08:05:51 2017 +0200 Unify SolarMutex implementations All backends implement the SolarMutex in mostly the same way. So this consolidates this code into a GenericSolarMutex. We still need the abstract SolarMutex class for all these fake AKA fascade implementations. The patch also replaces various places of direct mutex usage with either SolarMutexGuard or SolarMutexReleaser objects. Change-Id: Ia0146dd6c51a3b9a513cc6af34a66def58aad831 diff --git a/comphelper/source/misc/solarmutex.cxx b/comphelper/source/misc/solarmutex.cxx index 4b573078dffd..66b783f3368c 100644 --- a/comphelper/source/misc/solarmutex.cxx +++ b/comphelper/source/misc/solarmutex.cxx @@ -42,6 +42,67 @@ SolarMutex *SolarMutex::get() return pSolarMutex; } +GenericSolarMutex::GenericSolarMutex() + : m_nCount( 0 ) + , m_nThreadId( 0 ) + , m_aBeforeReleaseHandler( nullptr ) +{ + setSolarMutex( this ); +} + +GenericSolarMutex::~GenericSolarMutex() +{ + setSolarMutex( nullptr ); +} + +void GenericSolarMutex::doAcquire( const sal_uInt32 nLockCount ) +{ + for ( sal_uInt32 n = nLockCount; n ; --n ) + m_aMutex.acquire(); + m_nThreadId = osl::Thread::getCurrentIdentifier(); + m_nCount += nLockCount; +} + +sal_uInt32 GenericSolarMutex::doRelease( bool bUnlockAll ) +{ + if ( m_nCount == 0 ) + abort(); + if ( m_nThreadId != osl::Thread::getCurrentIdentifier() ) + abort(); + + const sal_uInt32 nCount = bUnlockAll ? m_nCount : 1; + m_nCount -= nCount; + + if ( 0 == m_nCount ) + { + if ( m_aBeforeReleaseHandler ) + m_aBeforeReleaseHandler(); + m_nThreadId = 0; + } + + for ( sal_uInt32 n = nCount ; n ; --n ) + m_aMutex.release(); + + return nCount; +} + +bool GenericSolarMutex::IsCurrentThread() const +{ + return m_nThreadId == osl::Thread::getCurrentIdentifier(); +} + +bool GenericSolarMutex::tryToAcquire() +{ + if ( m_aMutex.tryToAcquire() ) + { + m_nThreadId = osl::Thread::getCurrentIdentifier(); + m_nCount++; + return true; + } + else + return false; +} + } // namespace comphelper /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/ModelImpl.cxx b/dbaccess/source/core/dataaccess/ModelImpl.cxx index bbbe69d5f52f..3ddffa4caa52 100644 --- a/dbaccess/source/core/dataaccess/ModelImpl.cxx +++ b/dbaccess/source/core/dataaccess/ModelImpl.cxx @@ -92,14 +92,17 @@ VosMutexFacade::VosMutexFacade( ::osl::Mutex& _rMutex ) { } -void VosMutexFacade::acquire() +void VosMutexFacade::doAcquire( sal_uInt32 nLockCount ) { + assert( 1 == nLockCount ); (void) nLockCount; m_rMutex.acquire(); } -void VosMutexFacade::release() +sal_uInt32 VosMutexFacade::doRelease( bool bUnlockAll ) { + assert( !bUnlockAll ); (void) bUnlockAll; m_rMutex.release(); + return 1; } bool VosMutexFacade::tryToAcquire() @@ -107,6 +110,11 @@ bool VosMutexFacade::tryToAcquire() return m_rMutex.tryToAcquire(); } +bool VosMutexFacade::IsCurrentThread() const +{ + return true; +} + // DocumentStorageAccess class DocumentStorageAccess : public ::cppu::WeakImplHelper< XDocumentSubStorageSupplier , XTransactionListener > diff --git a/dbaccess/source/core/dataaccess/ModelImpl.hxx b/dbaccess/source/core/dataaccess/ModelImpl.hxx index 130bb5493a10..034e1bbd4b8d 100644 --- a/dbaccess/source/core/dataaccess/ModelImpl.hxx +++ b/dbaccess/source/core/dataaccess/ModelImpl.hxx @@ -118,7 +118,7 @@ class ODatabaseContext; class OSharedConnectionManager; // VosMutexFacade -/** a class which provides an IMutex interface to an OSL-based mutex +/** a class which provides an SolarMutex interface to an OSL-based mutex */ class VosMutexFacade : public comphelper::SolarMutex { @@ -128,9 +128,12 @@ public: */ explicit VosMutexFacade( ::osl::Mutex& _rMutex ); - virtual void acquire() override; - virtual void release() override; virtual bool tryToAcquire() override; + virtual bool IsCurrentThread() const override; + +protected: + virtual void doAcquire( sal_uInt32 nLockCount ) override; + virtual sal_uInt32 doRelease( bool bUnlockAll ) override; private: ::osl::Mutex& m_rMutex; diff --git a/include/comphelper/solarmutex.hxx b/include/comphelper/solarmutex.hxx index 48453de915e4..1587a9767221 100644 --- a/include/comphelper/solarmutex.hxx +++ b/include/comphelper/solarmutex.hxx @@ -22,10 +22,13 @@ #include <sal/config.h> +#include <osl/thread.hxx> +#include <osl/mutex.hxx> #include <comphelper/comphelperdllapi.h> namespace comphelper { + /** * Abstract SolarMutex interface, needed for VCL's * Application::GetSolarMutex(). @@ -37,29 +40,82 @@ namespace comphelper { */ class COMPHELPER_DLLPUBLIC SolarMutex { public: - virtual void acquire() = 0; + typedef void (*BeforeReleaseHandler) (); - virtual void release() = 0; + void acquire( sal_uInt32 nLockCount = 1 ); + sal_uInt32 release( bool bUnlockAll = false ); virtual bool tryToAcquire() = 0; + // returns true, if the mutex is owned by the current thread + virtual bool IsCurrentThread() const = 0; + /// Help components to get the SolarMutex easily. static SolarMutex *get(); - /// semi-private: allow VCL to push its one-big-lock down here. - static void setSolarMutex( SolarMutex *pMutex ); - protected: SolarMutex(); - virtual ~SolarMutex(); + + /// allow VCL to push its one-big-lock down here. + static void setSolarMutex( SolarMutex *pMutex ); + + virtual sal_uInt32 doRelease( bool bUnlockAll ) = 0; + virtual void doAcquire( sal_uInt32 nLockCount ) = 0; + private: SolarMutex(const SolarMutex&) = delete; SolarMutex& operator=(const SolarMutex&) = delete; }; +inline void SolarMutex::acquire( sal_uInt32 nLockCount ) +{ + assert( nLockCount > 0 ); + doAcquire( nLockCount ); +} + +inline sal_uInt32 SolarMutex::release( bool bUnlockAll ) +{ + return doRelease( bUnlockAll ); +} + + +/** + * Generic implementation of the abstract SolarMutex interface. + * + * Treat this as a singleton, as its constructor calls + * setSolarMutex( this )! + * + * Kept seperately from SolarMutex, so others can implement fascades. + */ +class COMPHELPER_DLLPUBLIC GenericSolarMutex + : public SolarMutex +{ +public: + void SetBeforeReleaseHandler( const BeforeReleaseHandler& rLink ) + { m_aBeforeReleaseHandler = rLink; } + + virtual bool tryToAcquire() override; + virtual bool IsCurrentThread() const override; + +protected: + osl::Mutex m_aMutex; + sal_uInt32 m_nCount; + oslThreadIdentifier m_nThreadId; + + virtual void doAcquire( sal_uInt32 nLockCount ) override; + virtual sal_uInt32 doRelease( bool bUnlockAll ) override; + +protected: + GenericSolarMutex(); + virtual ~GenericSolarMutex() override; + +private: + BeforeReleaseHandler m_aBeforeReleaseHandler; +}; + } -#endif +#endif // INCLUDED_COMPHELPER_SOLARMUTEX_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/osl/mutex.hxx b/include/osl/mutex.hxx index f42323b9fd0a..7ff265f149ed 100644 --- a/include/osl/mutex.hxx +++ b/include/osl/mutex.hxx @@ -110,29 +110,36 @@ namespace osl private: Guard( const Guard& ) SAL_DELETED_FUNCTION; const Guard& operator = ( const Guard& ) SAL_DELETED_FUNCTION; - protected: - T * pT; + T * m_pT; + const bool m_bAquired; public: /** Acquires the object specified as parameter. */ - Guard(T * pT_) : pT(pT_) + Guard(T * pT, bool bAquire = true) + : m_pT(pT) + , m_bAquired(bAquire) { - pT->acquire(); + if ( m_bAquired ) + m_pT->acquire(); } /** Acquires the object specified as parameter. */ - Guard(T & t) : pT(&t) + Guard(T & rT, bool bAquire = true) + : m_pT(&rT) + , m_bAquired( bAquire ) { - pT->acquire(); + if ( m_bAquired ) + m_pT->acquire(); } /** Releases the mutex or interface. */ ~Guard() { - pT->release(); + if ( m_bAquired ) + m_pT->release(); } }; diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx index 7bdb4daccfb6..be6ea6f8a53c 100644 --- a/include/vcl/svapp.hxx +++ b/include/vcl/svapp.hxx @@ -28,6 +28,7 @@ #include <vector> #include <comphelper/solarmutex.hxx> +#include <osl/mutex.hxx> #include <rtl/ustring.hxx> #include <osl/thread.hxx> #include <tools/gen.hxx> @@ -531,7 +532,7 @@ public: @see Execute, Quit, Reschedule, Yield, EndYield, GetSolarMutex, GetMainThreadIdentifier, AcquireSolarMutex, */ - static sal_uLong ReleaseSolarMutex(); + static sal_uInt32 ReleaseSolarMutex(); /** @brief Acquire Solar Mutex(es) for this thread. @@ -541,7 +542,7 @@ public: @see Execute, Quit, Reschedule, Yield, EndYield, GetSolarMutex, GetMainThreadIdentifier, ReleaseSolarMutex, */ - static void AcquireSolarMutex( sal_uLong nCount ); + static void AcquireSolarMutex( sal_uInt32 nCount ); /** Queries whether the application is in "main", i.e. not yet in the event loop @@ -1397,110 +1398,28 @@ private: DECL_STATIC_LINK( Application, PostEventHandler, void*, void ); }; - class VCL_DLLPUBLIC SolarMutexGuard + : public osl::Guard<comphelper::SolarMutex> { -private: - SolarMutexGuard( const SolarMutexGuard& ) = delete; - const SolarMutexGuard& operator = ( const SolarMutexGuard& ) = delete; - comphelper::SolarMutex& m_solarMutex; - public: - /** Acquires the object specified as parameter. - */ - SolarMutexGuard() : - m_solarMutex(Application::GetSolarMutex()) - { - m_solarMutex.acquire(); - } - - /** Releases the mutex or interface. */ - ~SolarMutexGuard() - { - m_solarMutex.release(); - } + SolarMutexGuard( bool bAcquire = true ) + : osl::Guard<comphelper::SolarMutex>( Application::GetSolarMutex(), bAcquire ) {} }; -class VCL_DLLPUBLIC SolarMutexClearableGuard final +class VCL_DLLPUBLIC SolarMutexClearableGuard + : public osl::ClearableGuard<comphelper::SolarMutex> { - SolarMutexClearableGuard( const SolarMutexClearableGuard& ) = delete; - const SolarMutexClearableGuard& operator = ( const SolarMutexClearableGuard& ) = delete; - bool m_bCleared; - comphelper::SolarMutex& m_solarMutex; public: - /** Acquires mutex - */ SolarMutexClearableGuard() - : m_bCleared(false) - , m_solarMutex( Application::GetSolarMutex() ) - { - m_solarMutex.acquire(); - } - - /** Releases mutex. */ - ~SolarMutexClearableGuard() - { - if( !m_bCleared ) - { - m_solarMutex.release(); - } - } - - /** Releases mutex. */ - void SAL_CALL clear() - { - if( !m_bCleared ) - { - m_solarMutex.release(); - m_bCleared = true; - } - } + : osl::ClearableGuard<comphelper::SolarMutex>( Application::GetSolarMutex() ) {} }; -class VCL_DLLPUBLIC SolarMutexResettableGuard final +class VCL_DLLPUBLIC SolarMutexResettableGuard + : public osl::ResettableGuard<comphelper::SolarMutex> { - SolarMutexResettableGuard( const SolarMutexResettableGuard& ) = delete; - const SolarMutexResettableGuard& operator = ( const SolarMutexResettableGuard& ) = delete; - bool m_bCleared; - comphelper::SolarMutex& m_solarMutex; public: - /** Acquires mutex - */ SolarMutexResettableGuard() - : m_bCleared(false) - , m_solarMutex( Application::GetSolarMutex() ) - { - m_solarMutex.acquire(); - } - - /** Releases mutex. */ - ~SolarMutexResettableGuard() - { - if( !m_bCleared ) - { - m_solarMutex.release(); - } - } - - /** Releases mutex. */ - void SAL_CALL clear() - { - if( !m_bCleared) - { - m_solarMutex.release(); - m_bCleared = true; - } - } - - /** Re-acquires mutex. */ - void SAL_CALL reset() - { - if( m_bCleared) - { - m_solarMutex.acquire(); - m_bCleared = false; - } - } + : osl::ResettableGuard<comphelper::SolarMutex>( Application::GetSolarMutex() ) {} }; namespace vcl @@ -1559,14 +1478,20 @@ public: */ class SolarMutexReleaser { - sal_uLong mnReleased; + sal_uInt32 mnReleased; public: - SolarMutexReleaser(): mnReleased(Application::ReleaseSolarMutex()) {} + SolarMutexReleaser( bool bDoRelease = true ) + : mnReleased( 0 ) + { + if ( bDoRelease ) + mnReleased = Application::ReleaseSolarMutex(); + } ~SolarMutexReleaser() { - Application::ReAcquireSolarMutex(mnReleased); + if ( mnReleased ) + Application::ReAcquireSolarMutex( mnReleased ); } }; diff --git a/vcl/android/androidinst.cxx b/vcl/android/androidinst.cxx index a2cb49cb60aa..afb919a2e4e9 100644 --- a/vcl/android/androidinst.cxx +++ b/vcl/android/androidinst.cxx @@ -191,13 +191,13 @@ SalInstance *CreateSalInstance() LOGI("Android: CreateSalInstance!"); AndroidSalInstance* pInstance = new AndroidSalInstance( new SalYieldMutex() ); new AndroidSalData( pInstance ); - pInstance->AcquireYieldMutex(1); + pInstance->AcquireYieldMutex(); return pInstance; } void DestroySalInstance( SalInstance *pInst ) { - pInst->ReleaseYieldMutex(); + pInst->ReleaseYieldMutex( true ); delete pInst; } diff --git a/vcl/headless/headlessinst.cxx b/vcl/headless/headlessinst.cxx index e6f5cf03f5b3..69027f3ccb3c 100644 --- a/vcl/headless/headlessinst.cxx +++ b/vcl/headless/headlessinst.cxx @@ -92,13 +92,13 @@ SalInstance *CreateSalInstance() { HeadlessSalInstance* pInstance = new HeadlessSalInstance( new SalYieldMutex() ); new HeadlessSalData( pInstance ); - pInstance->AcquireYieldMutex(1); + pInstance->AcquireYieldMutex(); return pInstance; } void DestroySalInstance( SalInstance *pInst ) { - pInst->ReleaseYieldMutex(); + pInst->ReleaseYieldMutex( true ); delete pInst; } diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx index 4ebeac8f4a3c..b75a035466f1 100644 --- a/vcl/headless/svpinst.cxx +++ b/vcl/headless/svpinst.cxx @@ -389,7 +389,7 @@ void SvpSalInstance::DoReleaseYield( int nTimeoutMS ) aPoll.revents = 0; // release yield mutex - sal_uLong nAcquireCount = ReleaseYieldMutex(); + sal_uInt32 nAcquireCount = ReleaseYieldMutex( true ); (void)poll( &aPoll, 1, nTimeoutMS ); diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h index 104b96ba9401..f7e5c219175d 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -37,19 +37,17 @@ class ApplicationEvent; class Image; enum class SalEvent; -class SalYieldMutex : public comphelper::SolarMutex +class SalYieldMutex : public comphelper::GenericSolarMutex { - osl::Mutex m_mutex; - sal_uLong mnCount; - oslThreadIdentifier mnThreadId; + bool mbInAquireWithTry; + +protected: + virtual void doAcquire( sal_uInt32 nLockCount ) override; + virtual sal_uInt32 doRelease( bool bUnlockAll ) override; public: - SalYieldMutex(); - virtual void acquire() override; - virtual void release() override; - virtual bool tryToAcquire() override; - sal_uLong GetAcquireCount() const { return mnCount; } - oslThreadIdentifier GetThreadId() const { return mnThreadId; } + SalYieldMutex(); + virtual ~SalYieldMutex(); }; class AquaSalInstance : public SalInstance @@ -104,9 +102,8 @@ public: virtual SalSystem* CreateSalSystem() override; virtual SalBitmap* CreateSalBitmap() override; virtual comphelper::SolarMutex* GetYieldMutex() override; - virtual sal_uLong ReleaseYieldMutex() override; - virtual void AcquireYieldMutex( sal_uLong nCount ) override; - virtual bool CheckYieldMutex() 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 AnyInput( VclInputFlags nType ) override; @@ -156,15 +153,6 @@ public: static NSMenu* GetDynamicDockMenu(); }; -// helper class: inverted solar guard -class YieldMutexReleaser -{ - sal_uLong mnCount; - public: - YieldMutexReleaser(); - ~YieldMutexReleaser(); -}; - CGImageRef CreateCGImage( const Image& ); NSImage* CreateNSImage( const Image& ); diff --git a/vcl/inc/salinst.hxx b/vcl/inc/salinst.hxx index 03491553c62a..12959cc44280 100644 --- a/vcl/inc/salinst.hxx +++ b/vcl/inc/salinst.hxx @@ -25,6 +25,7 @@ #include <tools/solar.h> #include <vcl/dllapi.h> #include <vcl/salgtype.hxx> +#include <osl/thread.hxx> #include "displayconnectiondispatch.hxx" @@ -121,10 +122,9 @@ public: // YieldMutex virtual comphelper::SolarMutex* GetYieldMutex() = 0; - virtual sal_uLong ReleaseYieldMutex() = 0; - virtual void AcquireYieldMutex( sal_uLong nCount ) = 0; + virtual sal_uInt32 ReleaseYieldMutex( bool bUnlockAll = false ) = 0; + virtual void AcquireYieldMutex( sal_uInt32 nCount = 1 ) = 0; // return true, if yield mutex is owned by this thread, else false - virtual bool CheckYieldMutex() = 0; virtual bool IsMainThread() const = 0; /** diff --git a/vcl/inc/unx/geninst.h b/vcl/inc/unx/geninst.h index 2c99a7b3e0a1..5b3cbc9c98b6 100644 --- a/vcl/inc/unx/geninst.h +++ b/vcl/inc/unx/geninst.h @@ -30,7 +30,8 @@ class VCL_DLLPUBLIC SalYieldMutexReleaser { - sal_uLong m_nYieldCount; + sal_uInt32 m_nYieldCount; + public: inline SalYieldMutexReleaser(); inline ~SalYieldMutexReleaser(); @@ -38,32 +39,20 @@ public: inline SalYieldMutexReleaser::SalYieldMutexReleaser() { - m_nYieldCount = GetSalData()->m_pInstance->ReleaseYieldMutex(); + m_nYieldCount = GetSalData()->m_pInstance->ReleaseYieldMutex( true ); } inline SalYieldMutexReleaser::~SalYieldMutexReleaser() { - GetSalData()->m_pInstance->AcquireYieldMutex( m_nYieldCount ); + if ( m_nYieldCount ) + GetSalData()->m_pInstance->AcquireYieldMutex( m_nYieldCount ); } -class VCL_DLLPUBLIC SalYieldMutex : public comphelper::SolarMutex +class VCL_DLLPUBLIC SalYieldMutex : public comphelper::GenericSolarMutex { - osl::Mutex m_mutex; - -protected: - sal_uIntPtr mnCount; - oslThreadIdentifier mnThreadId; - public: - SalYieldMutex(); - virtual ~SalYieldMutex() override; - - virtual void acquire() override; - virtual void release() override; - virtual bool tryToAcquire() override; - - sal_uIntPtr GetAcquireCount() const { return mnCount; } - oslThreadIdentifier GetThreadId() const { return mnThreadId; } + SalYieldMutex(); + virtual ~SalYieldMutex() override; }; /* @@ -84,9 +73,8 @@ public: // Yield mutex virtual comphelper::SolarMutex* GetYieldMutex() override; - virtual sal_uIntPtr ReleaseYieldMutex() override; - virtual void AcquireYieldMutex( sal_uIntPtr nCount ) override; - virtual bool CheckYieldMutex() override; + virtual sal_uInt32 ReleaseYieldMutex( bool bUnlockAll = false ) override; + virtual void AcquireYieldMutex( sal_uInt32 nCount = 1 ) override; // Printing virtual SalInfoPrinter* CreateInfoPrinter ( SalPrinterQueueInfo* pQueueInfo, diff --git a/vcl/inc/win/saldata.hxx b/vcl/inc/win/saldata.hxx index 4d8361d57325..bc5b9c5db1eb 100644 --- a/vcl/inc/win/saldata.hxx +++ b/vcl/inc/win/saldata.hxx @@ -172,11 +172,9 @@ bool ImplLoadSalIcon( int nId, HICON& rIcon, HICON& rSmallIcon ); void ImplInitSalGDI(); void ImplFreeSalGDI(); -void ImplSalYieldMutexAcquireWithWait( sal_uLong nCount = 1 ); +void ImplSalYieldMutexAcquireWithWait( sal_uInt32 nCount = 1 ); bool ImplSalYieldMutexTryToAcquire(); void ImplSalYieldMutexRelease(); -sal_uLong ImplSalReleaseYieldMutex(); -void ImplSalAcquireYieldMutex( sal_uLong nCount ); LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ); diff --git a/vcl/inc/win/salinst.h b/vcl/inc/win/salinst.h index 03ba573c523b..6efecbd6bd5e 100644 --- a/vcl/inc/win/salinst.h +++ b/vcl/inc/win/salinst.h @@ -59,9 +59,8 @@ public: virtual SalSystem* CreateSalSystem() override; virtual SalBitmap* CreateSalBitmap() override; virtual comphelper::SolarMutex* GetYieldMutex() override; - virtual sal_uIntPtr ReleaseYieldMutex() override; - virtual void AcquireYieldMutex( sal_uIntPtr nCount ) override; - virtual bool CheckYieldMutex() override; + virtual sal_uInt32 ReleaseYieldMutex( bool bUnlockAll = false ) override; + virtual void AcquireYieldMutex( sal_uInt32 nCount = 1 ) override; virtual bool IsMainThread() const override; virtual bool DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) override; diff --git a/vcl/inc/win/salprn.h b/vcl/inc/win/salprn.h index a483e2502cc7..ed6005283661 100644 --- a/vcl/inc/win/salprn.h +++ b/vcl/inc/win/salprn.h @@ -84,6 +84,9 @@ public: bool mbValid; +protected: + void DoEndDoc(HDC hDC); + public: WinSalPrinter(); virtual ~WinSalPrinter() override; diff --git a/vcl/ios/iosinst.cxx b/vcl/ios/iosinst.cxx index b4b6f1f9f0bd..fb2d79b2fd59 100644 --- a/vcl/ios/iosinst.cxx +++ b/vcl/ios/iosinst.cxx @@ -172,13 +172,13 @@ SalInstance *CreateSalInstance() { IosSalInstance* pInstance = new IosSalInstance( new SalYieldMutex() ); new IosSalData( pInstance ); - pInstance->AcquireYieldMutex(1); + pInstance->AcquireYieldMutex(); return pInstance; } void DestroySalInstance( SalInstance *pInst ) { - pInst->ReleaseYieldMutex(); + pInst->ReleaseYieldMutex( true ); delete pInst; } diff --git a/vcl/osx/salframeview.mm b/vcl/osx/salframeview.mm index a20f3b7a6e5a..d205c0b3b1db 100644 --- a/vcl/osx/salframeview.mm +++ b/vcl/osx/salframeview.mm @@ -223,13 +223,8 @@ static AquaSalFrame* getMouseContainerFrame() { if( GetSalData() && GetSalData()->mpFirstInstance ) { - comphelper::SolarMutex* pMutex = GetSalData()->mpFirstInstance->GetYieldMutex(); - if( pMutex ) - { - pMutex->acquire(); - [super displayIfNeeded]; - pMutex->release(); - } + SolarMutexGuard aGuard; + [super displayIfNeeded]; } } diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index 426d83544383..721a32ac2298 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -259,42 +259,52 @@ void InitSalMain() } SalYieldMutex::SalYieldMutex() + : mbInAquireWithTry( false ) { - mnCount = 0; - mnThreadId = 0; } -void SalYieldMutex::acquire() +SalYieldMutex::~SalYieldMutex() { - m_mutex.acquire(); - mnThreadId = osl::Thread::getCurrentIdentifier(); - mnCount++; } -void SalYieldMutex::release() +void SalYieldMutex::doAcquire( sal_uInt32 nLockCount ) { - if ( mnThreadId == osl::Thread::getCurrentIdentifier() ) + if ( GetSalData()->mpFirstInstance && GetSalData()->mpFirstInstance->IsMainThread() ) { - if ( mnCount == 1 ) + while ( !m_aMutex.tryToAcquire() ) { - // TODO: add OpenGLContext::prepareForYield with vcl OpenGL support - mnThreadId = 0; + mbInAquireWithTry = true; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSApplicationDefinedMask' is deprecated: first deprecated in macOS 10.12 + NSEvent* pPeekEvent = [NSApp nextEventMatchingMask: NSApplicationDefinedMask +SAL_WNODEPRECATED_DECLARATIONS_POP + untilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1] + inMode: NSDefaultRunLoopMode + dequeue: YES]; + if ( AquaSalInstance::UnlockedYieldMutexEvent != (int) [pPeekEvent subtype] ) + [NSApp postEvent: pPeekEvent atStart: YES]; } - mnCount--; + mbInAquireWithTry = false; } - m_mutex.release(); + else + m_aMutex.acquire(); + ++m_nCount; + --nLockCount; + + comphelper::GenericSolarMutex::doAcquire( nLockCount ); } -bool SalYieldMutex::tryToAcquire() +sal_uInt32 SalYieldMutex::doRelease( const bool bUnlockAll ) { - if ( m_mutex.tryToAcquire() ) - { - mnThreadId = osl::Thread::getCurrentIdentifier(); - mnCount++; - return true; - } - else - return false; + sal_uInt32 nCount = comphelper::GenericSolarMutex::doRelease( bUnlockAll ); + + if ( mbInAquireWithTry && 0 == m_nCount + && !GetSalData()->mpFirstInstance->IsMainThread() ) + dispatch_async(dispatch_get_main_queue(),^{ + ImplNSAppPostEvent( AquaSalInstance::UnlockedYieldMutexEvent, NO ); + }); + + return nCount; } // some convenience functions regarding the yield mutex, aka solar mutex @@ -352,14 +362,12 @@ AquaSalInstance::AquaSalInstance() { mpSalYieldMutex = new SalYieldMutex; mpSalYieldMutex->acquire(); - ::comphelper::SolarMutex::setSolarMutex( mpSalYieldMutex ); maMainThread = osl::Thread::getCurrentIdentifier(); mnActivePrintJobs = 0; } AquaSalInstance::~AquaSalInstance() { - ::comphelper::SolarMutex::setSolarMutex( nullptr ); mpSalYieldMutex->release(); delete mpSalYieldMutex; } @@ -381,47 +389,14 @@ comphelper::SolarMutex* AquaSalInstance::GetYieldMutex() return mpSalYieldMutex; } -sal_uLong AquaSalInstance::ReleaseYieldMutex() +sal_uInt32 AquaSalInstance::ReleaseYieldMutex( bool bUnlockAll ) { - SalYieldMutex* pYieldMutex = mpSalYieldMutex; - if ( pYieldMutex->GetThreadId() == - osl::Thread::getCurrentIdentifier() ) - { - sal_uLong nCount = pYieldMutex->GetAcquireCount(); - sal_uLong n = nCount; - while ( n ) - { - pYieldMutex->release(); - n--; - } - - return nCount; - } - else - return 0; + return mpSalYieldMutex->release( bUnlockAll ); } -void AquaSalInstance::AcquireYieldMutex( sal_uLong nCount ) +void AquaSalInstance::AcquireYieldMutex( sal_uInt32 nCount ) { - SalYieldMutex* pYieldMutex = mpSalYieldMutex; - while ( nCount ) - { - pYieldMutex->acquire(); - nCount--; - } -} - -bool AquaSalInstance::CheckYieldMutex() -{ - bool bRet = true; - - SalYieldMutex* pYieldMutex = mpSalYieldMutex; - if ( pYieldMutex->GetThreadId() != osl::Thread::getCurrentIdentifier()) - { - bRet = false; - } - - return bRet; + mpSalYieldMutex->acquire( nCount ); } bool AquaSalInstance::IsMainThread() const @@ -473,7 +448,7 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) // dispatch it if ( aEvent.mpFrame ) { - osl::Guard< comphelper::SolarMutex > aGuard( *mpSalYieldMutex ); + SolarMutexGuard aGuard; if ( AquaSalFrame::isAlive( aEvent.mpFrame ) ) aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData ); } @@ -573,8 +548,6 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLon NSEvent* pEvent = nil; do { - sal_uLong nCount = ReleaseYieldMutex(); - SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12 pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask @@ -584,18 +557,18 @@ SAL_WNODEPRECATED_DECLARATIONS_POP dequeue: YES]; if( pEvent ) { + SolarMutexReleaser aReleaser; [NSApp sendEvent: pEvent]; + [NSApp updateWindows]; bHadEvent = true; } - [NSApp updateWindows]; - - AcquireYieldMutex( nCount ); - } while( bHandleAllCurrentEvents && pEvent ); + } + while( bHandleAllCurrentEvents && pEvent ); // if we had no event yet, wait for one if requested if( bWait && ! bHadEvent ) { - sal_uLong nCount = ReleaseYieldMutex(); + SolarMutexReleaser aReleaser; NSDate* pDt = AquaSalTimer::pRunningTimer ? [AquaSalTimer::pRunningTimer fireDate] : [NSDate distantFuture]; SAL_WNODEPRECATED_DECLARATIONS_PUSH @@ -608,8 +581,6 @@ SAL_WNODEPRECATED_DECLARATIONS_POP if( pEvent ) [NSApp sendEvent: pEvent]; [NSApp updateWindows]; - - AcquireYieldMutex( nCount ); } // collect update rectangles @@ -630,10 +601,8 @@ SAL_WNODEPRECATED_DECLARATIONS_POP // wait until any thread (most likely the main thread) // has dispatched an event, cop out at 200 ms maWaitingYieldCond.reset(); - TimeValue aVal = { 0, 200000000 }; - sal_uLong nCount = ReleaseYieldMutex(); - maWaitingYieldCond.wait( &aVal ); - AcquireYieldMutex( nCount ); + SolarMutexReleaser aReleaser; + maWaitingYieldCond.wait(); } // we get some apple events way too early @@ -957,23 +926,6 @@ OUString AquaSalInstance::getOSVersion() return aVersion; } -// YieldMutexReleaser -YieldMutexReleaser::YieldMutexReleaser() : mnCount( 0 ) -{ - SalData* pSalData = GetSalData(); - if( ! pSalData->mpFirstInstance->IsMainThread() ) - { - SalData::ensureThreadAutoreleasePool(); - mnCount = pSalData->mpFirstInstance->ReleaseYieldMutex(); - } -} - -YieldMutexReleaser::~YieldMutexReleaser() -{ - if( mnCount != 0 ) - GetSalData()->mpFirstInstance->AcquireYieldMutex( mnCount ); -} - CGImageRef CreateCGImage( const Image& rImage ) { BitmapEx aBmpEx( rImage.GetBitmapEx() ); diff --git a/vcl/source/app/dbggui.cxx b/vcl/source/app/dbggui.cxx index b191ae9a5b9d..f2ebc5117ddd 100644 --- a/vcl/source/app/dbggui.cxx +++ b/vcl/source/app/dbggui.cxx @@ -44,7 +44,7 @@ using namespace ::com::sun::star; void ImplDbgTestSolarMutex() { - assert(ImplGetSVData()->mpDefInst->CheckYieldMutex() && "SolarMutex not locked"); + assert(ImplGetSVData()->mpDefInst->GetYieldMutex()->IsCurrentThread() && "SolarMutex not owned!"); } void DbgGUIInitSolarMutexCheck() diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx index 5a5be865906f..c281c934e0a2 100644 --- a/vcl/source/app/svapp.cxx +++ b/vcl/source/app/svapp.cxx ... etc. - the rest is truncated
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits