Rebased ref, commits from common ancestor: commit 41a306ec32752d96987e8ebfb6038b320b0e60fb Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Fri Oct 28 11:05:18 2016 +0200
Add VCL scheduler documentation Change-Id: Id2476e39272f5e253c5edfce59e84b0e2902db82 diff --git a/vcl/README.scheduler b/vcl/README.scheduler new file mode 100644 index 000000000000..01add4b3613b --- /dev/null +++ b/vcl/README.scheduler @@ -0,0 +1,122 @@ += Introduction = + +The VCL scheduler handles LOs primary event queue. +It is simple by design, currently just a singly-linked list. + +The scheduler has the following behaviour: + +B.1. Tasks are scheduled just priority based +B.2. Implicitly cooperative AKA non-preemptive +B.3. It's not "fair" in any way (a consequence of B.2) +B.4. Tasks are handled round-robin (per priority) +B.5. Higher priorities have lower values +B.6. A small set of priorities instead of an flexible value AKA int + +There are some consequences due to this design. + +C.1. Higher priorority tasks starve lower priority tasks + As long as a higher task is available, lower tasks are never run! + See Anti-pattern. + +C.2. Tasks should be split into sensible blocks + If this can't really be done, process pending tasks by calling Application::Reschedule(). Or use a thread. + +C.3. This is not an OS scheduler + There is no real way to "fix" B.2. and B.3. If you need to do an preemptive task, use a thread! + OS schedulers need to be "fair". There are complex approaches, like RCU, priority inversion, priority inheritance, etc. to fix C.1., but most aren't useable in userspace (there even is a userspace RCU library, FWIW). + + += Driving the scheduler AKA the system timer = + +Scheduling is done using a single system timer (SalTimer) + + * There is just one system timer, which drives the LO event loop + * The system timer is supposed to be a single-shot timer, restarted by the Scheduler as approriate + * The timer must just run in the main window thread + * Messages are processed in order, by priority + * The scheduler runs with the Solar mutex acquired + + += Anti-pattern: Try detecting "real idle" time = + +Even if the application thinks it is currently idle, this may change just a millisecond later. All longer tasks should be either interruptable, call Application::Reschedule() to process pending events or even use a thread for blocking tasks, like I/O. + +You may want to schedule instant tasks, which have a dependency on a state or function. To prevent busy polling, you can sublass Idle and override the UpdateMinPeriod() function. A call of this function should be very quick. For an example have a look at SwDocIdle, which prevents the idle to act on busy documents, currently used by mail merge. + + += Anti-pattern: Dependencies via (fine grained) priorities = + +"Idle 1" should run before "Idle 2", therefore give "Idle 1" a higher priority then "Idle 2". +This just works correct for low frequency idles, but otherwise always breaks! + +If you have some longer work - even if it can be split by into schedulable, smaller blocks - you normally don't want to schedule it with a non-default priority, as it starves all lower priority tasks. Even if a block was processed in "Idle 1", it is scheduled with the same (higher) priority again. Changing the "Idle" to a "Timer" also won't work, as this breaks the dependency. + +What is needed is task based dependency handling, so if "Task 1" is done, it has to start "Task 2" and if "Task 1" is started again, it has to stop "Task 2". This currently has to be done by the implementor, but this feature can be added to the scheduler reasonably. + + += TODOs and ideas = + +== Move memory handling of Tasks into the scheduler == + +Currently the creator of a Task objects handles the memory of the task object. Actually a lot of Tasks are simply embedded into other objects. This makes multi-threaded handling of these object complex and the locking really hard. And there are also some special cases, where the invoking Task deletes itself at the end of its Invoke() function. +One way this is handled in other main loop implementations, like glib, is to refer to the Task just by an ID. So there is no direct interaction with the object and it'S actually forbidden to modify most of the tasks parameters after scheduling, e.g. a timer has to be destroyed and recreated to change the timeout. +In teh end nothing happens, if an ID is already missing. The scheduler is free to release a Task without any interference of a Task object. + +1. All tasks would need to be unembedded and become pointers +2.1. Change the Task to be reference counted, or +2.2. Create a Task object and transfer it into the scheduler. If you want to change it, you would have to receeve the Task from the scheduler and then push it again. This probably could be incorporated in the Start() and Stop() functions. + +== Locking (mp-sc) == + +LO currently crashes, when it adds new events to the scheduler without holding the SolarMutex. + +Locking needs to be implemented for multiple producers and a single consumer. + +While the consumer can process any task in the list, a producer is just allowed to append a task. + +The scheduler is implicitly deinitialized, when VCL start deinitialization starts setting ImplSVData::mbDeInit to true. +At this point no more tasks will be scheduled. + +The scheduler has to handle locking for the following situations: + + 1. when changing the first or the last element + The ImplSVData::mpAppendMutex protects ImplSVData::mpFirstSchedulerData and ImplSVData::mpLastSchedulerData pointers + 1.1 when adding an element + 1.2 when removing the last element + 1.3 when removing the first element + 2. when changing the list of freed scheduler objects + The ImplSVData::mpFreeListMutex protects the ImplSVData::mpFreeSchedulerData pointer + 3. when invoking a task + The ImplSVData::mpInvokeMutex and ImplSVData::maInvokeCondition protect the ImplSchedulerData::mbInScheduler boolean and ImplSchedulerData::mpScheduler pointer + 3.1 prevent dispose of the Scheduler object while invoked + 3.2 prevent detaching ImplSchedulerData from the Scheduler object + +The scheduler must always only run in the main thread. + +== Task dependencies AKA children == + +Every task can have a list of children / a child. This is just an idea and currently has no known users emulating the behaviour. + + * When a task is stopped, the children are started. + * When a task is started, the children are stopped. + +== Per priority time-sorted queues == + +This would result in O(1) scheduler. This kind of scheduler was used in the Linux kernel for some time (search Ingo Molinars O(1) scheduler). This can be a scheduling optimization, which would prevent walking longer event list. But quite probably the management overhead would be too large, as we have many one-shot events. + +To find the next task the scheduler just walks the (constant) list of priority queues and schedules the first ready event of any queue. + +The downside of this approach: Insert / Start / Reschedule(for "auto" tasks) now need O(log(n)) to find the position in the queue, instead of O(1) for a simple append. + +== Always process all (higher priority) pending events == + +Currently Application::Reschedule() processes a single event or "all" events, with "all" defined as "100" events in most backends. This already is "ignored" by the KDE4 backend, as Qt defines its ProcessPendingEvents() as always processing all pending events (there are ways to skip event classes, but no easy way to process just a single event). + +== Annotate task dependencies == + +Currently no formal annotation exists to describe dependencies between Tasks. I couldn't find any documentation, why a task has a certain priority. +This could probably be improved by adding a way to annotate Tasks and create trees / groups of tasks. + +== Easyhack: move Task and Scheduler into vcl namespace == + +Create it after the scheduler patchset was merged and add reference commit 9b077a0e480095f9de24dbed8c443b9e54b40847 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Wed Apr 5 14:44:34 2017 +0200 WIN shorten DoYield by using existing functions This also adds an sal_uLong nCount parameter to ImplSalYieldMutexAcquireWithWait, so it can be called like ImplSalAcquireYieldMutex and actually uses the result from the deferred DoYield. Change-Id: Ie3b466ad03e7ed8c35a62f41c09d09757865364d diff --git a/vcl/inc/win/saldata.hxx b/vcl/inc/win/saldata.hxx index 03641a297e23..a588b0c72698 100644 --- a/vcl/inc/win/saldata.hxx +++ b/vcl/inc/win/saldata.hxx @@ -160,7 +160,7 @@ bool ImplLoadSalIcon( int nId, HICON& rIcon, HICON& rSmallIcon ); void ImplInitSalGDI(); void ImplFreeSalGDI(); -void ImplSalYieldMutexAcquireWithWait(); +void ImplSalYieldMutexAcquireWithWait( sal_uLong nCount = 1 ); bool ImplSalYieldMutexTryToAcquire(); void ImplSalYieldMutexRelease(); sal_uLong ImplSalReleaseYieldMutex(); diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx index 502d18b8f2a9..b3b7ef30f08e 100644 --- a/vcl/win/app/salinst.cxx +++ b/vcl/win/app/salinst.cxx @@ -180,7 +180,7 @@ sal_uLong SalYieldMutex::GetAcquireCount( sal_uLong nThreadId ) /// note: while VCL is fully up and running (other threads started and /// before shutdown), the main thread must acquire SolarMutex only via /// this function to avoid deadlock -void ImplSalYieldMutexAcquireWithWait() +void ImplSalYieldMutexAcquireWithWait( sal_uLong nCount ) { WinSalInstance* pInst = GetSalData()->mpFirstInstance; if ( !pInst ) @@ -195,21 +195,26 @@ void ImplSalYieldMutexAcquireWithWait() // needed because if we don't reschedule, then we create deadlocks if a // Window's create/destroy is called via SendMessage() from another thread. // Have a look at the osl_waitCondition implementation for more info. - pInst->mpSalYieldMutex->m_condition.reset(); - while (!pInst->mpSalYieldMutex->tryToAcquire()) + SalYieldMutex * const pYieldMutex = pInst->mpSalYieldMutex; + osl::Condition &rCondition = pYieldMutex->m_condition; + while ( nCount ) { - // wait for SalYieldMutex::release() to set the condition - osl::Condition::Result res = pInst->mpSalYieldMutex->m_condition.wait(); - assert(osl::Condition::Result::result_ok == res); - // reset condition *before* acquiring! - pInst->mpSalYieldMutex->m_condition.reset(); + do { + // reset condition *before* acquiring! + rCondition.reset(); + if (pYieldMutex->tryToAcquire()) + break; + // wait for SalYieldMutex::release() to set the condition + osl::Condition::Result res = rCondition.wait(); + assert(osl::Condition::Result::result_ok == res); + } + while ( 1 ); + --nCount; } } else - { // If this is not the main thread, call acquire directly. - pInst->mpSalYieldMutex->acquire(); - } + ImplSalAcquireYieldMutex( nCount ); } bool ImplSalYieldMutexTryToAcquire() @@ -595,17 +600,8 @@ bool WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong bool bDidWork = false; // NOTE: if nReleased != 0 this will be called without SolarMutex // so don't do anything dangerous before releasing it here - SalYieldMutex* pYieldMutex = mpSalYieldMutex; - DWORD nCurThreadId = GetCurrentThreadId(); sal_uLong const nCount = (nReleased != 0) - ? nReleased - : pYieldMutex->GetAcquireCount(nCurThreadId); - sal_uLong n = (nReleased != 0) ? 0 : nCount; - while ( n ) - { - pYieldMutex->release(); - n--; - } + ? nReleased : ImplSalReleaseYieldMutex(); if ( !IsMainThread() ) { // #97739# A SendMessage call blocks until the called thread (here: the main thread) @@ -619,31 +615,20 @@ bool WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong // #i18883# only sleep if potential deadlock scenario, ie, when a dialog is open if( ImplGetSVData()->maAppData.mnModalMode ) - Sleep(1); + SwitchToThread(); else - SendMessageW( mhComWnd, SAL_MSG_THREADYIELD, (WPARAM)bWait, (LPARAM)bHandleAllCurrentEvents ); + bDidWork = SendMessageW( mhComWnd, SAL_MSG_THREADYIELD, (WPARAM)bWait, (LPARAM)bHandleAllCurrentEvents ); - n = nCount; - while ( n ) - { - pYieldMutex->acquire(); - n--; - } + ImplSalAcquireYieldMutex( nCount ); } else { if (nReleased == 0) // tdf#99383 ReAcquireSolarMutex shouldn't Yield - { bDidWork = ImplSalYield( bWait, bHandleAllCurrentEvents ); - } - n = nCount; - while ( n ) - { - ImplSalYieldMutexAcquireWithWait(); - n--; - } + ImplSalYieldMutexAcquireWithWait( nCount ); } + return bDidWork; } @@ -654,7 +639,7 @@ LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, i switch ( nMsg ) { case SAL_MSG_THREADYIELD: - ImplSalYield( (bool)wParam, (bool)lParam ); + nRet = static_cast<LRESULT>(ImplSalYield( (bool)wParam, (bool)lParam )); rDef = FALSE; break; case SAL_MSG_STARTTIMER: commit 52b147441d7491814d6a4ae694225820bc7e7e61 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Wed Sep 14 18:17:18 2016 +0200 Don't poll busy documents via idle task Creates a very busy idle-loop, for non-task work like mail merge. Change-Id: If7be82e4675008f23e6f4f6be5c40df40a231a8b diff --git a/sw/source/core/doc/DocumentTimerManager.cxx b/sw/source/core/doc/DocumentTimerManager.cxx index 83ce6fe2dce9..4a9855570bd6 100644 --- a/sw/source/core/doc/DocumentTimerManager.cxx +++ b/sw/source/core/doc/DocumentTimerManager.cxx @@ -40,44 +40,44 @@ namespace sw DocumentTimerManager::DocumentTimerManager( SwDoc& i_rSwdoc ) : m_rDoc( i_rSwdoc ), mbStartIdleTimer( false ), mIdleBlockCount( 0 ), - maIdle("DocumentTimerManagerIdleTimer") + maDocIdle( i_rSwdoc ) { - maIdle.SetPriority( TaskPriority::LOWEST ); - maIdle.SetInvokeHandler( LINK( this, DocumentTimerManager, DoIdleJobs) ); - maIdle.SetDebugName( "sw::DocumentTimerManager maIdle" ); + maDocIdle.SetPriority( TaskPriority::LOWEST ); + maDocIdle.SetInvokeHandler( LINK( this, DocumentTimerManager, DoIdleJobs) ); + maDocIdle.SetDebugName( "sw::DocumentTimerManager maDocIdle" ); } void DocumentTimerManager::StartIdling() { mbStartIdleTimer = true; if( !mIdleBlockCount ) - maIdle.Start(); + maDocIdle.Start(); } void DocumentTimerManager::StopIdling() { mbStartIdleTimer = false; - maIdle.Stop(); + maDocIdle.Stop(); } void DocumentTimerManager::BlockIdling() { - maIdle.Stop(); + maDocIdle.Stop(); ++mIdleBlockCount; } void DocumentTimerManager::UnblockIdling() { --mIdleBlockCount; - if( !mIdleBlockCount && mbStartIdleTimer && !maIdle.IsActive() ) - maIdle.Start(); + if( !mIdleBlockCount && mbStartIdleTimer && !maDocIdle.IsActive() ) + maDocIdle.Start(); } void DocumentTimerManager::StartBackgroundJobs() { // Trigger DoIdleJobs(), asynchronously. - if (!maIdle.IsActive()) //fdo#73165 if the timer is already running don't restart from 0 - maIdle.Start(); + if (!maDocIdle.IsActive()) //fdo#73165 if the timer is already running don't restart from 0 + maDocIdle.Start(); } IMPL_LINK( DocumentTimerManager, DoIdleJobs, Timer*, pIdle, void ) @@ -96,10 +96,7 @@ IMPL_LINK( DocumentTimerManager, DoIdleJobs, Timer*, pIdle, void ) for(SwViewShell& rSh : pShell->GetRingContainer()) { if( rSh.ActionPend() ) - { - pIdle->Start(); return; - } } if( pTmpRoot->IsNeedGrammarCheck() ) @@ -119,9 +116,7 @@ IMPL_LINK( DocumentTimerManager, DoIdleJobs, Timer*, pIdle, void ) if ((*pLayIter)->IsIdleFormat()) { (*pLayIter)->GetCurrShell()->LayoutIdle(); - // Defer the remaining work. - pIdle->Start(); return; } } @@ -135,11 +130,8 @@ IMPL_LINK( DocumentTimerManager, DoIdleJobs, Timer*, pIdle, void ) /* && !pStartSh->GetViewOptions()->IsFieldName()*/ ) { if ( m_rDoc.getIDocumentFieldsAccess().GetUpdateFields().IsInUpdateFields() || - m_rDoc.getIDocumentFieldsAccess().IsExpFieldsLocked() ) - { - pIdle->Start(); + m_rDoc.getIDocumentFieldsAccess().IsExpFieldsLocked() ) return; - } // Action brackets! m_rDoc.getIDocumentFieldsAccess().GetUpdateFields().SetInUpdateFields( true ); @@ -167,6 +159,7 @@ IMPL_LINK( DocumentTimerManager, DoIdleJobs, Timer*, pIdle, void ) if( pModLogFile && 1 != (long)pModLogFile ) delete pModLogFile, static_cast<long&>(pModLogFile) = 1; #endif + pIdle->Stop(); } DocumentTimerManager::~DocumentTimerManager() {} diff --git a/sw/source/core/inc/DocumentTimerManager.hxx b/sw/source/core/inc/DocumentTimerManager.hxx index da4b9e4b30fd..698762ab087e 100644 --- a/sw/source/core/inc/DocumentTimerManager.hxx +++ b/sw/source/core/inc/DocumentTimerManager.hxx @@ -21,8 +21,8 @@ #define INCLUDED_SW_SOURCE_CORE_INC_DOCUMENTTIMERMANAGER_HXX #include <IDocumentTimerAccess.hxx> +#include <SwDocIdle.hxx> -#include <vcl/idle.hxx> #include <sal/types.h> #include <tools/link.hxx> @@ -47,7 +47,6 @@ public: void StartBackgroundJobs() override; - // Our own 'IdleTimer' calls the following method DECL_LINK( DoIdleJobs, Timer *, void ); virtual ~DocumentTimerManager() override; @@ -61,7 +60,7 @@ private: bool mbStartIdleTimer; //< idle timer mode start/stop sal_Int32 mIdleBlockCount; - Idle maIdle; + SwDocIdle maDocIdle; }; } commit d907c14fdaec59d4ac3104ba54955c80076fabc4 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Sun Jul 31 16:35:49 2016 +0200 Don't update document stats for non-idle views This functionality should be merged into the DocumentTimerManager, which itself should run the different document idle tasks via seperate jobs instead of a single idle, if they don't depend on each other. To implement a non-busy, suspendable Idle, this adds an AutoIdle class, which is automatically re-scheduled after being processed. It also adds a SwDocIdle, which isn't ready to schedule for busy documents. Change-Id: I185137ed3423ecaae0f7edb39018d26c4244d359 diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk index 847d061af188..cd052dbffe7f 100644 --- a/sw/Library_sw.mk +++ b/sw/Library_sw.mk @@ -159,6 +159,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\ sw/source/core/crsr/trvltbl \ sw/source/core/crsr/viscrs \ sw/source/core/crsr/overlayrangesoutline \ + sw/source/core/doc/SwDocIdle \ sw/source/core/doc/SwStyleNameMapper \ sw/source/core/doc/acmplwrd \ sw/source/core/doc/CntntIdxStore \ diff --git a/sw/inc/SwDocIdle.hxx b/sw/inc/SwDocIdle.hxx new file mode 100644 index 000000000000..6bc65e24766c --- /dev/null +++ b/sw/inc/SwDocIdle.hxx @@ -0,0 +1,53 @@ +/* -*- 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_SW_INC_SWDOCIDLE_HXX +#define INCLUDED_SW_INC_SWDOCIDLE_HXX + +#include <doc.hxx> +#include <vcl/idle.hxx> + +namespace sw { + +/** + * An Idle, which is just ready to be scheduled for idle documents. + * + * Currently it's missing the notification, when busy documents become idle + * again, so it relies on any task being triggered to recheck, which is + * quite probably not a problem, as busy documents have a high chance to have + * generated idle tasks. + */ +class SwDocIdle : public AutoIdle +{ +private: + SwDoc &m_rDoc; + +protected: + virtual sal_uInt64 UpdateMinPeriod( + sal_uInt64 nMinPeriod, sal_uInt64 nTimeNow ) const override; + +public: + SwDocIdle( SwDoc &doc ); + virtual ~SwDocIdle() override; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/doc/DocumentStatisticsManager.cxx b/sw/source/core/doc/DocumentStatisticsManager.cxx index f529d5483417..9d050e0c77a0 100644 --- a/sw/source/core/doc/DocumentStatisticsManager.cxx +++ b/sw/source/core/doc/DocumentStatisticsManager.cxx @@ -34,6 +34,8 @@ #include <vector> #include <viewsh.hxx> #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <wrtsh.hxx> +#include <viewopt.hxx> using namespace ::com::sun::star; @@ -71,12 +73,13 @@ namespace sw DocumentStatisticsManager::DocumentStatisticsManager( SwDoc& i_rSwdoc ) : m_rDoc( i_rSwdoc ), mpDocStat( new SwDocStat ), - mbInitialized( false ) + mbInitialized( false ), + maStatsUpdateIdle( i_rSwdoc ) + { - maStatsUpdateTimer.SetTimeout( 1 ); - maStatsUpdateTimer.SetPriority( TaskPriority::LOWEST ); - maStatsUpdateTimer.SetInvokeHandler( LINK( this, DocumentStatisticsManager, DoIdleStatsUpdate ) ); - maStatsUpdateTimer.SetDebugName( "sw::DocumentStatisticsManager maStatsUpdateTimer" ); + maStatsUpdateIdle.SetPriority( TaskPriority::LOWEST ); + maStatsUpdateIdle.SetInvokeHandler( LINK( this, DocumentStatisticsManager, DoIdleStatsUpdate ) ); + maStatsUpdateIdle.SetDebugName( "sw::DocumentStatisticsManager maStatsUpdateIdle" ); } void DocumentStatisticsManager::DocInfoChgd(bool const isEnableSetModified) @@ -120,14 +123,15 @@ void DocumentStatisticsManager::UpdateDocStat( bool bCompleteAsync, bool bFields { if (!bCompleteAsync) { + maStatsUpdateIdle.Stop(); while (IncrementalDocStatCalculate( std::numeric_limits<long>::max(), bFields)) {} - maStatsUpdateTimer.Stop(); } - else if (IncrementalDocStatCalculate(5000, bFields)) - maStatsUpdateTimer.Start(); else - maStatsUpdateTimer.Stop(); + { + if (!maStatsUpdateIdle.IsActive() && IncrementalDocStatCalculate(5000, bFields)) + maStatsUpdateIdle.Start(); + } } } @@ -178,7 +182,7 @@ bool DocumentStatisticsManager::IncrementalDocStatCalculate(long nChars, bool bF } mpDocStat->nPage = m_rDoc.getIDocumentLayoutAccess().GetCurrentLayout() ? m_rDoc.getIDocumentLayoutAccess().GetCurrentLayout()->GetPageNum() : 0; - mpDocStat->bModified = false; + SetDocStatModified( false ); css::uno::Sequence < css::beans::NamedValue > aStat( mpDocStat->nPage ? 8 : 7); sal_Int32 n=0; @@ -233,11 +237,10 @@ bool DocumentStatisticsManager::IncrementalDocStatCalculate(long nChars, bool bF return nChars < 0; } -IMPL_LINK_NOARG( DocumentStatisticsManager, DoIdleStatsUpdate, Timer *, void ) +IMPL_LINK( DocumentStatisticsManager, DoIdleStatsUpdate, Timer *, pIdle, void ) { - if (IncrementalDocStatCalculate(32000)) - maStatsUpdateTimer.Start(); - + if (!IncrementalDocStatCalculate(32000)) + pIdle->Stop(); SwView* pView = m_rDoc.GetDocShell() ? m_rDoc.GetDocShell()->GetView() : nullptr; if( pView ) pView->UpdateDocStats(); @@ -245,7 +248,7 @@ IMPL_LINK_NOARG( DocumentStatisticsManager, DoIdleStatsUpdate, Timer *, void ) DocumentStatisticsManager::~DocumentStatisticsManager() { - maStatsUpdateTimer.Stop(); + maStatsUpdateIdle.Stop(); delete mpDocStat; } diff --git a/sw/source/core/doc/SwDocIdle.cxx b/sw/source/core/doc/SwDocIdle.cxx new file mode 100644 index 000000000000..9461807943d8 --- /dev/null +++ b/sw/source/core/doc/SwDocIdle.cxx @@ -0,0 +1,55 @@ +/* -*- 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 . + */ + +#include <view.hxx> +#include <wrtsh.hxx> +#include <docsh.hxx> +#include <viewopt.hxx> +#include <vcl/scheduler.hxx> + +#include "SwDocIdle.hxx" + +namespace sw +{ + +sal_uInt64 SwDocIdle::UpdateMinPeriod( sal_uInt64 /* nMinPeriod */, sal_uInt64 /* nTimeNow */ ) const +{ + bool bReadyForSchedule = true; + SwView* pView = m_rDoc.GetDocShell() ? m_rDoc.GetDocShell()->GetView() : nullptr; + if( pView ) + { + SwWrtShell& rWrtShell = pView->GetWrtShell(); + bReadyForSchedule = rWrtShell.GetViewOptions()->IsIdle(); + } + return bReadyForSchedule + ? Scheduler::ImmediateTimeoutMs : Scheduler::InfiniteTimeoutMs; +} + +SwDocIdle::SwDocIdle( SwDoc &doc ) + : m_rDoc( doc ) +{ +} + +SwDocIdle::~SwDocIdle() +{ +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/inc/DocumentStatisticsManager.hxx b/sw/source/core/inc/DocumentStatisticsManager.hxx index b21e8ec9ef99..41b961f9cae5 100644 --- a/sw/source/core/inc/DocumentStatisticsManager.hxx +++ b/sw/source/core/inc/DocumentStatisticsManager.hxx @@ -20,11 +20,10 @@ #define INCLUDED_SW_SOURCE_CORE_INC_DOCUMENTSTATISTICSMANAGER_HXX #include <IDocumentStatistics.hxx> -#include <vcl/timer.hxx> +#include <SwDocIdle.hxx> class SwDoc; struct SwDocStat; -class Timer; namespace sw { @@ -61,10 +60,9 @@ private: // Our own 'StatsUpdateTimer' calls the following method DECL_LINK( DoIdleStatsUpdate, Timer *, void ); - - SwDocStat *mpDocStat; //< Statistics information. - bool mbInitialized; // allow first time update - Timer maStatsUpdateTimer; //< Timer for asynchronous stats calculation + SwDocStat *mpDocStat; //< Statistics information + bool mbInitialized; //< allow first time update + SwDocIdle maStatsUpdateIdle; //< Idle for asynchronous stats calculation }; } commit 22bf1c11275d29aee0c4417a272220c624b7bfad Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Wed Aug 10 12:00:53 2016 +0200 Reorganize Scheduler priority classes This is based on glibs classification of tasks, but while glib uses an int for more fine grained priority, we stay with our enum. 1. Timers start with DEFAULT priority, which directly corresponds with the previous HIGH priority 2. Idles start with DEFAULT_IDLE priority instead of the previous HIGH priority, so idle default becomes "really run when idle". As RESIZE and REPAINT are special, and the DEFAULTS are set, there is just one primary decision for the programmer: should my idle run before paint (AKA HIGH_IDLE)? If we really need a more fine-grained classification, we can add it later, or also switch to a real int. As a result, this drops many classifications from the code and drastically changes behaviour, AKA a mail merge from KDE is now as fast as Gtk+ again. Change-Id: I498a73fd02d5fb6f5d7e9f742f3bce972de9b1f9 diff --git a/avmedia/source/framework/mediacontrol.cxx b/avmedia/source/framework/mediacontrol.cxx index 18d4f5599618..c44a12fd872c 100644 --- a/avmedia/source/framework/mediacontrol.cxx +++ b/avmedia/source/framework/mediacontrol.cxx @@ -114,7 +114,7 @@ MediaControl::MediaControl( vcl::Window* pParent, MediaControlStyle eControlStyl mpZoomToolBox->SetPaintTransparent( true ); } - maIdle.SetPriority( TaskPriority::LOW ); + maIdle.SetPriority( TaskPriority::HIGH_IDLE ); maIdle.SetInvokeHandler( LINK( this, MediaControl, implTimeoutHdl ) ); maIdle.Start(); } diff --git a/avmedia/source/framework/soundhandler.cxx b/avmedia/source/framework/soundhandler.cxx index 45f1b61132f7..a2ea3ed52ac0 100644 --- a/avmedia/source/framework/soundhandler.cxx +++ b/avmedia/source/framework/soundhandler.cxx @@ -221,7 +221,7 @@ void SAL_CALL SoundHandler::dispatchWithNotification(const css::util::URL& // Count this request and initialize self-holder against dying by uno ref count ... m_xSelfHold.set(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY); m_xPlayer->start(); - m_aUpdateIdle.SetPriority( TaskPriority::LOWER ); + m_aUpdateIdle.SetPriority( TaskPriority::HIGH_IDLE ); m_aUpdateIdle.Start(); } catch( css::uno::Exception& e ) diff --git a/avmedia/source/opengl/oglplayer.cxx b/avmedia/source/opengl/oglplayer.cxx index 18b4e9437d66..b44f77de6caf 100644 --- a/avmedia/source/opengl/oglplayer.cxx +++ b/avmedia/source/opengl/oglplayer.cxx @@ -123,7 +123,7 @@ bool OGLPlayer::create( const OUString& rURL ) // Set timer m_aTimer.SetTimeout(8); // is 125fps enough for anyone ? - m_aTimer.SetPriority(TaskPriority::LOW); + m_aTimer.SetPriority(TaskPriority::HIGH_IDLE); m_aTimer.SetInvokeHandler(LINK(this,OGLPlayer,TimerHandler)); return true; diff --git a/basctl/source/basicide/baside2b.cxx b/basctl/source/basicide/baside2b.cxx index c51f5e8e4dee..bd66b641789d 100644 --- a/basctl/source/basicide/baside2b.cxx +++ b/basctl/source/basicide/baside2b.cxx @@ -960,7 +960,6 @@ void EditorWindow::CreateEditEngine() ImplSetFont(); - aSyntaxIdle.SetPriority( TaskPriority::LOWER ); aSyntaxIdle.SetInvokeHandler( LINK( this, EditorWindow, SyntaxTimerHdl ) ); bool bWasDoSyntaxHighlight = bDoSyntaxHighlight; diff --git a/basctl/source/dlged/dlged.cxx b/basctl/source/dlged/dlged.cxx index bb8ddeff03a8..99a186ca2c29 100644 --- a/basctl/source/dlged/dlged.cxx +++ b/basctl/source/dlged/dlged.cxx @@ -217,7 +217,6 @@ DlgEditor::DlgEditor ( m_ClipboardDataFlavorsResource[1].HumanPresentableName = "Dialog 8.0" ; m_ClipboardDataFlavorsResource[1].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get(); - aMarkIdle.SetPriority(TaskPriority::LOW); aMarkIdle.SetInvokeHandler( LINK( this, DlgEditor, MarkTimeout ) ); rWindow.SetMapMode( MapMode( MapUnit::Map100thMM ) ); diff --git a/cui/source/options/optjava.cxx b/cui/source/options/optjava.cxx index 20fd7a9e0f5c..e539ec1bf143 100644 --- a/cui/source/options/optjava.cxx +++ b/cui/source/options/optjava.cxx @@ -186,7 +186,6 @@ SvxJavaOptionsPage::SvxJavaOptionsPage( vcl::Window* pParent, const SfxItemSet& m_pParameterBtn->SetClickHdl( LINK( this, SvxJavaOptionsPage, ParameterHdl_Impl ) ); m_pClassPathBtn->SetClickHdl( LINK( this, SvxJavaOptionsPage, ClassPathHdl_Impl ) ); m_aResetIdle.SetInvokeHandler( LINK( this, SvxJavaOptionsPage, ResetHdl_Impl ) ); - m_aResetIdle.SetPriority(TaskPriority::LOWER); m_pExpertConfigBtn->SetClickHdl( LINK( this, SvxJavaOptionsPage, ExpertConfigHdl_Impl) ); if (!officecfg::Office::Common::Security::EnableExpertConfiguration::get()) diff --git a/dbaccess/source/ui/querydesign/JoinTableView.cxx b/dbaccess/source/ui/querydesign/JoinTableView.cxx index 0c8fedfc97f9..af9c315c5615 100644 --- a/dbaccess/source/ui/querydesign/JoinTableView.cxx +++ b/dbaccess/source/ui/querydesign/JoinTableView.cxx @@ -1063,7 +1063,7 @@ void OJoinTableView::ScrollWhileDragging() // resetting timer, if still necessary if (bNeedScrollTimer) { - m_aDragScrollIdle.SetPriority(TaskPriority::LOW); + m_aDragScrollIdle.SetPriority( TaskPriority::HIGH_IDLE ); m_aDragScrollIdle.Start(); } diff --git a/formula/source/ui/dlg/formula.cxx b/formula/source/ui/dlg/formula.cxx index d795395884f7..a9e4ef33b0bc 100644 --- a/formula/source/ui/dlg/formula.cxx +++ b/formula/source/ui/dlg/formula.cxx @@ -1801,7 +1801,6 @@ OUString FormulaDlg::GetMeText() const void FormulaDlg::Update() { m_pImpl->Update(); - m_pImpl->aIdle.SetPriority(TaskPriority::LOWER); m_pImpl->aIdle.SetInvokeHandler(LINK( this, FormulaDlg, UpdateFocusHdl)); m_pImpl->aIdle.Start(); } diff --git a/formula/source/ui/dlg/funcutl.cxx b/formula/source/ui/dlg/funcutl.cxx index 685381fadb1c..35c8312a17d1 100644 --- a/formula/source/ui/dlg/funcutl.cxx +++ b/formula/source/ui/dlg/funcutl.cxx @@ -409,7 +409,6 @@ RefEdit::RefEdit( vcl::Window* _pParent, vcl::Window* pShrinkModeLabel, WinBits , pLabelWidget(pShrinkModeLabel) { aIdle.SetInvokeHandler( LINK( this, RefEdit, UpdateHdl ) ); - aIdle.SetPriority( TaskPriority::LOW ); } VCL_BUILDER_DECL_FACTORY(RefEdit) @@ -478,7 +477,6 @@ void RefEdit::SetReferences( IControlReferenceHandler* pDlg, vcl::Window* pLabel if( pDlg ) { aIdle.SetInvokeHandler( LINK( this, RefEdit, UpdateHdl ) ); - aIdle.SetPriority( TaskPriority::LOW ); } else { diff --git a/framework/source/layoutmanager/layoutmanager.cxx b/framework/source/layoutmanager/layoutmanager.cxx index 45ee6f67f135..659d84b0af31 100644 --- a/framework/source/layoutmanager/layoutmanager.cxx +++ b/framework/source/layoutmanager/layoutmanager.cxx @@ -138,6 +138,7 @@ LayoutManager::LayoutManager( const Reference< XComponentContext >& xContext ) : m_xToolbarManager = new ToolbarLayoutManager( xContext, Reference<XUIElementFactory>(m_xUIElementFactoryManager, UNO_QUERY_THROW), this ); } + m_aAsyncLayoutTimer.SetPriority( TaskPriority::HIGH_IDLE ); m_aAsyncLayoutTimer.SetTimeout( 50 ); m_aAsyncLayoutTimer.SetInvokeHandler( LINK( this, LayoutManager, AsyncLayoutHdl ) ); m_aAsyncLayoutTimer.SetDebugName( "framework::LayoutManager m_aAsyncLayoutTimer" ); diff --git a/include/vcl/task.hxx b/include/vcl/task.hxx index 573ee5db92d1..c955fb812e7f 100644 --- a/include/vcl/task.hxx +++ b/include/vcl/task.hxx @@ -29,16 +29,14 @@ struct ImplSchedulerData; enum class TaskPriority { - HIGHEST = 0, - HIGH = 1, - RESIZE = 2, - REPAINT = 3, - MEDIUM = 3, - POST_PAINT = 4, - DEFAULT_IDLE = 5, - LOW = 6, - LOWER = 7, - LOWEST = 8 + HIGHEST, ///< These events should run very fast! + DEFAULT, ///< Default priority used, e.g. the default timer priority + HIGH_IDLE, ///< Important idle events to be run before processing drawing events + RESIZE, ///< Resize runs before repaint, so we won't paint twice + REPAINT, ///< All repaint events should go in here + POST_PAINT, ///< Everything running directly after painting + DEFAULT_IDLE, ///< Default idle priority + LOWEST ///< Low, very idle cleanup tasks }; class VCL_DLLPUBLIC Task diff --git a/reportdesign/source/ui/report/DesignView.cxx b/reportdesign/source/ui/report/DesignView.cxx index ff6b97866952..b52eb7a3ce5e 100644 --- a/reportdesign/source/ui/report/DesignView.cxx +++ b/reportdesign/source/ui/report/DesignView.cxx @@ -116,7 +116,6 @@ ODesignView::ODesignView( vcl::Window* pParent, m_aSplitWin->SetAlign(WindowAlign::Left); m_aSplitWin->Show(); - m_aMarkIdle.SetPriority( TaskPriority::LOW ); m_aMarkIdle.SetInvokeHandler( LINK( this, ODesignView, MarkTimeout ) ); } diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx index d9149ff1788f..217f076a2f62 100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -250,7 +250,6 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) : SetLanguage( ScGlobal::eLnge, ScGlobal::eLnge, ScGlobal::eLnge ); aTrackIdle.SetInvokeHandler( LINK( this, ScDocument, TrackTimeHdl ) ); - aTrackIdle.SetPriority( TaskPriority::LOW ); } sfx2::LinkManager* ScDocument::GetLinkManager() diff --git a/sc/source/ui/app/scmod.cxx b/sc/source/ui/app/scmod.cxx index c25910d55dc0..0d03dc939308 100644 --- a/sc/source/ui/app/scmod.cxx +++ b/sc/source/ui/app/scmod.cxx @@ -179,7 +179,6 @@ ScModule::ScModule( SfxObjectFactory* pFact ) : ERRCODE_AREA_APP2-1, GetResMgr() ); - aSpellIdle.SetPriority(TaskPriority::LOWER); aSpellIdle.SetInvokeHandler( LINK( this, ScModule, SpellTimerHdl ) ); aSpellIdle.SetDebugName( "sc::ScModule aSpellIdle" ); diff --git a/sc/source/ui/miscdlgs/acredlin.cxx b/sc/source/ui/miscdlgs/acredlin.cxx index f33efa354854..700feef0825d 100644 --- a/sc/source/ui/miscdlgs/acredlin.cxx +++ b/sc/source/ui/miscdlgs/acredlin.cxx @@ -109,13 +109,11 @@ ScAcceptChgDlg::ScAcceptChgDlg(SfxBindings* pB, SfxChildWindow* pCW, vcl::Window m_pAcceptChgCtr = VclPtr<SvxAcceptChgCtr>::Create(get_content_area(), this); nAcceptCount=0; nRejectCount=0; - aReOpenIdle.SetPriority(TaskPriority::MEDIUM); aReOpenIdle.SetInvokeHandler(LINK( this, ScAcceptChgDlg, ReOpenTimerHdl )); pTPFilter=m_pAcceptChgCtr->GetFilterPage(); pTPView=m_pAcceptChgCtr->GetViewPage(); pTheView=pTPView->GetTableControl(); - aSelectionIdle.SetPriority(TaskPriority::LOW); aSelectionIdle.SetInvokeHandler(LINK( this, ScAcceptChgDlg, UpdateSelectionHdl )); aSelectionIdle.SetDebugName( "ScAcceptChgDlg aSelectionIdle" ); diff --git a/sc/source/ui/miscdlgs/anyrefdg.cxx b/sc/source/ui/miscdlgs/anyrefdg.cxx index 1b68a73c1c8a..8c1a9e6e9217 100644 --- a/sc/source/ui/miscdlgs/anyrefdg.cxx +++ b/sc/source/ui/miscdlgs/anyrefdg.cxx @@ -764,7 +764,6 @@ ScRefHandler::ScRefHandler( vcl::Window &rWindow, SfxBindings* pB, bool bBindRef pActiveWin(nullptr) { m_aHelper.SetWindow(m_rWindow.get()); - aIdle.SetPriority(TaskPriority::LOWER); aIdle.SetInvokeHandler(LINK( this, ScRefHandler, UpdateFocusHdl)); if( bBindRef ) EnterRefMode(); diff --git a/sc/source/ui/miscdlgs/conflictsdlg.cxx b/sc/source/ui/miscdlgs/conflictsdlg.cxx index a6c7104e9271..772f3a893493 100644 --- a/sc/source/ui/miscdlgs/conflictsdlg.cxx +++ b/sc/source/ui/miscdlgs/conflictsdlg.cxx @@ -421,7 +421,6 @@ ScConflictsDlg::ScConflictsDlg( vcl::Window* pParent, ScViewData* pViewData, ScD m_pLbConflicts->SetSelectionMode( SelectionMode::Multiple ); m_pLbConflicts->SetHighlightRange(); - maSelectionIdle.SetPriority( TaskPriority::LOW ); maSelectionIdle.SetInvokeHandler( LINK( this, ScConflictsDlg, UpdateSelectionHdl ) ); maSelectionIdle.SetDebugName( "ScConflictsDlg maSelectionIdle" ); diff --git a/sd/source/ui/dlg/filedlg.cxx b/sd/source/ui/dlg/filedlg.cxx index 7799458da69f..d97cf7923133 100644 --- a/sd/source/ui/dlg/filedlg.cxx +++ b/sd/source/ui/dlg/filedlg.cxx @@ -130,7 +130,6 @@ IMPL_LINK_NOARG(SdFileDialog_Imp, PlayMusicHdl, void*, void) { mxPlayer.set( avmedia::MediaWindow::createPlayer( aUrl, "" ), css::uno::UNO_QUERY_THROW ); mxPlayer->start(); - maUpdateIdle.SetPriority( TaskPriority::LOW ); maUpdateIdle.Start(); } catch (const css::uno::Exception&) diff --git a/sd/source/ui/framework/module/ShellStackGuard.cxx b/sd/source/ui/framework/module/ShellStackGuard.cxx index 2372158fe950..79171d026bd2 100644 --- a/sd/source/ui/framework/module/ShellStackGuard.cxx +++ b/sd/source/ui/framework/module/ShellStackGuard.cxx @@ -72,7 +72,6 @@ ShellStackGuard::ShellStackGuard (Reference<frame::XController>& rxController) // Prepare the printer polling. maPrinterPollingIdle.SetInvokeHandler(LINK(this,ShellStackGuard,TimeoutHandler)); - maPrinterPollingIdle.SetPriority(TaskPriority::LOWER); } } diff --git a/sd/source/ui/view/sdview.cxx b/sd/source/ui/view/sdview.cxx index 2856afa6355c..9f523b4f30eb 100644 --- a/sd/source/ui/view/sdview.cxx +++ b/sd/source/ui/view/sdview.cxx @@ -143,9 +143,7 @@ View::View(SdDrawDocument& rDrawDoc, OutputDevice* pOutDev, // Timer for delayed drop (has to be for MAC) maDropErrorIdle.SetInvokeHandler( LINK(this, View, DropErrorHdl) ); - maDropErrorIdle.SetPriority(TaskPriority::MEDIUM); maDropInsertFileIdle.SetInvokeHandler( LINK(this, View, DropInsertFileHdl) ); - maDropInsertFileIdle.SetPriority(TaskPriority::MEDIUM); } void View::ImplClearDrawDropMarker() diff --git a/sfx2/source/appl/appcfg.cxx b/sfx2/source/appl/appcfg.cxx index 1c3cdc82aeca..640b93b54ed1 100644 --- a/sfx2/source/appl/appcfg.cxx +++ b/sfx2/source/appl/appcfg.cxx @@ -109,7 +109,7 @@ SfxEventAsyncer_Impl::SfxEventAsyncer_Impl( const SfxEventHint& rHint ) StartListening( *rHint.GetObjShell() ); pIdle.reset( new Idle("SfxEventASyncer") ); pIdle->SetInvokeHandler( LINK(this, SfxEventAsyncer_Impl, IdleHdl) ); - pIdle->SetPriority( TaskPriority::HIGHEST ); + pIdle->SetPriority( TaskPriority::HIGH_IDLE ); pIdle->SetDebugName( "sfx::SfxEventAsyncer_Impl pIdle" ); pIdle->Start(); } diff --git a/sfx2/source/appl/newhelp.cxx b/sfx2/source/appl/newhelp.cxx index 061d94622c0a..9b40d5116742 100644 --- a/sfx2/source/appl/newhelp.cxx +++ b/sfx2/source/appl/newhelp.cxx @@ -551,7 +551,6 @@ IndexTabPage_Impl::IndexTabPage_Impl(vcl::Window* pParent, SfxHelpIndexWindow_Im m_pOpenBtn->SetClickHdl( LINK( this, IndexTabPage_Impl, OpenHdl ) ); aFactoryIdle.SetInvokeHandler( LINK(this, IndexTabPage_Impl, IdleHdl )); - aFactoryIdle.SetPriority(TaskPriority::LOWER); aKeywordTimer.SetInvokeHandler( LINK( this, IndexTabPage_Impl, TimeoutHdl ) ); } @@ -1431,7 +1430,6 @@ SfxHelpIndexWindow_Impl::SfxHelpIndexWindow_Impl(SfxHelpWindow_Impl* _pParent) nMinWidth = ( m_pActiveLB->GetSizePixel().Width() / 2 ); aIdle.SetInvokeHandler( LINK( this, SfxHelpIndexWindow_Impl, InitHdl ) ); - aIdle.SetPriority( TaskPriority::LOWER ); aIdle.Start(); Show(); diff --git a/sfx2/source/control/dispatch.cxx b/sfx2/source/control/dispatch.cxx index bc2e8dcda13c..3a599ac2095d 100644 --- a/sfx2/source/control/dispatch.cxx +++ b/sfx2/source/control/dispatch.cxx @@ -437,7 +437,7 @@ void SfxDispatcher::Construct_Impl() xImp->xPoster = new SfxHintPoster(aGenLink); - xImp->aIdle.SetPriority(TaskPriority::MEDIUM); + xImp->aIdle.SetPriority(TaskPriority::HIGH_IDLE ); xImp->aIdle.SetInvokeHandler( LINK(this, SfxDispatcher, EventHdl_Impl ) ); xImp->aIdle.SetDebugName( "sfx::SfxDispatcher_Impl aIdle" ); } @@ -561,8 +561,6 @@ void SfxDispatcher::Pop(SfxShell& rShell, SfxDispatcherPopFlags nMode) if(!pSfxApp->IsDowning() && !xImp->aToDoStack.empty()) { // No immediate update is requested - xImp->aIdle.SetPriority(TaskPriority::MEDIUM); - xImp->aIdle.SetInvokeHandler( LINK(this, SfxDispatcher, EventHdl_Impl ) ); xImp->aIdle.Start(); } else @@ -757,8 +755,6 @@ void SfxDispatcher::DoActivate_Impl(bool bMDI) if(!xImp->aToDoStack.empty()) { // No immediate update is requested - xImp->aIdle.SetPriority(TaskPriority::MEDIUM); - xImp->aIdle.SetInvokeHandler( LINK(this, SfxDispatcher, EventHdl_Impl ) ); xImp->aIdle.Start(); } } diff --git a/svtools/source/contnr/imivctl1.cxx b/svtools/source/contnr/imivctl1.cxx index 8e728c707fd8..115f3b1316ec 100644 --- a/svtools/source/contnr/imivctl1.cxx +++ b/svtools/source/contnr/imivctl1.cxx @@ -143,7 +143,7 @@ SvxIconChoiceCtrl_Impl::SvxIconChoiceCtrl_Impl( aEditIdle.SetInvokeHandler(LINK(this,SvxIconChoiceCtrl_Impl,EditTimeoutHdl)); aEditIdle.SetDebugName( "svtools::SvxIconChoiceCtrl_Impl aEditIdle" ); - aAutoArrangeIdle.SetPriority( TaskPriority::LOW ); + aAutoArrangeIdle.SetPriority( TaskPriority::HIGH_IDLE ); aAutoArrangeIdle.SetInvokeHandler(LINK(this,SvxIconChoiceCtrl_Impl,AutoArrangeHdl)); aAutoArrangeIdle.SetDebugName( "svtools::SvxIconChoiceCtrl_Impl aAutoArrangeIdle" ); @@ -151,11 +151,11 @@ SvxIconChoiceCtrl_Impl::SvxIconChoiceCtrl_Impl( aCallSelectHdlIdle.SetInvokeHandler( LINK(this,SvxIconChoiceCtrl_Impl,CallSelectHdlHdl)); aCallSelectHdlIdle.SetDebugName( "svtools::SvxIconChoiceCtrl_Impl aCallSelectHdlIdle" ); - aDocRectChangedIdle.SetPriority( TaskPriority::MEDIUM ); + aDocRectChangedIdle.SetPriority( TaskPriority::HIGH_IDLE ); aDocRectChangedIdle.SetInvokeHandler(LINK(this,SvxIconChoiceCtrl_Impl,DocRectChangedHdl)); aDocRectChangedIdle.SetDebugName( "svtools::SvxIconChoiceCtrl_Impl aDocRectChangedIdle" ); - aVisRectChangedIdle.SetPriority( TaskPriority::MEDIUM ); + aVisRectChangedIdle.SetPriority( TaskPriority::HIGH_IDLE ); aVisRectChangedIdle.SetInvokeHandler(LINK(this,SvxIconChoiceCtrl_Impl,VisRectChangedHdl)); aVisRectChangedIdle.SetDebugName( "svtools::SvxIconChoiceCtrl_Impl aVisRectChangedIdle" ); diff --git a/svx/source/dialog/_contdlg.cxx b/svx/source/dialog/_contdlg.cxx index 98dc5efd828d..7343083b823e 100644 --- a/svx/source/dialog/_contdlg.cxx +++ b/svx/source/dialog/_contdlg.cxx @@ -287,7 +287,6 @@ SvxSuperContourDlg::SvxSuperContourDlg(SfxBindings *_pBindings, SfxChildWindow * Resize(); - aUpdateIdle.SetPriority( TaskPriority::LOW ); aUpdateIdle.SetInvokeHandler( LINK( this, SvxSuperContourDlg, UpdateHdl ) ); aCreateIdle.SetPriority( TaskPriority::RESIZE ); diff --git a/svx/source/dialog/imapdlg.cxx b/svx/source/dialog/imapdlg.cxx index dcd1e5242e95..2b8def32b699 100644 --- a/svx/source/dialog/imapdlg.cxx +++ b/svx/source/dialog/imapdlg.cxx @@ -204,7 +204,6 @@ SvxIMapDlg::SvxIMapDlg(SfxBindings *_pBindings, SfxChildWindow *pCW, vcl::Window m_pCbbTarget->Disable(); pOwnData->bExecState = false; - pOwnData->aIdle.SetPriority( TaskPriority::LOW ); pOwnData->aIdle.SetInvokeHandler( LINK( this, SvxIMapDlg, UpdateHdl ) ); m_pTbxIMapDlg1->EnableItem( mnActiveId, false ); diff --git a/svx/source/sdr/contact/objectcontactofpageview.cxx b/svx/source/sdr/contact/objectcontactofpageview.cxx index 8643cfd30324..0c028a02f200 100644 --- a/svx/source/sdr/contact/objectcontactofpageview.cxx +++ b/svx/source/sdr/contact/objectcontactofpageview.cxx @@ -61,7 +61,7 @@ namespace sdr setPreviewRenderer(((SdrPaintView&)rPageWindow.GetPageView().GetView()).IsPreviewRenderer()); // init timer - SetPriority(TaskPriority::HIGH); + SetPriority(TaskPriority::HIGH_IDLE); Stop(); } diff --git a/svx/source/sdr/contact/viewobjectcontactofpageobj.cxx b/svx/source/sdr/contact/viewobjectcontactofpageobj.cxx index a6c3e63ba912..f8d19ff3150b 100644 --- a/svx/source/sdr/contact/viewobjectcontactofpageobj.cxx +++ b/svx/source/sdr/contact/viewobjectcontactofpageobj.cxx @@ -84,7 +84,7 @@ PagePrimitiveExtractor::PagePrimitiveExtractor( setPreviewRenderer(true); // init timer - SetPriority(TaskPriority::HIGH); + SetPriority(TaskPriority::HIGH_IDLE); Stop(); } diff --git a/svx/source/sdr/event/eventhandler.cxx b/svx/source/sdr/event/eventhandler.cxx index 9511c623a1a2..8d0e29592c92 100644 --- a/svx/source/sdr/event/eventhandler.cxx +++ b/svx/source/sdr/event/eventhandler.cxx @@ -81,7 +81,7 @@ namespace sdr TimerEventHandler::TimerEventHandler() { - SetPriority(TaskPriority::HIGH); + SetPriority(TaskPriority::HIGH_IDLE); Stop(); } diff --git a/svx/source/svdraw/svdibrow.cxx b/svx/source/svdraw/svdibrow.cxx index 97100753fee4..edf20b4a67c6 100644 --- a/svx/source/svdraw/svdibrow.cxx +++ b/svx/source/svdraw/svdibrow.cxx @@ -1100,7 +1100,7 @@ void SdrItemBrowser::SetDirty() { if (!bDirty) { bDirty = true; - aIdle.SetPriority(TaskPriority::HIGH); + aIdle.SetPriority(TaskPriority::HIGH_IDLE); aIdle.Start(); } } diff --git a/svx/source/tbxctrls/grafctrl.cxx b/svx/source/tbxctrls/grafctrl.cxx index a66609ec79af..36f6ff0e5d4a 100644 --- a/svx/source/tbxctrls/grafctrl.cxx +++ b/svx/source/tbxctrls/grafctrl.cxx @@ -121,7 +121,6 @@ ImplGrafMetricField::ImplGrafMetricField( vcl::Window* pParent, const OUString& SetSpinSize( 1 ); } - maIdle.SetPriority( TaskPriority::LOW ); maIdle.SetInvokeHandler( LINK( this, ImplGrafMetricField, ImplModifyHdl ) ); } diff --git a/sw/source/uibase/docvw/srcedtw.cxx b/sw/source/uibase/docvw/srcedtw.cxx index 26c6d5bcde8d..f6c97eee8ef7 100644 --- a/sw/source/uibase/docvw/srcedtw.cxx +++ b/sw/source/uibase/docvw/srcedtw.cxx @@ -534,7 +534,6 @@ void SwSrcEditWindow::CreateTextEngine() m_pOutWin->SetFont( aFont ); m_pTextEngine->SetFont( aFont ); - m_aSyntaxIdle.SetPriority( TaskPriority::LOWER ); m_aSyntaxIdle.SetInvokeHandler( LINK( this, SwSrcEditWindow, SyntaxTimerHdl ) ); m_pTextEngine->EnableUndo( true ); diff --git a/sw/source/uibase/utlui/unotools.cxx b/sw/source/uibase/utlui/unotools.cxx index 260a02176a07..89c7f3a80928 100644 --- a/sw/source/uibase/utlui/unotools.cxx +++ b/sw/source/uibase/utlui/unotools.cxx @@ -83,7 +83,7 @@ SwOneExampleFrame::SwOneExampleFrame( vcl::Window& rWin, // the controller is asynchronously set aLoadedIdle.SetInvokeHandler(LINK(this, SwOneExampleFrame, TimeoutHdl)); - aLoadedIdle.SetPriority(TaskPriority::HIGH); + aLoadedIdle.SetPriority(TaskPriority::HIGH_IDLE); CreateControl(); diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index c097a57ba125..a585bf1df23d 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -109,7 +109,6 @@ void AquaSalInstance::delayedSettingsChanged( bool bInvalidate ) { osl::Guard< comphelper::SolarMutex > aGuard( *mpSalYieldMutex ); AquaDelayedSettingsChanged* pIdle = new AquaDelayedSettingsChanged( bInvalidate ); - pIdle->SetPriority( TaskPriority::MEDIUM ); pIdle->Start(); } diff --git a/vcl/source/app/idle.cxx b/vcl/source/app/idle.cxx index 78c114801868..0eca28c52306 100644 --- a/vcl/source/app/idle.cxx +++ b/vcl/source/app/idle.cxx @@ -42,8 +42,7 @@ void Idle::Start() { switch ( GetPriority() ) { - case TaskPriority::LOW: - case TaskPriority::LOWER: + case TaskPriority::DEFAULT_IDLE: case TaskPriority::LOWEST: nPeriod = Scheduler::InfiniteTimeoutMs; break; diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx index 25e43baf9b44..b8fcc6756f7f 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -474,7 +474,7 @@ Task::~Task() TaskImpl::TaskImpl( const sal_Char *pDebugName ) : mpSchedulerData( nullptr ) , mpDebugName( pDebugName ) - , mePriority( TaskPriority::HIGH ) + , mePriority( TaskPriority::DEFAULT ) , mbActive( false ) { } diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx index 6321b5c28753..111d70d2985c 100644 --- a/vcl/source/app/svapp.cxx +++ b/vcl/source/app/svapp.cxx @@ -453,7 +453,7 @@ void Application::Execute() pSVData->maAppData.mnEventTestLimit = 50; pSVData->maAppData.mpEventTestingIdle = new Idle("eventtesting"); pSVData->maAppData.mpEventTestingIdle->SetInvokeHandler(LINK(&(pSVData->maAppData), ImplSVAppData, VclEventTestingHdl)); - pSVData->maAppData.mpEventTestingIdle->SetPriority(TaskPriority::MEDIUM); + pSVData->maAppData.mpEventTestingIdle->SetPriority(TaskPriority::HIGH_IDLE); pSVData->maAppData.mpEventTestInput = new SvFileStream("eventtesting", StreamMode::READ); pSVData->maAppData.mpEventTestingIdle->Start(); } diff --git a/vcl/source/app/timer.cxx b/vcl/source/app/timer.cxx index 6cba9e2f2b2f..f615c9f732e6 100644 --- a/vcl/source/app/timer.cxx +++ b/vcl/source/app/timer.cxx @@ -42,7 +42,7 @@ Timer::Timer( bool bAuto, const sal_Char *pDebugName ) , mnTimeout( Scheduler::ImmediateTimeoutMs ) , mbAuto( bAuto ) { - SetPriority( TaskPriority::HIGHEST ); + SetPriority( TaskPriority::DEFAULT ); } Timer::Timer( const sal_Char *pDebugName ) diff --git a/vcl/source/edit/textdata.cxx b/vcl/source/edit/textdata.cxx index 4705386be87e..e5de47c77b96 100644 --- a/vcl/source/edit/textdata.cxx +++ b/vcl/source/edit/textdata.cxx @@ -279,7 +279,7 @@ IdleFormatter::IdleFormatter() { mpView = nullptr; mnRestarts = 0; - SetPriority(TaskPriority::HIGH); + SetPriority(TaskPriority::HIGH_IDLE); } IdleFormatter::~IdleFormatter() diff --git a/vcl/source/uitest/uno/uiobject_uno.cxx b/vcl/source/uitest/uno/uiobject_uno.cxx index 594471a8fbcb..ce78590f747a 100644 --- a/vcl/source/uitest/uno/uiobject_uno.cxx +++ b/vcl/source/uitest/uno/uiobject_uno.cxx @@ -114,7 +114,7 @@ void SAL_CALL UIObjectUnoObj::executeAction(const OUString& rAction, const css:: mReady = false; Idle aIdle; aIdle.SetDebugName("UI Test Idle Handler"); - aIdle.SetPriority(TaskPriority::HIGH); + aIdle.SetPriority(TaskPriority::DEFAULT); std::function<void()> func = [this](){ diff --git a/vcl/source/window/dockmgr.cxx b/vcl/source/window/dockmgr.cxx index a68d5b1fbd6d..ce427cd412f9 100644 --- a/vcl/source/window/dockmgr.cxx +++ b/vcl/source/window/dockmgr.cxx @@ -88,11 +88,11 @@ ImplDockFloatWin2::ImplDockFloatWin2( vcl::Window* pParent, WinBits nWinBits, SetBackground( GetSettings().GetStyleSettings().GetFaceColor() ); maDockIdle.SetInvokeHandler( LINK( this, ImplDockFloatWin2, DockTimerHdl ) ); - maDockIdle.SetPriority( TaskPriority::MEDIUM ); + maDockIdle.SetPriority( TaskPriority::HIGH_IDLE ); maDockIdle.SetDebugName( "vcl::ImplDockFloatWin2 maDockIdle" ); maEndDockIdle.SetInvokeHandler( LINK( this, ImplDockFloatWin2, EndDockTimerHdl ) ); - maEndDockIdle.SetPriority( TaskPriority::MEDIUM ); + maDockIdle.SetPriority( TaskPriority::HIGH_IDLE ); maEndDockIdle.SetDebugName( "vcl::ImplDockFloatWin2 maEndDockIdle" ); } diff --git a/vcl/source/window/dockwin.cxx b/vcl/source/window/dockwin.cxx index 4f61ff8aed92..a00b2fb5aa8e 100644 --- a/vcl/source/window/dockwin.cxx +++ b/vcl/source/window/dockwin.cxx @@ -98,7 +98,7 @@ ImplDockFloatWin::ImplDockFloatWin( vcl::Window* pParent, WinBits nWinBits, SetBackground(); maDockIdle.SetInvokeHandler( LINK( this, ImplDockFloatWin, DockTimerHdl ) ); - maDockIdle.SetPriority( TaskPriority::MEDIUM ); + maDockIdle.SetPriority( TaskPriority::HIGH_IDLE ); maDockIdle.SetDebugName( "vcl::ImplDockFloatWin maDockIdle" ); } commit d3d25b279307ddd8dc855f268d69a0e4d1a2d959 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Sun Jan 29 17:12:25 2017 +0100 Drop Task::ReadyForSchedule All relevant information is also provided by UpdateMinPeriod and the calculations were even duplicated. This also includes dropping Scheduler::UpdateMinPeriod, as this is now reduced to a simple comparison and assignment, as we simply ignore larger returned sleep times. Change-Id: I13852e3e63daead451bf7fcb98be9b1d44bd7abd diff --git a/include/vcl/idle.hxx b/include/vcl/idle.hxx index cb96c09864c5..18d4e8abaab7 100644 --- a/include/vcl/idle.hxx +++ b/include/vcl/idle.hxx @@ -35,8 +35,8 @@ private: sal_uInt64 GetTimeout() const = delete; protected: - virtual bool ReadyForSchedule( sal_uInt64 nTimeNow ) const override; - virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTimeNow ) const override; + virtual sal_uInt64 UpdateMinPeriod( + sal_uInt64 nMinPeriod, sal_uInt64 nTimeNow ) const override; Idle( bool bAuto, const sal_Char *pDebugName = nullptr ); diff --git a/include/vcl/scheduler.hxx b/include/vcl/scheduler.hxx index 669a402f73d6..ff5885edb36f 100644 --- a/include/vcl/scheduler.hxx +++ b/include/vcl/scheduler.hxx @@ -35,9 +35,6 @@ class VCL_DLLPUBLIC Scheduler final static inline bool HasPendingTasks( const ImplSchedulerContext &rSchedCtx, const sal_uInt64 nTime ); - static inline void UpdateMinPeriod( ImplSchedulerData *pSchedulerData, - sal_uInt64 nTime, sal_uInt64 &nMinPeriod ); - static inline void UpdateSystemTimer( ImplSchedulerContext &rSchedCtx, sal_uInt64 nMinPeriod, bool bForce, sal_uInt64 nTime ); diff --git a/include/vcl/task.hxx b/include/vcl/task.hxx index 75812c4e8622..573ee5db92d1 100644 --- a/include/vcl/task.hxx +++ b/include/vcl/task.hxx @@ -54,11 +54,18 @@ protected: const ImplSchedulerData* GetSchedulerData() const; virtual void SetDeletionFlags(); - /// Is this item ready to be dispatched at nTimeNow - virtual bool ReadyForSchedule( sal_uInt64 nTimeNow ) const = 0; + /** - * Adjust nMinPeriod downwards if we want to be notified before - * then, nTimeNow is the current time. + * How long (in MS) until the Task is ready to be dispatched? + * + * Simply return Scheduler::ImmediateTimeoutMs if you're ready, like an + * Idle. If you have to return Scheduler::InfiniteTimeoutMs, you probably + * need an other mechanism to wake up the Scheduler or rely on other + * Tasks to be scheduled, or simply use a polling Timer. + * + * @param nMinPeriod the currently expected sleep time + * @param nTimeNow the current time + * @return the sleep time of the Task to become ready */ virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTimeNow ) const = 0; diff --git a/include/vcl/timer.hxx b/include/vcl/timer.hxx index 5be766cb6aa7..d26004cc5312 100644 --- a/include/vcl/timer.hxx +++ b/include/vcl/timer.hxx @@ -31,8 +31,8 @@ class VCL_DLLPUBLIC Timer : public Task protected: virtual void SetDeletionFlags() override; - virtual bool ReadyForSchedule( sal_uInt64 nTimeNow ) const override; - virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTimeNow ) const override; + virtual sal_uInt64 UpdateMinPeriod( + sal_uInt64 nMinPeriod, sal_uInt64 nTimeNow ) const override; Timer( bool bAuto, const sal_Char *pDebugName = nullptr ); diff --git a/vcl/source/app/idle.cxx b/vcl/source/app/idle.cxx index 4cbd3f8c0ed6..78c114801868 100644 --- a/vcl/source/app/idle.cxx +++ b/vcl/source/app/idle.cxx @@ -55,11 +55,6 @@ void Idle::Start() Task::StartTimer(nPeriod); } -bool Idle::ReadyForSchedule( sal_uInt64 /* nTimeNow */ ) const -{ - return true; -} - sal_uInt64 Idle::UpdateMinPeriod( sal_uInt64 /* nMinPeriod */, sal_uInt64 /* nTimeNow */ ) const { return Scheduler::ImmediateTimeoutMs; diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx index b91ac191e564..25e43baf9b44 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -171,19 +171,6 @@ bool Scheduler::GetDeterministicMode() return g_bDeterministicMode; } -inline void Scheduler::UpdateMinPeriod( ImplSchedulerData * const pSchedulerData, - const sal_uInt64 nTime, sal_uInt64 &nMinPeriod ) -{ - if ( nMinPeriod > ImmediateTimeoutMs ) - { - sal_uInt64 nCurPeriod = nMinPeriod; - nMinPeriod = pSchedulerData->mpTask->UpdateMinPeriod( nCurPeriod, nTime ); - assert( nMinPeriod <= nCurPeriod ); - if ( nCurPeriod < nMinPeriod ) - nMinPeriod = nCurPeriod; - } -} - inline void Scheduler::UpdateSystemTimer( ImplSchedulerContext &rSchedCtx, const sal_uInt64 nMinPeriod, const bool bForce, const sal_uInt64 nTime ) @@ -253,6 +240,8 @@ bool Scheduler::ProcessTaskScheduling() ImplSchedulerData *pMostUrgent = nullptr; ImplSchedulerData *pPrevMostUrgent = nullptr; sal_uInt64 nMinPeriod = InfiniteTimeoutMs; + sal_uInt64 nMostUrgentPeriod = InfiniteTimeoutMs; + sal_uInt64 nReadyPeriod = InfiniteTimeoutMs; DBG_TESTSOLARMUTEX(); @@ -297,16 +286,18 @@ bool Scheduler::ProcessTaskScheduling() goto next_entry; // skip ready tasks with lower priority than the most urgent (numerical lower is higher) - if ( pSchedulerData->mpTask->ReadyForSchedule( nTime ) && + nReadyPeriod = pSchedulerData->mpTask->UpdateMinPeriod( nMinPeriod, nTime ); + if ( ImmediateTimeoutMs == nReadyPeriod && (!pMostUrgent || (pSchedulerData->mpTask->GetPriority() < pMostUrgent->mpTask->GetPriority())) ) { - if ( pMostUrgent ) - UpdateMinPeriod( pMostUrgent, nTime, nMinPeriod ); + if ( pMostUrgent && nMinPeriod > nMostUrgentPeriod ) + nMinPeriod = nMostUrgentPeriod; pPrevMostUrgent = pPrevSchedulerData; pMostUrgent = pSchedulerData; + nMostUrgentPeriod = nReadyPeriod; } - else - UpdateMinPeriod( pSchedulerData, nTime, nMinPeriod ); + else if ( nMinPeriod > nReadyPeriod ) + nMinPeriod = nReadyPeriod; next_entry: pPrevSchedulerData = pSchedulerData; @@ -357,7 +348,9 @@ next_entry: if ( pMostUrgent->mpTask && pMostUrgent->mpTask->IsActive() ) { pMostUrgent->mnUpdateTime = nTime; - UpdateMinPeriod( pMostUrgent, nTime, nMinPeriod ); + nReadyPeriod = pMostUrgent->mpTask->UpdateMinPeriod( nMinPeriod, nTime ); + if ( nMinPeriod > nReadyPeriod ) + nMinPeriod = nReadyPeriod; UpdateSystemTimer( rSchedCtx, nMinPeriod, false, nTime ); } } diff --git a/vcl/source/app/timer.cxx b/vcl/source/app/timer.cxx index 18796806a318..6cba9e2f2b2f 100644 --- a/vcl/source/app/timer.cxx +++ b/vcl/source/app/timer.cxx @@ -30,21 +30,11 @@ void Timer::SetDeletionFlags() Task::SetDeletionFlags(); } -bool Timer::ReadyForSchedule( sal_uInt64 nTimeNow ) const -{ - return (GetSchedulerData()->mnUpdateTime + mnTimeout) <= nTimeNow; -} - -sal_uInt64 Timer::UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTimeNow ) const +sal_uInt64 Timer::UpdateMinPeriod( sal_uInt64, sal_uInt64 nTimeNow ) const { sal_uInt64 nWakeupTime = GetSchedulerData()->mnUpdateTime + mnTimeout; - if( nWakeupTime <= nTimeNow ) - return Scheduler::ImmediateTimeoutMs; - else - { - sal_uInt64 nSleepTime = nWakeupTime - nTimeNow; - return ( nSleepTime < nMinPeriod ) ? nSleepTime : nMinPeriod; - } + return ( nWakeupTime <= nTimeNow ) + ? Scheduler::ImmediateTimeoutMs : nWakeupTime - nTimeNow; } Timer::Timer( bool bAuto, const sal_Char *pDebugName ) commit f948f55667e8411624e210bbe908be3b109f8a80 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Sat Jan 28 00:54:33 2017 +0100 Remove duplicated delete information Task::mbActive already stores the inverse information of ImplSchedulerData::mbDelete, so we can drop the latter one. Change-Id: I57f8c23ca1eebdeed780a644c83fcbeb9b92cd66 diff --git a/vcl/inc/schedulerimpl.hxx b/vcl/inc/schedulerimpl.hxx index f51d56870d3a..9706b8a875b6 100644 --- a/vcl/inc/schedulerimpl.hxx +++ b/vcl/inc/schedulerimpl.hxx @@ -30,7 +30,6 @@ struct ImplSchedulerData final { ImplSchedulerData* mpNext; ///< Pointer to the next element in list Task* mpTask; ///< Pointer to VCL Task instance - bool mbDelete; ///< Destroy this task? bool mbInScheduler; ///< Task currently processed? sal_uInt64 mnUpdateTime; ///< Last Update Time diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx index e1042fffd9fe..b91ac191e564 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -76,8 +76,7 @@ template< typename charT, typename traits > inline std::basic_ostream<charT, traits> & operator <<( std::basic_ostream<charT, traits> & stream, const ImplSchedulerData& data ) { - stream << " i: " << data.mbInScheduler - << " d: " << data.mbDelete; + stream << " i: " << data.mbInScheduler; return stream; } @@ -273,7 +272,8 @@ bool Scheduler::ProcessTaskScheduling() << pSchedulerData << " " << *pSchedulerData << " (to be deleted)" ); // Should the Task be released from scheduling or stacked? - if ( pSchedulerData->mbDelete || !pSchedulerData->mpTask || pSchedulerData->mbInScheduler ) + if ( !pSchedulerData->mpTask || !pSchedulerData->mpTask->IsActive() + || pSchedulerData->mbInScheduler ) { ImplSchedulerData * const pSchedulerDataNext = DropSchedulerData( rSchedCtx, pPrevSchedulerData, pSchedulerData ); @@ -354,7 +354,7 @@ next_entry: AppendSchedulerData( rSchedCtx, pMostUrgent ); } - if ( pMostUrgent->mpTask && !pMostUrgent->mbDelete ) + if ( pMostUrgent->mpTask && pMostUrgent->mpTask->IsActive() ) { pMostUrgent->mnUpdateTime = nTime; UpdateMinPeriod( pMostUrgent, nTime, nMinPeriod ); @@ -378,7 +378,6 @@ void Task::StartTimer( sal_uInt64 nMS ) void Task::SetDeletionFlags() { - mpImpl->mpSchedulerData->mbDelete = true; mpImpl->mbActive = false; } @@ -432,7 +431,6 @@ void Task::Start() SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " " << mpImpl->mpSchedulerData << " restarted " << *this ); - mpImpl->mpSchedulerData->mbDelete = false; mpImpl->mpSchedulerData->mnUpdateTime = tools::Time::GetSystemTicks(); } @@ -441,8 +439,6 @@ void Task::Stop() SAL_INFO_IF( mpImpl->mbActive, "vcl.schedule", tools::Time::GetSystemTicks() << " " << mpImpl->mpSchedulerData << " stopped " << *this ); mpImpl->mbActive = false; - if ( mpImpl->mpSchedulerData ) - mpImpl->mpSchedulerData->mbDelete = true; } Task& Task::operator=( const Task& rTask ) @@ -479,10 +475,7 @@ Task::Task( const Task& rTask ) Task::~Task() { if ( mpImpl->mpSchedulerData ) - { - mpImpl->mpSchedulerData->mbDelete = true; mpImpl->mpSchedulerData->mpTask = nullptr; - } } TaskImpl::TaskImpl( const sal_Char *pDebugName ) commit 9a6ad1ebd03b00f3308b9fd45220e1d0021a91de Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Fri Jan 27 23:40:11 2017 +0100 Run LO scheduler only via system timer Change-Id: I5283f18aebcd6797ad35771ae8fc4a0f425ff924 diff --git a/include/vcl/scheduler.hxx b/include/vcl/scheduler.hxx index 5c5617cd0c8b..669a402f73d6 100644 --- a/include/vcl/scheduler.hxx +++ b/include/vcl/scheduler.hxx @@ -52,8 +52,6 @@ public: /// Process one pending Timer with highhest priority static void CallbackTaskScheduling(); - /// Are there any pending tasks to process? - static bool HasPendingTasks(); /// Process one pending task ahead of time with highest priority. static bool ProcessTaskScheduling(); /// Process all events until we are idle diff --git a/vcl/inc/svdata.hxx b/vcl/inc/svdata.hxx index 3197b5b2e855..21468f7fb56e 100644 --- a/vcl/inc/svdata.hxx +++ b/vcl/inc/svdata.hxx @@ -319,7 +319,6 @@ struct ImplSchedulerContext SalTimer* mpSalTimer = nullptr; ///< interface to sal event loop / system timer sal_uInt64 mnTimerStart = 0; ///< start time of the timer sal_uInt64 mnTimerPeriod = SAL_MAX_UINT64; ///< current timer period - bool mbNeedsReschedule = false; ///< we need to reschedule }; struct ImplSVData diff --git a/vcl/source/app/idle.cxx b/vcl/source/app/idle.cxx index 8038005a7d4f..4cbd3f8c0ed6 100644 --- a/vcl/source/app/idle.cxx +++ b/vcl/source/app/idle.cxx @@ -57,8 +57,6 @@ void Idle::Start() bool Idle::ReadyForSchedule( sal_uInt64 /* nTimeNow */ ) const { - ImplSVData *pSVData = ImplGetSVData(); - pSVData->maSchedCtx.mbNeedsReschedule = true; return true; } diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx index 4cbc94e098b6..e1042fffd9fe 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -172,13 +172,6 @@ bool Scheduler::GetDeterministicMode() return g_bDeterministicMode; } -bool Scheduler::HasPendingTasks() -{ - const ImplSchedulerContext &rSchedCtx = ImplGetSVData()->maSchedCtx; - return ( rSchedCtx.mbNeedsReschedule || ((rSchedCtx.mnTimerPeriod != InfiniteTimeoutMs) - && (tools::Time::GetSystemTicks() >= rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod )) ); -} - inline void Scheduler::UpdateMinPeriod( ImplSchedulerData * const pSchedulerData, const sal_uInt64 nTime, sal_uInt64 &nMinPeriod ) { @@ -246,7 +239,6 @@ bool Scheduler::ProcessTaskScheduling() sal_uInt64 nTime = tools::Time::GetSystemTicks(); if ( pSVData->mbDeInit || InfiniteTimeoutMs == rSchedCtx.mnTimerPeriod ) return false; - rSchedCtx.mbNeedsReschedule = false; if ( nTime < rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod ) { @@ -442,7 +434,6 @@ void Task::Start() mpImpl->mpSchedulerData->mbDelete = false; mpImpl->mpSchedulerData->mnUpdateTime = tools::Time::GetSystemTicks(); - rSchedCtx.mbNeedsReschedule = true; } void Task::Stop() diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx index 982d9118d764..6321b5c28753 100644 --- a/vcl/source/app/svapp.cxx +++ b/vcl/source/app/svapp.cxx @@ -471,10 +471,6 @@ inline bool ImplYield(bool i_bWait, bool i_bAllEvents, sal_uLong const nReleased SAL_INFO("vcl.schedule", "Enter ImplYield: " << (i_bWait ? "wait" : "no wait") << ": " << (i_bAllEvents ? "all events" : "one event") << ": " << nReleased); - // we handle pending task outside the system event loop, so don't wait - if (i_bWait && Scheduler::HasPendingTasks()) - i_bWait = false; - // 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) // then the only remaining use of mnDispatchLevel is in OSX specific code @@ -488,24 +484,16 @@ inline bool ImplYield(bool i_bWait, bool i_bAllEvents, sal_uLong const nReleased i_bWait && !pSVData->maAppData.mbAppQuit, i_bAllEvents, nReleased); - SAL_INFO("vcl.schedule", "DoYield returns: " << bProcessedEvent ); - pSVData->maAppData.mnDispatchLevel--; DBG_TESTSOLARMUTEX(); // must be locked on return from Yield - if (nReleased == 0) // tdf#99383 don't run stuff from ReAcquireSolarMutex - { - // Process all Tasks - bProcessedEvent = Scheduler::ProcessTaskScheduling() || bProcessedEvent; - } - // flush lazy deleted objects if( pSVData->maAppData.mnDispatchLevel == 0 ) vcl::LazyDelete::flush(); SAL_INFO("vcl.schedule", "Leave ImplYield with return " << bProcessedEvent ); - return bProcessedEvent || Scheduler::HasPendingTasks(); + return bProcessedEvent; } bool Application::Reschedule( bool i_bAllEvents ) commit 7ca105450cad7c9dd5825ee0cea8f2ed3d1e569e Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Mar 21 13:32:47 2017 +0100 OSX fix empty message queue handling For some (unknown) reason [NSApp postEvent: ... atStart: NO] doesn't append the event, if the message queue is empty (AKA [NSApp nextEventMatchingMask .. ] returns nil). Due to nextEventMatchingMask usage, these postEvents have to run in the main thread. Using performSelectorOnMainThread deadlocks, since the calling thread may have locked the Yield mutex, so we simply defer the call using an NSEvent, like the Windows backend. So we have to peek at the queue and if it's empty simply prepend the event using [.. atStart: YES]. In the end this make the vcl_timer unit test pass on OSX. Change-Id: Ib41186425b2f76faa0e9f116f47fdcd60d878099 diff --git a/vcl/Module_vcl.mk b/vcl/Module_vcl.mk index a3c78c07b8e8..80e4b56f7d85 100644 --- a/vcl/Module_vcl.mk +++ b/vcl/Module_vcl.mk @@ -173,6 +173,12 @@ $(eval $(call gb_Module_add_check_targets,vcl,\ )) endif +ifeq ($(OS),MACOSX) +$(eval $(call gb_Module_add_check_targets,vcl,\ + CppunitTest_vcl_timer \ +)) +endif + # screenshots $(eval $(call gb_Module_add_screenshot_targets,vcl,\ CppunitTest_vcl_dialogs_test \ diff --git a/vcl/inc/osx/saltimer.h b/vcl/inc/osx/saltimer.h index f9a6acb7a02f..86964115d648 100644 --- a/vcl/inc/osx/saltimer.h +++ b/vcl/inc/osx/saltimer.h @@ -26,10 +26,24 @@ #include "saltimer.hxx" -class AquaSalTimer : public SalTimer +/** + * if NO == bAtStart, then it has to be run in the main thread, + * e.g. via performSelectorOnMainThread! + **/ +void ImplNSAppPostEvent( short nEventId, BOOL bAtStart, int nUserData = 0 ); + +class ReleasePoolHolder { - public: + NSAutoreleasePool* mpPool; + +public: + ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc] init] ) {} + ~ReleasePoolHolder() { [mpPool release]; } +}; +class AquaSalTimer : public SalTimer +{ +public: AquaSalTimer(); virtual ~AquaSalTimer() override; diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index 49e4dbdb084d..c097a57ba125 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -370,23 +370,7 @@ void AquaSalInstance::wakeupYield() { // wakeup :Yield if( mbWaitingYield ) - { - SalData::ensureThreadAutoreleasePool(); -SAL_WNODEPRECATED_DECLARATIONS_PUSH - // 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12 - NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined - location: NSZeroPoint - modifierFlags: 0 - timestamp: 0 - windowNumber: 0 - context: nil - subtype: AquaSalInstance::YieldWakeupEvent - data1: 0 - data2: 0 ]; -SAL_WNODEPRECATED_DECLARATIONS_POP - if( pEvent ) - [NSApp postEvent: pEvent atStart: NO]; - } + ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, YES ); } void AquaSalInstance::PostUserEvent( AquaSalFrame* pFrame, SalEvent nType, void* pData ) @@ -556,14 +540,6 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) }; } -class ReleasePoolHolder -{ - NSAutoreleasePool* mpPool; - public: - ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc] init] ) {} - ~ReleasePoolHolder() { [mpPool release]; } -}; - bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased) { (void) nReleased; @@ -629,9 +605,11 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLon SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12 - pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: nil + pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask SAL_WNODEPRECATED_DECLARATIONS_POP - inMode: NSDefaultRunLoopMode dequeue: YES]; + untilDate: nil + inMode: NSDefaultRunLoopMode + dequeue: YES]; if( pEvent ) { [NSApp sendEvent: pEvent]; @@ -650,9 +628,11 @@ SAL_WNODEPRECATED_DECLARATIONS_POP NSDate* pDt = AquaSalTimer::pRunningTimer ? [AquaSalTimer::pRunningTimer fireDate] : [NSDate distantFuture]; SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12 - pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: pDt + pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask SAL_WNODEPRECATED_DECLARATIONS_POP - inMode: NSDefaultRunLoopMode dequeue: YES]; + untilDate: pDt + inMode: NSDefaultRunLoopMode + dequeue: YES]; if( pEvent ) [NSApp sendEvent: pEvent]; [NSApp updateWindows]; diff --git a/vcl/osx/salnstimer.mm b/vcl/osx/salnstimer.mm index 9c3264295d60..c9867cf7a79e 100644 --- a/vcl/osx/salnstimer.mm +++ b/vcl/osx/salnstimer.mm @@ -26,24 +26,13 @@ #include "svdata.hxx" @implementation TimerCallbackCaller + -(void)timerElapsed:(NSTimer*)pTimer { (void)pTimer; -SAL_WNODEPRECATED_DECLARATIONS_PUSH -// 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12 - NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined -SAL_WNODEPRECATED_DECLARATIONS_POP - location: NSZeroPoint - modifierFlags: 0 - timestamp: [NSDate timeIntervalSinceReferenceDate] - windowNumber: 0 - context: nil - subtype: AquaSalInstance::DispatchTimerEvent - data1: 0 - data2: 0 ]; - assert( pEvent ); - [NSApp postEvent: pEvent atStart: YES]; + ImplNSAppPostEvent( AquaSalInstance::DispatchTimerEvent, YES ); } + @end /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/saltimer.cxx b/vcl/osx/saltimer.cxx index 415ad1284af8..3cf74529a301 100644 --- a/vcl/osx/saltimer.cxx +++ b/vcl/osx/saltimer.cxx @@ -31,22 +31,45 @@ NSTimer* AquaSalTimer::pRunningTimer = nil; static void ImplSalStopTimer(); -static inline void ImplPostEvent( short nEventId, bool bAtStart, int nUserData = 0 ) +void ImplNSAppPostEvent( short nEventId, BOOL bAtStart, int nUserData ) { - SalData::ensureThreadAutoreleasePool(); + ReleasePoolHolder aPool; SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12 NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined SAL_WNODEPRECATED_DECLARATIONS_POP location: NSZeroPoint modifierFlags: 0 - timestamp: [NSDate timeIntervalSinceReferenceDate] + timestamp: 0 windowNumber: 0 context: nil subtype: nEventId data1: nUserData - data2: 0 ]; + data2: 0]; assert( pEvent ); + if ( nil == pEvent ) + return; + if ( NO == bAtStart ) + { + // nextEventMatchingMask has to run in the main thread! + assert([NSThread isMainThread]); + + // Posting an event to the end of an empty queue fails, + // so we peek the queue and post to the start, if empty. + // Some Qt bugs even indicate nextEvent without dequeue + // sometimes blocks, so we dequeue and re-add the event. +SAL_WNODEPRECATED_DECLARATIONS_PUSH +// 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12 + NSEvent* pPeekEvent = [NSApp nextEventMatchingMask: NSAnyEventMask +SAL_WNODEPRECATED_DECLARATIONS_POP + untilDate: nil + inMode: NSDefaultRunLoopMode + dequeue: YES]; + if ( nil == pPeekEvent ) + bAtStart = YES; + else + [NSApp postEvent: pPeekEvent atStart: YES]; + } [NSApp postEvent: pEvent atStart: bAtStart]; } @@ -54,14 +77,18 @@ static void ImplSalStartTimer( sal_uLong nMS ) { SalData* pSalData = GetSalData(); - if ( 0 == nMS ) + if( !pSalData->mpFirstInstance->IsMainThread() ) { - ImplSalStopTimer(); - ImplPostEvent( AquaSalInstance::DispatchTimerEvent, false ); + ImplNSAppPostEvent( AquaSalInstance::AppStartTimerEvent, YES, nMS ); return; } - if( pSalData->mpFirstInstance->IsMainThread() ) + if ( 0 == nMS ) + { + ImplSalStopTimer(); + ImplNSAppPostEvent( AquaSalInstance::DispatchTimerEvent, NO ); + } + else { NSTimeInterval aTI = double(nMS) / 1000.0; if( AquaSalTimer::pRunningTimer != nil ) @@ -89,8 +116,6 @@ static void ImplSalStartTimer( sal_uLong nMS ) [[NSRunLoop currentRunLoop] addTimer: AquaSalTimer::pRunningTimer forMode: NSEventTrackingRunLoopMode]; } } - else - ImplPostEvent( AquaSalInstance::AppStartTimerEvent, true, nMS ); } static void ImplSalStopTimer() commit a1e1223d5bf09f9f575e9783cd15be5b2921e53d Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Fri Feb 24 18:27:49 2017 +0100 OSX change to run LO via a single shot timer As all other backends, this runs the LO main loop just via the OSX main loop. Change-Id: Ie7562444951e16ff58edcaf6409f32809314c2fa diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h index 146391b073c2..8468dbd8dd59 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -153,6 +153,7 @@ public: static const short AppEndLoopEvent = 1; static const short AppStartTimerEvent = 10; static const short YieldWakeupEvent = 20; + static const short DispatchTimerEvent = 30; static NSMenu* GetDynamicDockMenu(); }; diff --git a/vcl/inc/osx/saltimer.h b/vcl/inc/osx/saltimer.h index 94b58f82fd8b..f9a6acb7a02f 100644 --- a/vcl/inc/osx/saltimer.h +++ b/vcl/inc/osx/saltimer.h @@ -37,6 +37,7 @@ class AquaSalTimer : public SalTimer void Stop() override; static void handleStartTimerEvent( NSEvent* pEvent ); + static void handleDispatchTimerEvent(); static NSTimer* pRunningTimer; static bool bDispatchTimer; diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index f33f1e99435a..49e4dbdb084d 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -475,8 +475,11 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) [pDockMenu release]; pDockMenu = nil; } + break; } - break; + case DispatchTimerEvent: + AquaSalTimer::handleDispatchTimerEvent(); + break; #if !HAVE_FEATURE_MACOSX_SANDBOX case AppleRemoteControlEvent: // Defined in <apple_remote/RemoteMainController.h> { @@ -565,6 +568,7 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLon { (void) nReleased; assert(nReleased == 0); // not implemented + bool bHadEvent = false; // ensure that the per thread autorelease pool is top level and // will therefore not be destroyed by cocoa implicitly @@ -589,6 +593,7 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLon { aEvent = maUserEvents.front(); maUserEvents.pop_front(); + bHadEvent = true; } else bDispatchUser = false; @@ -600,15 +605,15 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLon { aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData ); maWaitingYieldCond.set(); - // return if only one event is asked for - if( ! bHandleAllCurrentEvents ) - return true; } + + // return if only one event is asked for + if( !bHandleAllCurrentEvents && bDispatchUser ) + return true; } // handle cocoa event queue // cocoa events may be only handled in the thread the NSApp was created - bool bHadEvent = false; if( IsMainThread() && mnActivePrintJobs == 0 ) { // we need to be woken up by a cocoa-event @@ -653,18 +658,6 @@ SAL_WNODEPRECATED_DECLARATIONS_POP [NSApp updateWindows]; AcquireYieldMutex( nCount ); - - // #i86581# - // FIXME: sometimes the NSTimer will never fire. Firing it by hand then - // fixes the problem even seems to set the correct next firing date - // Why oh why? - if( ! pEvent && AquaSalTimer::pRunningTimer ) - { - // this cause crashes on MacOSX 10.4 - // [AquaSalTimer::pRunningTimer fire]; - if (ImplGetSVData()->maSchedCtx.mpSalTimer != nullptr) - ImplGetSVData()->maSchedCtx.mpSalTimer->CallCallback(); - } } mbWaitingYield = bOldWaitingYield; diff --git a/vcl/osx/salnstimer.mm b/vcl/osx/salnstimer.mm index 00f67e52cd26..9c3264295d60 100644 --- a/vcl/osx/salnstimer.mm +++ b/vcl/osx/salnstimer.mm @@ -29,19 +29,20 @@ -(void)timerElapsed:(NSTimer*)pTimer { (void)pTimer; - if( AquaSalTimer::bDispatchTimer ) - { - SolarMutexGuard aGuard; - ImplSVData* pSVData = ImplGetSVData(); - if( pSVData->maSchedCtx.mpSalTimer ) - { - pSVData->maSchedCtx.mpSalTimer->CallCallback(); - - // NSTimer does not end nextEventMatchingMask of NSApplication - // so we need to wakeup a waiting Yield to inform it something happened - GetSalData()->mpFirstInstance->wakeupYield(); - } - } +SAL_WNODEPRECATED_DECLARATIONS_PUSH +// 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12 + NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined +SAL_WNODEPRECATED_DECLARATIONS_POP + location: NSZeroPoint + modifierFlags: 0 + timestamp: [NSDate timeIntervalSinceReferenceDate] + windowNumber: 0 + context: nil + subtype: AquaSalInstance::DispatchTimerEvent + data1: 0 + data2: 0 ]; + assert( pEvent ); + [NSApp postEvent: pEvent atStart: YES]; } @end diff --git a/vcl/osx/saltimer.cxx b/vcl/osx/saltimer.cxx index 0221c81a17ae..415ad1284af8 100644 --- a/vcl/osx/saltimer.cxx +++ b/vcl/osx/saltimer.cxx @@ -28,15 +28,42 @@ #include "osx/salinst.h" NSTimer* AquaSalTimer::pRunningTimer = nil; -bool AquaSalTimer::bDispatchTimer = false; -void ImplSalStartTimer( sal_uLong nMS ) +static void ImplSalStopTimer(); + +static inline void ImplPostEvent( short nEventId, bool bAtStart, int nUserData = 0 ) +{ + SalData::ensureThreadAutoreleasePool(); +SAL_WNODEPRECATED_DECLARATIONS_PUSH +// 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12 + NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined +SAL_WNODEPRECATED_DECLARATIONS_POP + location: NSZeroPoint + modifierFlags: 0 + timestamp: [NSDate timeIntervalSinceReferenceDate] + windowNumber: 0 + context: nil + subtype: nEventId + data1: nUserData + data2: 0 ]; + assert( pEvent ); + [NSApp postEvent: pEvent atStart: bAtStart]; +} + +static void ImplSalStartTimer( sal_uLong nMS ) { SalData* pSalData = GetSalData(); - if( !pSalData->mpFirstInstance->IsMainThread() ) + + if ( 0 == nMS ) { - AquaSalTimer::bDispatchTimer = true; - NSTimeInterval aTI = double(nMS)/1000.0; + ImplSalStopTimer(); + ImplPostEvent( AquaSalInstance::DispatchTimerEvent, false ); + return; + } + + if( pSalData->mpFirstInstance->IsMainThread() ) + { + NSTimeInterval aTI = double(nMS) / 1000.0; if( AquaSalTimer::pRunningTimer != nil ) { if (rtl::math::approxEqual( @@ -46,18 +73,16 @@ void ImplSalStartTimer( sal_uLong nMS ) [AquaSalTimer::pRunningTimer setFireDate: [NSDate dateWithTimeIntervalSinceNow: aTI]]; } else - { - [AquaSalTimer::pRunningTimer invalidate]; - AquaSalTimer::pRunningTimer = nil; - } + ImplSalStopTimer(); } if( AquaSalTimer::pRunningTimer == nil ) { - AquaSalTimer::pRunningTimer = [NSTimer scheduledTimerWithTimeInterval: aTI - target: [[[TimerCallbackCaller alloc] init] autorelease] - selector: @selector(timerElapsed:) - userInfo: nil - repeats: YES]; + AquaSalTimer::pRunningTimer = [[NSTimer scheduledTimerWithTimeInterval: aTI + target: [[[TimerCallbackCaller alloc] init] autorelease] + selector: @selector(timerElapsed:) + userInfo: nil + repeats: NO + ] retain]; /* #i84055# add timer to tracking run loop mode, so they also elapse while e.g. life resize */ @@ -65,29 +90,25 @@ void ImplSalStartTimer( sal_uLong nMS ) } } else + ImplPostEvent( AquaSalInstance::AppStartTimerEvent, true, nMS ); +} + +static void ImplSalStopTimer() +{ + if( AquaSalTimer::pRunningTimer != nil ) { - SalData::ensureThreadAutoreleasePool(); - // post an event so we can get into the main thread -SAL_WNODEPRECATED_DECLARATIONS_PUSH - // 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12 - NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined - location: NSZeroPoint - modifierFlags: 0 - timestamp: [NSDate timeIntervalSinceReferenceDate] - windowNumber: 0 - context: nil - subtype: AquaSalInstance::AppStartTimerEvent - data1: (int)nMS - data2: 0 ]; -SAL_WNODEPRECATED_DECLARATIONS_POP - if( pEvent ) - [NSApp postEvent: pEvent atStart: YES]; + [AquaSalTimer::pRunningTimer invalidate]; + [AquaSalTimer::pRunningTimer release]; + AquaSalTimer::pRunningTimer = nil; } } -void ImplSalStopTimer() +void AquaSalTimer::handleDispatchTimerEvent() { - AquaSalTimer::bDispatchTimer = false; + ImplSVData* pSVData = ImplGetSVData(); + SolarMutexGuard aGuard; + if( pSVData->maSchedCtx.mpSalTimer ) + pSVData->maSchedCtx.mpSalTimer->CallCallback(); } void AquaSalTimer::handleStartTimerEvent( NSEvent* pEvent ) @@ -98,14 +119,10 @@ void AquaSalTimer::handleStartTimerEvent( NSEvent* pEvent ) NSTimeInterval posted = [pEvent timestamp] + NSTimeInterval([pEvent data1])/1000.0; NSTimeInterval current = [NSDate timeIntervalSinceReferenceDate]; if( (posted - current) <= 0.0 ) - { - SolarMutexGuard aGuard; - if( pSVData->maSchedCtx.mpSalTimer ) - pSVData->maSchedCtx.mpSalTimer->CallCallback(); - } - ImplSalStartTimer( sal_uLong( [pEvent data1] ) ); + handleDispatchTimerEvent(); + else + ImplSalStartTimer( sal_uLong( [pEvent data1] ) ); } - } AquaSalTimer::AquaSalTimer( ) diff --git a/vcl/osx/vclnsapp.mm b/vcl/osx/vclnsapp.mm index 4c38466961b0..2add55ffde85 100644 --- a/vcl/osx/vclnsapp.mm +++ b/vcl/osx/vclnsapp.mm @@ -73,8 +73,8 @@ SAL_WNODEPRECATED_DECLARATIONS_PUSH data1: 0 data2: 0 ]; SAL_WNODEPRECATED_DECLARATIONS_POP - if( pEvent ) - [NSApp postEvent: pEvent atStart: NO]; + assert( pEvent ); + [NSApp postEvent: pEvent atStart: NO]; } -(void)sendEvent:(NSEvent*)pEvent commit 0a4b4b02185d3baeea55568cfb8c6ae78ea9f818 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Sun Oct 30 02:02:10 2016 +0100 WIN just wait for the Yield mutex in the timerout Don't re-schedule a timeout, simply wait in the timer callback. Change-Id: Ib46eb6dbf57f29c85ffdbd6492922020f7785d30 diff --git a/vcl/win/app/saltimer.cxx b/vcl/win/app/saltimer.cxx index af379700c5bd..2ddb34b8f0b6 100644 --- a/vcl/win/app/saltimer.cxx +++ b/vcl/win/app/saltimer.cxx @@ -154,16 +154,9 @@ void EmitTimerCallback() if ( ! pSVData->maSchedCtx.mpSalTimer ) return; - // Try to acquire the mutex. If we don't get the mutex then we - // try this a short time later again. - if (ImplSalYieldMutexTryToAcquire()) - { - pSVData->maSchedCtx.mpSalTimer->CallCallback(); - - ImplSalYieldMutexRelease(); - } - else - ImplSalStartTimer( 10 ); + ImplSalYieldMutexAcquireWithWait(); + pSVData->maSchedCtx.mpSalTimer->CallCallback(); + ImplSalYieldMutexRelease(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 1c88b11ab6fbf35d0fee58e02557374c6c60156d Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Sun Oct 30 00:14:18 2016 +0000 WIN simplify system timer / LO event handling This removes a level of indirection for the timer callback handling. It also ensures we just have a single timeout message queued. Also drops the 16bit MAX duration limit, as CreateTimerQueueTimer uses a DWORD for the DueTime parameter, which is always UINT32. CreateTimerQueueTimer already sets the period to 0, which makes it a one-shot timer, but there is also the WT_EXECUTEONLYONCE, which enforces the Period parameter to be 0. Change-Id: I549142394334bdc098f053b42f222b23cf4fcecd diff --git a/vcl/inc/win/saldata.hxx b/vcl/inc/win/saldata.hxx index 2fb1b49d5177..03641a297e23 100644 --- a/vcl/inc/win/saldata.hxx +++ b/vcl/inc/win/saldata.hxx @@ -80,10 +80,6 @@ public: long* mpDitherDiff; // Dither mapping table BYTE* mpDitherLow; // Dither mapping table BYTE* mpDitherHigh; // Dither mapping table - sal_uLong mnTimerMS; // Current Time (in MS) of the Timer - sal_uLong mnTimerOrgMS; // Current Original Time (in MS) - DWORD mnNextTimerTime; - DWORD mnLastEventTime; HANDLE mnTimerId; ///< Windows timer id HHOOK mhSalObjMsgHook; // hook to get interesting msg for SalObject HWND mhWantLeaveMsg; // window handle, that want a MOUSELEAVE message @@ -220,9 +216,9 @@ int ImplSalWICompareAscii( const wchar_t* pStr1, const char* pStr2 ); // wParam == hWnd; lParam == 0 #define SAL_MSG_RELEASEDC (WM_USER+121) // wParam == newParentHwnd; lParam == oldHwnd; lResult == newhWnd -#define SAL_MSG_RECREATEHWND (WM_USER+122) +#define SAL_MSG_RECREATEHWND (WM_USER+122) // wParam == newParentHwnd; lParam == oldHwnd; lResult == newhWnd -#define SAL_MSG_RECREATECHILDHWND (WM_USER+123) +#define SAL_MSG_RECREATECHILDHWND (WM_USER+123) // wParam == 0; lParam == HWND; #define SAL_MSG_DESTROYHWND (WM_USER+124) @@ -232,6 +228,7 @@ int ImplSalWICompareAscii( const wchar_t* pStr1, const char* pStr2 ); #define SAL_MSG_MOUSELEAVE (WM_USER+131) // NULL-Message, should not be processed #define SAL_MSG_DUMMY (WM_USER+132) +// Used for SETFOCUS and KILLFOCUS // wParam == 0; lParam == 0 #define SAL_MSG_POSTFOCUS (WM_USER+133) // wParam == wParam; lParam == lParam @@ -258,11 +255,10 @@ int ImplSalWICompareAscii( const wchar_t* pStr1, const char* pStr2 ); #define SAL_MSG_SETINPUTCONTEXT (WM_USER+144) // wParam == nFlags; lParam == 0 #define SAL_MSG_ENDEXTTEXTINPUT (WM_USER+145) -// POSTTIMER-Message; wparam = 0, lParam == time -#define SAL_MSG_POSTTIMER (WM_USER+161) // SysChild-ToTop; wParam = 0; lParam = 0 #define SALOBJ_MSG_TOTOP (WM_USER+160) +// Used for SETFOCUS and KILLFOCUS // POSTFOCUS-Message; wParam == bFocus; lParam == 0 #define SALOBJ_MSG_POSTFOCUS (WM_USER+161) diff --git a/vcl/inc/win/salinst.h b/vcl/inc/win/salinst.h index 359bc275e463..03ba573c523b 100644 --- a/vcl/inc/win/salinst.h +++ b/vcl/inc/win/salinst.h @@ -83,8 +83,6 @@ public: SalFrame* ImplSalCreateFrame( WinSalInstance* pInst, HWND hWndParent, SalFrameStyleFlags nSalFrameStyle ); SalObject* ImplSalCreateObject( WinSalInstance* pInst, WinSalFrame* pParent ); HWND ImplSalReCreateHWND( HWND hWndParent, HWND oldhWnd, bool bAsChild ); -void ImplSalStartTimer( sal_uIntPtr nMS, bool bMutex = false ); -void ImplSalStopTimer(); #endif // INCLUDED_VCL_INC_WIN_SALINST_H diff --git a/vcl/inc/win/saltimer.h b/vcl/inc/win/saltimer.h index 996b2b5137da..084a25745b87 100644 --- a/vcl/inc/win/saltimer.h +++ b/vcl/inc/win/saltimer.h @@ -32,6 +32,9 @@ public: virtual void Stop() override; }; +void ImplSalStartTimer( sal_uIntPtr nMS ); +void ImplSalStopTimer(); + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx index 8b4c2eef950a..502d18b8f2a9 100644 --- a/vcl/win/app/salinst.cxx +++ b/vcl/win/app/salinst.cxx @@ -314,10 +314,6 @@ SalData::SalData() mpDitherDiff = nullptr; // Dither mapping table ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits