// Only if smaller timeout, to avoid skipping. // Force instant wakeup on 0ms, if the previous period was not 0ms if (bForce || nProposedTimeout < nCurTimeout || (!nMS && rSchedCtx.mnTimerPeriod))
{
SAL_INFO( "vcl.schedule", " Starting scheduler system timer (" << nMS << "ms)" );
rSchedCtx.mnTimerStart = nTime;
rSchedCtx.mnTimerPeriod = nMS;
rSchedCtx.mpSalTimer->Start( nMS );
}
}
Scheduler::IdlesLockGuard::IdlesLockGuard()
{
ImplSVData* pSVData = ImplGetSVData();
ImplSchedulerContext& rSchedCtx = pSVData->maSchedCtx;
osl_atomic_increment(&rSchedCtx.mnIdlesLockCount); if (!Application::IsMainThread())
{ // Make sure that main thread has reached the main message loop, so no idles are executing. // It is important to ensure this, because e.g. ProcessEventsToIdle could be executed in a // nested event loop, while an active processed idle in the main thread is waiting for some // condition to proceed. Only main thread returning to Application::Execute guarantees that // the flag really took effect.
pSVData->m_inExecuteCondtion.reset(); // Put an empty event to the application's queue, to make sure that it loops through the // code that sets the condition, even when there's no other events in the queue
Application::PostUserEvent({});
SolarMutexReleaser releaser;
pSVData->m_inExecuteCondtion.wait();
}
}
int Scheduler::GetMostUrgentTaskPriority()
{ // Similar to Scheduler::CallbackTaskScheduling(), figure out the most urgent priority, but // don't actually invoke any task. int nMostUrgentPriority = -1;
ImplSVData* pSVData = ImplGetSVData();
ImplSchedulerContext& rSchedCtx = pSVData->maSchedCtx; if (!rSchedCtx.mbActive || rSchedCtx.mnTimerPeriod == InfiniteTimeoutMs)
{ return nMostUrgentPriority;
}
#if !(defined EMSCRIPTEN && ENABLE_QT6 && HAVE_EMSCRIPTEN_JSPI && !HAVE_EMSCRIPTEN_PROXY_TO_PTHREAD) //TODO: While the special Emscripten Qt6 JSPI/non-PROXY_TO_PTHREAD mode doesn't lock the // SolarMutex in QtTimer::timeoutActivated, but only down below when calling pTask->Invoke(), // that looks too brittle in general, so treat that special mode specially here.
DBG_TESTSOLARMUTEX(); #endif
sal_uInt64 nTime = tools::Time::GetSystemTicks(); // Allow for decimals, so subtract in the compare (needed at least on iOS) if ( nTime < rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod -1)
{ int nSleep = rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod - nTime;
UpdateSystemTimer(rSchedCtx, nSleep, true, nTime); return;
}
for (; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
{ // Related: tdf#152703 Eliminate potential blocking during live resize // Only higher priority tasks need to be fired to redraw the window // so skip firing potentially long-running tasks, such as the Writer // idle layout timer, when a window is in live resize if ( nTaskPriority == static_cast<int>(TaskPriority::LOWEST) && ( ImplGetSVData()->mpWinData->mbIsLiveResize || ImplGetSVData()->mpWinData->mbIsWaitingForNativeEvent ) ) continue;
// always push the stack, as we don't traverse the whole list to push later
DropSchedulerData(rSchedCtx, pPrevMostUrgent, pMostUrgent, nMostUrgentPriority);
pMostUrgent->mpNext = rSchedCtx.mpSchedulerStack;
rSchedCtx.mpSchedulerStack = pMostUrgent;
rSchedCtx.mpSchedulerStackTop = pMostUrgent;
// high priority idle handlers have smaller numerical values for mePriority bool bIsLowerPriorityIdle = pMostUrgent->mePriority >= TaskPriority::HIGH_IDLE;
#ifdef MACOSX // tdf#165277 On macOS, only delay priorities lower than POST_PAINT // macOS bugs tdf#157312 and tdf#163945 were fixed by firing the // Skia flush task with TaskPriority::POST_PAINT. // The problem is that this method often executes within an // NSTimer and NSTimers are always fired while LibreOffice is in // -[NSApp nextEventMatchingMask:untilDate:inMode:dequeue:]. // Since fetching the next native event doesn't handle pending // events until *after* all of the pending NSTimers have fired, // calling SalInstance::AnyInput() will almost always return true // due to the pending events that will be handled immediately // after all of the pending NSTimers have fired. // The result is that the Skia flush task is frequently delayed // and, in cases like tdf#165277, a user's attempts to get // LibreOffice to paint the window through key and mouse events // leads to an endless delaying of the Skia flush task. // After experimenting with both Skia/Metal and Skia/Raster, // tdf#165277 requires the Skia flush task to run immediately // before the TaskPriority::POST_PAINT tasks. After that, all // TaskPriority::POST_PAINT tasks must run so the Skia flush // task now uses the TaskPriority::SKIA_FLUSH priority on macOS. // One positive side effect of this change is that live resizing // on macOS is now much smoother. Even with Skia disabled (which // does not paint using a task but does use tasks to handle live // resizing), the content resizes much more quickly when a user // rapidly changes window's size. if (bIsLowerPriorityIdle && pMostUrgent->mePriority <= TaskPriority::POST_PAINT)
bIsLowerPriorityIdle = false; #endif
// invoke the task
Unlock();
// Delay invoking tasks with idle priorities as long as there are user input or repaint events // in the OS event queue. This will often effectively compress such events and repaint only // once at the end, improving performance in cases such as repeated zooming with a complex document. bool bDelayInvoking
= bIsLowerPriorityIdle
&& (rSchedCtx.mnIdlesLockCount > 0
|| Application::AnyInput(VclInputFlags::MOUSE | VclInputFlags::KEYBOARD | VclInputFlags::PAINT));
SchedulerGuard aSchedulerGuard; if ( !rSchedCtx.mbActive ) return;
// is the task scheduled in the correct priority queue? // if not we have to get a new data object, as we don't want to traverse // the whole list to move the data to the correct list, as the task list // is just single linked. // Task priority doesn't change that often AFAIK, or we might need to // start caching ImplSchedulerData objects. if (mpSchedulerData && mpSchedulerData->mePriority != mePriority)
{
mpSchedulerData->mpTask = nullptr;
mpSchedulerData = nullptr;
}
mbActive = true;
if ( !mpSchedulerData )
{ // insert Task
ImplSchedulerData* pSchedulerData = new ImplSchedulerData;
pSchedulerData->mpTask = this;
pSchedulerData->mbInScheduler = false; // mePriority is set in AppendSchedulerData
mpSchedulerData = pSchedulerData;
void Task::SetPriority(TaskPriority ePriority)
{ // you don't actually need to call Stop() before but Start() after, but we // can't check that and don't know when Start() should be called.
SAL_WARN_IF(mpSchedulerData && mbActive, "vcl.schedule", "Stop the task before changing the priority, as it will just " "change after the task was scheduled with the old prio!");
mePriority = ePriority;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.