LibreOffice Module vcl (master)  1
scheduler.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <cassert>
23 #include <cstdlib>
24 #include <exception>
25 #include <typeinfo>
26 
27 #include <com/sun/star/uno/Exception.hpp>
28 #include <sal/log.hxx>
29 #include <sal/types.h>
30 #include <svdata.hxx>
31 #include <tools/time.hxx>
32 #include <tools/debug.hxx>
33 #include <tools/diagnose_ex.h>
34 #include <unotools/configmgr.hxx>
35 #include <vcl/TaskStopwatch.hxx>
36 #include <vcl/scheduler.hxx>
37 #include <vcl/idle.hxx>
38 #include <saltimer.hxx>
39 #include <salinst.hxx>
41 #include <schedulerimpl.hxx>
42 
43 namespace {
44 
45 template< typename charT, typename traits >
46 std::basic_ostream<charT, traits> & operator <<(
47  std::basic_ostream<charT, traits> & stream, const Task& task )
48 {
49  stream << "a: " << task.IsActive() << " p: " << static_cast<int>(task.GetPriority());
50  const char *name = task.GetDebugName();
51  if( nullptr == name )
52  return stream << " (nullptr)";
53  else
54  return stream << " " << name;
55 }
56 
64 template< typename charT, typename traits >
65 std::basic_ostream<charT, traits> & operator <<(
66  std::basic_ostream<charT, traits> & stream, const Timer& timer )
67 {
68  bool bIsIdle = (dynamic_cast<const Idle*>( &timer ) != nullptr);
69  stream << (bIsIdle ? "Idle " : "Timer")
70  << " a: " << timer.IsActive() << " p: " << static_cast<int>(timer.GetPriority());
71  const char *name = timer.GetDebugName();
72  if ( nullptr == name )
73  stream << " (nullptr)";
74  else
75  stream << " " << name;
76  if ( !bIsIdle )
77  stream << " " << timer.GetTimeout() << "ms";
78  stream << " (" << &timer << ")";
79  return stream;
80 }
81 
82 template< typename charT, typename traits >
83 std::basic_ostream<charT, traits> & operator <<(
84  std::basic_ostream<charT, traits> & stream, const Idle& idle )
85 {
86  return stream << static_cast<const Timer*>( &idle );
87 }
88 
89 template< typename charT, typename traits >
90 std::basic_ostream<charT, traits> & operator <<(
91  std::basic_ostream<charT, traits> & stream, const ImplSchedulerData& data )
92 {
93  stream << " i: " << data.mbInScheduler;
94  return stream;
95 }
96 
97 } // end anonymous namespace
98 
100 
102 {
103  ImplSVData* pSVData = ImplGetSVData();
104  assert( pSVData != nullptr );
105  ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
106 
108 
109  SchedulerGuard aSchedulerGuard;
110 
111  int nTaskPriority = 0;
112 #if OSL_DEBUG_LEVEL > 0
113  sal_uInt32 nTasks = 0;
114  for (nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
115  {
116  ImplSchedulerData* pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
117  while ( pSchedulerData )
118  {
119  ++nTasks;
120  pSchedulerData = pSchedulerData->mpNext;
121  }
122  }
123  SAL_INFO( "vcl.schedule.deinit",
124  "DeInit the scheduler - pending tasks: " << nTasks );
125 
126  // clean up all the sfx::SfxItemDisruptor_Impl Idles
127  Unlock();
129  Lock();
130 #endif
131  rSchedCtx.mbActive = false;
132 
133  assert( nullptr == rSchedCtx.mpSchedulerStack );
134 
135  if (rSchedCtx.mpSalTimer) rSchedCtx.mpSalTimer->Stop();
136  delete rSchedCtx.mpSalTimer;
137  rSchedCtx.mpSalTimer = nullptr;
138 
139 #if OSL_DEBUG_LEVEL > 0
140  sal_uInt32 nActiveTasks = 0, nIgnoredTasks = 0;
141 #endif
142  nTaskPriority = 0;
143  ImplSchedulerData* pSchedulerData = nullptr;
144 
145 next_priority:
146  pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
147  while ( pSchedulerData )
148  {
149  Task *pTask = pSchedulerData->mpTask;
150  if ( pTask )
151  {
152  if ( pTask->mbActive )
153  {
154 #if OSL_DEBUG_LEVEL > 0
155  const char *sIgnored = "";
156  ++nActiveTasks;
157  // TODO: shutdown these timers before Scheduler de-init
158  // TODO: remove Task from static object
159  if ( pTask->GetDebugName() && ( false
160  || !strcmp( pTask->GetDebugName(), "desktop::Desktop m_firstRunTimer" )
161  || !strcmp( pTask->GetDebugName(), "DrawWorkStartupTimer" )
162  || !strcmp( pTask->GetDebugName(), "editeng::ImpEditEngine aOnlineSpellTimer" )
163  || !strcmp( pTask->GetDebugName(), "ImplHandleMouseMsg SalData::mpMouseLeaveTimer" )
164  || !strcmp( pTask->GetDebugName(), "sc ScModule IdleTimer" )
165  || !strcmp( pTask->GetDebugName(), "sd::CacheConfiguration maReleaseTimer" )
166  || !strcmp( pTask->GetDebugName(), "svtools::GraphicCache maReleaseTimer" )
167  || !strcmp( pTask->GetDebugName(), "svtools::GraphicObject mpSwapOutTimer" )
168  || !strcmp( pTask->GetDebugName(), "svx OLEObjCache pTimer UnloadCheck" )
169  || !strcmp( pTask->GetDebugName(), "vcl SystemDependentDataBuffer aSystemDependentDataBuffer" )
170  ))
171  {
172  sIgnored = " (ignored)";
173  ++nIgnoredTasks;
174  }
175  const Timer *timer = dynamic_cast<Timer*>( pTask );
176  if ( timer )
177  SAL_WARN( "vcl.schedule.deinit", "DeInit task: " << *timer << sIgnored );
178  else
179  SAL_WARN( "vcl.schedule.deinit", "DeInit task: " << *pTask << sIgnored );
180 #endif
181  pTask->mbActive = false;
182  }
183  pTask->mpSchedulerData = nullptr;
184  pTask->SetStatic();
185  }
186  ImplSchedulerData* pDeleteSchedulerData = pSchedulerData;
187  pSchedulerData = pSchedulerData->mpNext;
188  delete pDeleteSchedulerData;
189  }
190 
191  ++nTaskPriority;
192  if (nTaskPriority < PRIO_COUNT)
193  goto next_priority;
194 
195 #if OSL_DEBUG_LEVEL > 0
196  SAL_INFO( "vcl.schedule.deinit", "DeInit the scheduler - finished" );
197  SAL_WARN_IF( 0 != nActiveTasks, "vcl.schedule.deinit", "DeInit active tasks: "
198  << nActiveTasks << " (ignored: " << nIgnoredTasks << ")" );
199 // assert( nIgnoredTasks == nActiveTasks );
200 #endif
201 
202  for (nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
203  {
204  rSchedCtx.mpFirstSchedulerData[nTaskPriority] = nullptr;
205  rSchedCtx.mpLastSchedulerData[nTaskPriority] = nullptr;
206  }
207  rSchedCtx.mnTimerPeriod = InfiniteTimeoutMs;
208 }
209 
211 {
212  ImplSVData* pSVData = ImplGetSVData();
213  assert( pSVData != nullptr );
214  pSVData->maSchedCtx.maMutex.lock();
215 }
216 
218 {
219  ImplSVData* pSVData = ImplGetSVData();
220  assert( pSVData != nullptr );
221  pSVData->maSchedCtx.maMutex.unlock();
222 }
223 
231 void Scheduler::ImplStartTimer(sal_uInt64 nMS, bool bForce, sal_uInt64 nTime)
232 {
233  ImplSVData* pSVData = ImplGetSVData();
234  ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
235  if ( !rSchedCtx.mbActive )
236  return;
237 
238  if (!rSchedCtx.mpSalTimer)
239  {
240  rSchedCtx.mnTimerStart = 0;
241  rSchedCtx.mnTimerPeriod = InfiniteTimeoutMs;
242  rSchedCtx.mpSalTimer = pSVData->mpDefInst->CreateSalTimer();
244  }
245 
246  assert(SAL_MAX_UINT64 - nMS >= nTime);
247 
248  sal_uInt64 nProposedTimeout = nTime + nMS;
249  sal_uInt64 nCurTimeout = ( rSchedCtx.mnTimerPeriod == InfiniteTimeoutMs )
250  ? SAL_MAX_UINT64 : rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod;
251 
252  // Only if smaller timeout, to avoid skipping.
253  // Force instant wakeup on 0ms, if the previous period was not 0ms
254  if (bForce || nProposedTimeout < nCurTimeout || (!nMS && rSchedCtx.mnTimerPeriod))
255  {
256  SAL_INFO( "vcl.schedule", " Starting scheduler system timer (" << nMS << "ms)" );
257  rSchedCtx.mnTimerStart = nTime;
258  rSchedCtx.mnTimerPeriod = nMS;
259  rSchedCtx.mpSalTimer->Start( nMS );
260  }
261 }
262 
263 static bool g_bDeterministicMode = false;
264 
265 void Scheduler::SetDeterministicMode(bool bDeterministic)
266 {
267  g_bDeterministicMode = bDeterministic;
268 }
269 
271 {
272  return g_bDeterministicMode;
273 }
274 
276  const sal_uInt64 nMinPeriod,
277  const bool bForce, const sal_uInt64 nTime )
278 {
279  if ( InfiniteTimeoutMs == nMinPeriod )
280  {
281  SAL_INFO("vcl.schedule", " Stopping system timer");
282  if ( rSchedCtx.mpSalTimer )
283  rSchedCtx.mpSalTimer->Stop();
284  rSchedCtx.mnTimerPeriod = nMinPeriod;
285  }
286  else
287  Scheduler::ImplStartTimer( nMinPeriod, bForce, nTime );
288 }
289 
291  ImplSchedulerData * const pSchedulerData)
292 {
293  assert(pSchedulerData->mpTask);
294  pSchedulerData->mePriority = pSchedulerData->mpTask->GetPriority();
295  pSchedulerData->mpNext = nullptr;
296 
297  const int nTaskPriority = static_cast<int>(pSchedulerData->mePriority);
298  if (!rSchedCtx.mpLastSchedulerData[nTaskPriority])
299  {
300  rSchedCtx.mpFirstSchedulerData[nTaskPriority] = pSchedulerData;
301  rSchedCtx.mpLastSchedulerData[nTaskPriority] = pSchedulerData;
302  }
303  else
304  {
305  rSchedCtx.mpLastSchedulerData[nTaskPriority]->mpNext = pSchedulerData;
306  rSchedCtx.mpLastSchedulerData[nTaskPriority] = pSchedulerData;
307  }
308 }
309 
311  ImplSchedulerContext &rSchedCtx, ImplSchedulerData * const pPrevSchedulerData,
312  const ImplSchedulerData * const pSchedulerData, const int nTaskPriority)
313 {
314  assert( pSchedulerData );
315  if ( pPrevSchedulerData )
316  assert( pPrevSchedulerData->mpNext == pSchedulerData );
317  else
318  assert(rSchedCtx.mpFirstSchedulerData[nTaskPriority] == pSchedulerData);
319 
320  ImplSchedulerData * const pSchedulerDataNext = pSchedulerData->mpNext;
321  if ( pPrevSchedulerData )
322  pPrevSchedulerData->mpNext = pSchedulerDataNext;
323  else
324  rSchedCtx.mpFirstSchedulerData[nTaskPriority] = pSchedulerDataNext;
325  if ( !pSchedulerDataNext )
326  rSchedCtx.mpLastSchedulerData[nTaskPriority] = pPrevSchedulerData;
327  return pSchedulerDataNext;
328 }
329 
331 {
332  ImplSVData *pSVData = ImplGetSVData();
333  ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
334 
336 
337  SchedulerGuard aSchedulerGuard;
338  if ( !rSchedCtx.mbActive || InfiniteTimeoutMs == rSchedCtx.mnTimerPeriod )
339  return;
340 
341  sal_uInt64 nTime = tools::Time::GetSystemTicks();
342  // Allow for decimals, so subtract in the compare (needed at least on iOS)
343  if ( nTime < rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod -1)
344  {
345  int nSleep = rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod - nTime;
346  UpdateSystemTimer(rSchedCtx, nSleep, true, nTime);
347  return;
348  }
349 
350  ImplSchedulerData* pSchedulerData = nullptr;
351  ImplSchedulerData* pPrevSchedulerData = nullptr;
352  ImplSchedulerData *pMostUrgent = nullptr;
353  ImplSchedulerData *pPrevMostUrgent = nullptr;
354  int nMostUrgentPriority = 0;
355  sal_uInt64 nMinPeriod = InfiniteTimeoutMs;
356  sal_uInt64 nReadyPeriod = InfiniteTimeoutMs;
357  unsigned nTasks = 0;
358  int nTaskPriority = 0;
359 
360  for (; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
361  {
362  pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
363  pPrevSchedulerData = nullptr;
364  while (pSchedulerData)
365  {
366  ++nTasks;
367  const Timer *timer = dynamic_cast<Timer*>( pSchedulerData->mpTask );
368  if ( timer )
369  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
370  << pSchedulerData << " " << *pSchedulerData << " " << *timer );
371  else if ( pSchedulerData->mpTask )
372  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
373  << pSchedulerData << " " << *pSchedulerData
374  << " " << *pSchedulerData->mpTask );
375  else
376  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
377  << pSchedulerData << " " << *pSchedulerData << " (to be deleted)" );
378 
379  // Should the Task be released from scheduling?
380  assert(!pSchedulerData->mbInScheduler);
381  if (!pSchedulerData->mpTask || !pSchedulerData->mpTask->IsActive())
382  {
383  ImplSchedulerData * const pSchedulerDataNext =
384  DropSchedulerData(rSchedCtx, pPrevSchedulerData, pSchedulerData, nTaskPriority);
385  if ( pSchedulerData->mpTask )
386  pSchedulerData->mpTask->mpSchedulerData = nullptr;
387  delete pSchedulerData;
388  pSchedulerData = pSchedulerDataNext;
389  continue;
390  }
391 
392  assert(pSchedulerData->mpTask);
393  if (pSchedulerData->mpTask->IsActive())
394  {
395  nReadyPeriod = pSchedulerData->mpTask->UpdateMinPeriod( nTime );
396  if (ImmediateTimeoutMs == nReadyPeriod)
397  {
398  if (!pMostUrgent)
399  {
400  pPrevMostUrgent = pPrevSchedulerData;
401  pMostUrgent = pSchedulerData;
402  nMostUrgentPriority = nTaskPriority;
403  }
404  else
405  {
406  nMinPeriod = ImmediateTimeoutMs;
407  break;
408  }
409  }
410  else if (nMinPeriod > nReadyPeriod)
411  nMinPeriod = nReadyPeriod;
412  }
413 
414  pPrevSchedulerData = pSchedulerData;
415  pSchedulerData = pSchedulerData->mpNext;
416  }
417 
418  if (ImmediateTimeoutMs == nMinPeriod)
419  break;
420  }
421 
422  // Delay invoking tasks with idle priorities as long as there are user input or repaint events
423  // in the OS event queue. This will often effectively compress such events and repaint only
424  // once at the end, improving performance in cases such as repeated zooming with a complex document.
425  if ( pMostUrgent && pMostUrgent->mePriority >= TaskPriority::HIGH_IDLE
427  {
428  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
429  << " idle priority task " << pMostUrgent << " delayed, system events pending" );
430  pMostUrgent = nullptr;
431  nMinPeriod = 0;
432  }
433 
434  if (InfiniteTimeoutMs != nMinPeriod)
435  SAL_INFO("vcl.schedule",
436  "Calculated minimum timeout as " << nMinPeriod << " of " << nTasks << " tasks");
437  UpdateSystemTimer(rSchedCtx, nMinPeriod, true, nTime);
438 
439  if ( pMostUrgent )
440  {
441  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
442  << pMostUrgent << " invoke-in " << *pMostUrgent->mpTask );
443 
444  Task *pTask = pMostUrgent->mpTask;
445 
446  comphelper::ProfileZone aZone( pTask->GetDebugName() );
447 
448  // prepare Scheduler object for deletion after handling
449  pTask->SetDeletionFlags();
450 
451  assert(!pMostUrgent->mbInScheduler);
452  pMostUrgent->mbInScheduler = true;
453 
454  // always push the stack, as we don't traverse the whole list to push later
455  DropSchedulerData(rSchedCtx, pPrevMostUrgent, pMostUrgent, nMostUrgentPriority);
456  pMostUrgent->mpNext = rSchedCtx.mpSchedulerStack;
457  rSchedCtx.mpSchedulerStack = pMostUrgent;
458  rSchedCtx.mpSchedulerStackTop = pMostUrgent;
459 
460  // invoke the task
461  Unlock();
462  /*
463  * Current policy is that scheduler tasks aren't allowed to throw an exception.
464  * Because otherwise the exception is caught somewhere totally unrelated.
465  * TODO Ideally we could capture a proper backtrace and feed this into breakpad,
466  * which is do-able, but requires writing some assembly.
467  * See also SalUserEventList::DispatchUserEvents
468  */
469  try
470  {
471  pTask->Invoke();
472  }
473  catch (css::uno::Exception&)
474  {
475  TOOLS_WARN_EXCEPTION("vcl.schedule", "Uncaught");
476  std::abort();
477  }
478  catch (std::exception& e)
479  {
480  SAL_WARN("vcl.schedule", "Uncaught " << typeid(e).name() << " " << e.what());
481  std::abort();
482  }
483  catch (...)
484  {
485  SAL_WARN("vcl.schedule", "Uncaught exception during Task::Invoke()!");
486  std::abort();
487  }
488  Lock();
489 
490  assert(pMostUrgent->mbInScheduler);
491  pMostUrgent->mbInScheduler = false;
492 
493  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
494  << pMostUrgent << " invoke-out" );
495 
496  // pop the scheduler stack
497  pSchedulerData = rSchedCtx.mpSchedulerStack;
498  assert(pSchedulerData == pMostUrgent);
499  rSchedCtx.mpSchedulerStack = pSchedulerData->mpNext;
500 
501  // coverity[check_after_deref : FALSE] - pMostUrgent->mpTask is initially pMostUrgent->mpTask, but Task::Invoke can clear it
502  const bool bTaskAlive = pMostUrgent->mpTask && pMostUrgent->mpTask->IsActive();
503  if (!bTaskAlive)
504  {
505  if (pMostUrgent->mpTask)
506  pMostUrgent->mpTask->mpSchedulerData = nullptr;
507  delete pMostUrgent;
508  }
509  else
510  AppendSchedulerData(rSchedCtx, pMostUrgent);
511 
512  // this just happens for nested calls, which renders all accounting
513  // invalid, so we just enforce a rescheduling!
514  if (rSchedCtx.mpSchedulerStackTop != pSchedulerData)
515  {
516  UpdateSystemTimer( rSchedCtx, ImmediateTimeoutMs, true,
518  }
519  else if (bTaskAlive)
520  {
521  pMostUrgent->mnUpdateTime = nTime;
522  nReadyPeriod = pMostUrgent->mpTask->UpdateMinPeriod( nTime );
523  if ( nMinPeriod > nReadyPeriod )
524  nMinPeriod = nReadyPeriod;
525  UpdateSystemTimer( rSchedCtx, nMinPeriod, false, nTime );
526  }
527  }
528 }
529 
531 {
533 }
534 
535 void Task::StartTimer( sal_uInt64 nMS )
536 {
538 }
539 
541 {
542  mbActive = false;
543 }
544 
545 void Task::Start(const bool bStartTimer)
546 {
547  ImplSVData *const pSVData = ImplGetSVData();
548  ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
549 
550  SchedulerGuard aSchedulerGuard;
551  if ( !rSchedCtx.mbActive )
552  return;
553 
554  // is the task scheduled in the correct priority queue?
555  // if not we have to get a new data object, as we don't want to traverse
556  // the whole list to move the data to the correct list, as the task list
557  // is just single linked.
558  // Task priority doesn't change that often AFAIK, or we might need to
559  // start caching ImplSchedulerData objects.
561  {
562  mpSchedulerData->mpTask = nullptr;
563  mpSchedulerData = nullptr;
564  }
565  mbActive = true;
566 
567  if ( !mpSchedulerData )
568  {
569  // insert Task
570  ImplSchedulerData* pSchedulerData = new ImplSchedulerData;
571  pSchedulerData->mpTask = this;
572  pSchedulerData->mbInScheduler = false;
573  // mePriority is set in AppendSchedulerData
574  mpSchedulerData = pSchedulerData;
575 
576  AppendSchedulerData( rSchedCtx, pSchedulerData );
577  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
578  << " " << mpSchedulerData << " added " << *this );
579  }
580  else
581  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
582  << " " << mpSchedulerData << " restarted " << *this );
583 
585 
586  if (bStartTimer)
587  Task::StartTimer(0);
588 }
589 
591 {
593  << " " << mpSchedulerData << " stopped " << *this );
594  mbActive = false;
595 }
596 
598 {
599  // you don't actually need to call Stop() before but Start() after, but we
600  // can't check that and don't know when Start() should be called.
601  SAL_WARN_IF(mpSchedulerData && mbActive, "vcl.schedule",
602  "Stop the task before changing the priority, as it will just "
603  "change after the task was scheduled with the old prio!");
604  mePriority = ePriority;
605 }
606 
607 Task& Task::operator=( const Task& rTask )
608 {
609  if(this == &rTask)
610  return *this;
611 
612  if ( IsActive() )
613  Stop();
614 
615  mbActive = false;
616  mePriority = rTask.mePriority;
617 
618  if ( rTask.IsActive() )
619  Start();
620 
621  return *this;
622 }
623 
624 Task::Task( const char *pDebugName )
625  : mpSchedulerData( nullptr )
626  , mpDebugName( pDebugName )
627  , mePriority( TaskPriority::DEFAULT )
628  , mbActive( false )
629  , mbStatic( false )
630 {
631 }
632 
633 Task::Task( const Task& rTask )
634  : mpSchedulerData( nullptr )
635  , mpDebugName( rTask.mpDebugName )
636  , mePriority( rTask.mePriority )
637  , mbActive( false )
638  , mbStatic( false )
639 {
640  if ( rTask.IsActive() )
641  Start();
642 }
643 
644 Task::~Task() COVERITY_NOEXCEPT_FALSE
645 {
646  if ( !IsStatic() )
647  {
648  SchedulerGuard aSchedulerGuard;
649  if ( mpSchedulerData )
650  mpSchedulerData->mpTask = nullptr;
651  }
652  else
653  assert(nullptr == mpSchedulerData || utl::ConfigManager::IsFuzzing());
654 }
655 
656 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static void Unlock()
Definition: scheduler.cxx:217
static void AppendSchedulerData(ImplSchedulerContext &rSchedCtx, ImplSchedulerData *const pSchedulerData)
Definition: scheduler.cxx:290
static void Wakeup()
Wakes up the scheduler.
Definition: scheduler.cxx:530
static void Lock()
Definition: scheduler.cxx:210
#define SAL_INFO_IF(condition, area, stream)
#define PRIO_COUNT
Definition: task.hxx:40
Important idle events to be run before processing drawing events.
TaskPriority mePriority
Task priority.
void SetCallback(SALTIMERPROC pProc)
Definition: saltimer.hxx:46
SalTimer * mpSalTimer
interface to sal event loop / system timer
Definition: svdata.hxx:370
ImplSchedulerData * mpFirstSchedulerData[PRIO_COUNT]
list of all active tasks per priority
Definition: svdata.hxx:366
sal_uInt64 mnUpdateTime
Last Update Time.
bool IsActive() const
Definition: task.hxx:102
virtual void Stop()=0
virtual void Start(bool bStartTimer=true)
Schedules the task for execution.
Definition: scheduler.cxx:545
ImplSchedulerData * mpSchedulerData
Pointer to the element in scheduler list.
Definition: task.hxx:47
static bool IsFuzzing()
virtual SalTimer * CreateSalTimer()=0
static unsigned int m_nTimeSlice
static void ImplStartTimer(sal_uInt64 nMS, bool bForce, sal_uInt64 nTime)
Start a new timer if we need to for nMS duration.
Definition: scheduler.cxx:231
ImplSchedulerData * mpNext
Pointer to the next element in list.
bool mbActive
virtual void Invoke()=0
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:75
virtual void Start(sal_uInt64 nMS)=0
#define TOOLS_WARN_EXCEPTION(area, stream)
static void UpdateSystemTimer(ImplSchedulerContext &rSchedCtx, sal_uInt64 nMinPeriod, bool bForce, sal_uInt64 nTime)
Definition: scheduler.cxx:275
#define SAL_MAX_UINT64
sal_uInt64 GetTimeout() const
Definition: timer.hxx:60
Task(const char *pDebugName)
Definition: scheduler.cxx:624
static bool AnyInput(VclInputFlags nType=VCL_INPUT_ANY)
Determine if there are any pending input events.
Definition: svapp.cxx:595
TaskPriority mePriority
Task priority.
Definition: task.hxx:49
Task * mpTask
Pointer to VCL Task instance.
ImplSchedulerData * mpSchedulerStack
stack of invoked tasks
Definition: svdata.hxx:368
void SetStatic()
This function must be called for static tasks, so the Task destructor ignores the scheduler mutex...
Definition: task.hxx:110
ImplSchedulerData * mpLastSchedulerData[PRIO_COUNT]
last item of each mpFirstSchedulerData list
Definition: svdata.hxx:367
bool mbActive
Currently in the scheduler.
Definition: task.hxx:50
TaskPriority GetPriority() const
Definition: task.hxx:80
static constexpr sal_uInt64 ImmediateTimeoutMs
Definition: scheduler.hxx:43
Task & operator=(const Task &rTask)
Definition: scheduler.cxx:607
ImplSchedulerContext maSchedCtx
Definition: svdata.hxx:390
std::ostream & operator<<(std::ostream &s, ImplLayoutArgs const &rArgs)
Definition: sallayout.cxx:52
static constexpr unsigned int nDefaultTimeSlice
static bool g_bDeterministicMode
Definition: scheduler.cxx:263
static bool GetDeterministicMode()
Return the current state of deterministic mode.
Definition: scheduler.cxx:270
sal_uInt64 mnTimerStart
start time of the timer
Definition: svdata.hxx:371
static constexpr sal_uInt64 InfiniteTimeoutMs
Definition: scheduler.hxx:44
bool IsStatic() const
Definition: task.hxx:111
virtual void SetDeletionFlags()
Definition: scheduler.cxx:540
virtual ~Task() COVERITY_NOEXCEPT_FALSE
Definition: scheduler.cxx:644
void Stop()
Definition: scheduler.cxx:590
#define SAL_WARN_IF(condition, area, stream)
static void StartTimer(sal_uInt64 nMS)
Definition: scheduler.cxx:535
static void CallbackTaskScheduling()
System timer callback function, which processes one LO task.
Definition: scheduler.cxx:330
#define SAL_INFO(area, stream)
bool mbActive
is the scheduler active?
Definition: svdata.hxx:375
if(aStr!=aBuf) UpdateName_Impl(m_xFollowLb.get()
static void SetDeterministicMode(bool bDeterministic)
Control the deterministic mode.
Definition: scheduler.cxx:265
TaskPriority
Definition: task.hxx:27
static void ProcessEventsToIdle()
Process all events until none is pending.
Definition: svapp.cxx:481
const char * name
static sal_uInt64 GetSystemTicks()
ImplSchedulerData * mpSchedulerStackTop
top most stack entry to detect needed rescheduling during pop
Definition: svdata.hxx:369
friend struct ImplSchedulerData
Definition: task.hxx:45
#define SAL_WARN(area, stream)
virtual sal_uInt64 UpdateMinPeriod(sal_uInt64 nTimeNow) const =0
How long (in MS) until the Task is ready to be dispatched?
Definition: timer.hxx:26
void SetPriority(TaskPriority ePriority)
Definition: scheduler.cxx:597
#define DBG_TESTSOLARMUTEX()
sal_uInt64 mnTimerPeriod
current timer period
Definition: svdata.hxx:372
Definition: task.hxx:42
const char * GetDebugName() const
Definition: task.hxx:83
static void ImplDeInitScheduler()
Definition: scheduler.cxx:101
SalInstance * mpDefInst
Definition: svdata.hxx:383
An idle is a timer to be scheduled immediately.
Definition: idle.hxx:34
std::mutex maMutex
the "scheduler mutex" (see vcl/README.scheduler)
Definition: svdata.hxx:373
bool mbInScheduler
Is the Task currently processed / on the stack?
static ImplSchedulerData * DropSchedulerData(ImplSchedulerContext &rSchedCtx, ImplSchedulerData *const pPrevSchedulerData, const ImplSchedulerData *const pSchedulerData, const int nTaskPriority)
Definition: scheduler.cxx:310