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
128 #endif
129  rSchedCtx.mbActive = false;
130 
131  assert( nullptr == rSchedCtx.mpSchedulerStack );
132  assert( 1 == rSchedCtx.maMutex.lockDepth() );
133 
134  if (rSchedCtx.mpSalTimer) rSchedCtx.mpSalTimer->Stop();
135  delete rSchedCtx.mpSalTimer;
136  rSchedCtx.mpSalTimer = nullptr;
137 
138 #if OSL_DEBUG_LEVEL > 0
139  sal_uInt32 nActiveTasks = 0, nIgnoredTasks = 0;
140 #endif
141  nTaskPriority = 0;
142  ImplSchedulerData* pSchedulerData = nullptr;
143 
144 next_priority:
145  pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
146  while ( pSchedulerData )
147  {
148  Task *pTask = pSchedulerData->mpTask;
149  if ( pTask )
150  {
151  if ( pTask->mbActive )
152  {
153 #if OSL_DEBUG_LEVEL > 0
154  const char *sIgnored = "";
155  ++nActiveTasks;
156  // TODO: shutdown these timers before Scheduler de-init
157  // TODO: remove Task from static object
158  if ( pTask->GetDebugName() && ( false
159  || !strcmp( pTask->GetDebugName(), "desktop::Desktop m_firstRunTimer" )
160  || !strcmp( pTask->GetDebugName(), "DrawWorkStartupTimer" )
161  || !strcmp( pTask->GetDebugName(), "editeng::ImpEditEngine aOnlineSpellTimer" )
162  || !strcmp( pTask->GetDebugName(), "ImplHandleMouseMsg SalData::mpMouseLeaveTimer" )
163  || !strcmp( pTask->GetDebugName(), "sc ScModule IdleTimer" )
164  || !strcmp( pTask->GetDebugName(), "sd::CacheConfiguration maReleaseTimer" )
165  || !strcmp( pTask->GetDebugName(), "svtools::GraphicCache maReleaseTimer" )
166  || !strcmp( pTask->GetDebugName(), "svtools::GraphicObject mpSwapOutTimer" )
167  || !strcmp( pTask->GetDebugName(), "svx OLEObjCache pTimer UnloadCheck" )
168  || !strcmp( pTask->GetDebugName(), "vcl SystemDependentDataBuffer aSystemDependentDataBuffer" )
169  ))
170  {
171  sIgnored = " (ignored)";
172  ++nIgnoredTasks;
173  }
174  const Timer *timer = dynamic_cast<Timer*>( pTask );
175  if ( timer )
176  SAL_WARN( "vcl.schedule.deinit", "DeInit task: " << *timer << sIgnored );
177  else
178  SAL_WARN( "vcl.schedule.deinit", "DeInit task: " << *pTask << sIgnored );
179 #endif
180  pTask->mbActive = false;
181  }
182  pTask->mpSchedulerData = nullptr;
183  pTask->SetStatic();
184  }
185  ImplSchedulerData* pDeleteSchedulerData = pSchedulerData;
186  pSchedulerData = pSchedulerData->mpNext;
187  delete pDeleteSchedulerData;
188  }
189 
190  ++nTaskPriority;
191  if (nTaskPriority < PRIO_COUNT)
192  goto next_priority;
193 
194 #if OSL_DEBUG_LEVEL > 0
195  SAL_INFO( "vcl.schedule.deinit", "DeInit the scheduler - finished" );
196  SAL_WARN_IF( 0 != nActiveTasks, "vcl.schedule.deinit", "DeInit active tasks: "
197  << nActiveTasks << " (ignored: " << nIgnoredTasks << ")" );
198 // assert( nIgnoredTasks == nActiveTasks );
199 #endif
200 
201  for (nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
202  {
203  rSchedCtx.mpFirstSchedulerData[nTaskPriority] = nullptr;
204  rSchedCtx.mpLastSchedulerData[nTaskPriority] = nullptr;
205  }
206  rSchedCtx.mnTimerPeriod = InfiniteTimeoutMs;
207 }
208 
209 void SchedulerMutex::acquire( sal_uInt32 nLockCount )
210 {
211  assert(nLockCount > 0);
212  for (sal_uInt32 i = 0; i != nLockCount; ++i) {
213  if (!maMutex.acquire())
214  abort();
215  }
216  mnLockDepth += nLockCount;
217 }
218 
219 sal_uInt32 SchedulerMutex::release( bool bUnlockAll )
220 {
221  assert(mnLockDepth > 0);
222  const sal_uInt32 nLockCount =
223  (bUnlockAll || 0 == mnLockDepth) ? mnLockDepth : 1;
224  mnLockDepth -= nLockCount;
225  for (sal_uInt32 i = 0; i != nLockCount; ++i) {
226  if (!maMutex.release())
227  abort();
228  }
229  return nLockCount;
230 }
231 
232 void Scheduler::Lock( sal_uInt32 nLockCount )
233 {
234  ImplSVData* pSVData = ImplGetSVData();
235  assert( pSVData != nullptr );
236  pSVData->maSchedCtx.maMutex.acquire( nLockCount );
237 }
238 
239 sal_uInt32 Scheduler::Unlock( bool bUnlockAll )
240 {
241  ImplSVData* pSVData = ImplGetSVData();
242  assert( pSVData != nullptr );
243  return pSVData->maSchedCtx.maMutex.release( bUnlockAll );
244 }
245 
253 void Scheduler::ImplStartTimer(sal_uInt64 nMS, bool bForce, sal_uInt64 nTime)
254 {
255  ImplSVData* pSVData = ImplGetSVData();
256  ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
257  if ( !rSchedCtx.mbActive )
258  return;
259 
260  if (!rSchedCtx.mpSalTimer)
261  {
262  rSchedCtx.mnTimerStart = 0;
263  rSchedCtx.mnTimerPeriod = InfiniteTimeoutMs;
264  rSchedCtx.mpSalTimer = pSVData->mpDefInst->CreateSalTimer();
266  }
267 
268  assert(SAL_MAX_UINT64 - nMS >= nTime);
269 
270  sal_uInt64 nProposedTimeout = nTime + nMS;
271  sal_uInt64 nCurTimeout = ( rSchedCtx.mnTimerPeriod == InfiniteTimeoutMs )
272  ? SAL_MAX_UINT64 : rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod;
273 
274  // Only if smaller timeout, to avoid skipping.
275  // Force instant wakeup on 0ms, if the previous period was not 0ms
276  if (bForce || nProposedTimeout < nCurTimeout || (!nMS && rSchedCtx.mnTimerPeriod))
277  {
278  SAL_INFO( "vcl.schedule", " Starting scheduler system timer (" << nMS << "ms)" );
279  rSchedCtx.mnTimerStart = nTime;
280  rSchedCtx.mnTimerPeriod = nMS;
281  rSchedCtx.mpSalTimer->Start( nMS );
282  }
283 }
284 
286 {
287  // this function is for the saltimer callback
289 }
290 
291 static bool g_bDeterministicMode = false;
292 
293 void Scheduler::SetDeterministicMode(bool bDeterministic)
294 {
295  g_bDeterministicMode = bDeterministic;
296 }
297 
299 {
300  return g_bDeterministicMode;
301 }
302 
304  const sal_uInt64 nMinPeriod,
305  const bool bForce, const sal_uInt64 nTime )
306 {
307  if ( InfiniteTimeoutMs == nMinPeriod )
308  {
309  SAL_INFO("vcl.schedule", " Stopping system timer");
310  if ( rSchedCtx.mpSalTimer )
311  rSchedCtx.mpSalTimer->Stop();
312  rSchedCtx.mnTimerPeriod = nMinPeriod;
313  }
314  else
315  Scheduler::ImplStartTimer( nMinPeriod, bForce, nTime );
316 }
317 
319  ImplSchedulerData * const pSchedulerData)
320 {
321  assert(pSchedulerData->mpTask);
322  pSchedulerData->mePriority = pSchedulerData->mpTask->GetPriority();
323  pSchedulerData->mpNext = nullptr;
324 
325  const int nTaskPriority = static_cast<int>(pSchedulerData->mePriority);
326  if (!rSchedCtx.mpLastSchedulerData[nTaskPriority])
327  {
328  rSchedCtx.mpFirstSchedulerData[nTaskPriority] = pSchedulerData;
329  rSchedCtx.mpLastSchedulerData[nTaskPriority] = pSchedulerData;
330  }
331  else
332  {
333  rSchedCtx.mpLastSchedulerData[nTaskPriority]->mpNext = pSchedulerData;
334  rSchedCtx.mpLastSchedulerData[nTaskPriority] = pSchedulerData;
335  }
336 }
337 
339  ImplSchedulerContext &rSchedCtx, ImplSchedulerData * const pPrevSchedulerData,
340  const ImplSchedulerData * const pSchedulerData, const int nTaskPriority)
341 {
342  assert( pSchedulerData );
343  if ( pPrevSchedulerData )
344  assert( pPrevSchedulerData->mpNext == pSchedulerData );
345  else
346  assert(rSchedCtx.mpFirstSchedulerData[nTaskPriority] == pSchedulerData);
347 
348  ImplSchedulerData * const pSchedulerDataNext = pSchedulerData->mpNext;
349  if ( pPrevSchedulerData )
350  pPrevSchedulerData->mpNext = pSchedulerDataNext;
351  else
352  rSchedCtx.mpFirstSchedulerData[nTaskPriority] = pSchedulerDataNext;
353  if ( !pSchedulerDataNext )
354  rSchedCtx.mpLastSchedulerData[nTaskPriority] = pPrevSchedulerData;
355  return pSchedulerDataNext;
356 }
357 
359 {
360  ImplSVData *pSVData = ImplGetSVData();
361  ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
362 
364 
365  SchedulerGuard aSchedulerGuard;
366  if ( !rSchedCtx.mbActive || InfiniteTimeoutMs == rSchedCtx.mnTimerPeriod )
367  return false;
368 
369  sal_uInt64 nTime = tools::Time::GetSystemTicks();
370  // Allow for decimals, so subtract in the compare (needed at least on iOS)
371  if ( nTime < rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod -1)
372  {
373  int nSleep = rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod - nTime;
374  UpdateSystemTimer(rSchedCtx, nSleep, true, nTime);
375  return false;
376  }
377 
378  ImplSchedulerData* pSchedulerData = nullptr;
379  ImplSchedulerData* pPrevSchedulerData = nullptr;
380  ImplSchedulerData *pMostUrgent = nullptr;
381  ImplSchedulerData *pPrevMostUrgent = nullptr;
382  int nMostUrgentPriority = 0;
383  sal_uInt64 nMinPeriod = InfiniteTimeoutMs;
384  sal_uInt64 nReadyPeriod = InfiniteTimeoutMs;
385  unsigned nTasks = 0;
386  int nTaskPriority = 0;
387 
388  for (; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
389  {
390  pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
391  pPrevSchedulerData = nullptr;
392  while (pSchedulerData)
393  {
394  ++nTasks;
395  const Timer *timer = dynamic_cast<Timer*>( pSchedulerData->mpTask );
396  if ( timer )
397  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
398  << pSchedulerData << " " << *pSchedulerData << " " << *timer );
399  else if ( pSchedulerData->mpTask )
400  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
401  << pSchedulerData << " " << *pSchedulerData
402  << " " << *pSchedulerData->mpTask );
403  else
404  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
405  << pSchedulerData << " " << *pSchedulerData << " (to be deleted)" );
406 
407  // Should the Task be released from scheduling?
408  assert(!pSchedulerData->mbInScheduler);
409  if (!pSchedulerData->mpTask || !pSchedulerData->mpTask->IsActive())
410  {
411  ImplSchedulerData * const pSchedulerDataNext =
412  DropSchedulerData(rSchedCtx, pPrevSchedulerData, pSchedulerData, nTaskPriority);
413  if ( pSchedulerData->mpTask )
414  pSchedulerData->mpTask->mpSchedulerData = nullptr;
415  delete pSchedulerData;
416  pSchedulerData = pSchedulerDataNext;
417  continue;
418  }
419 
420  assert(pSchedulerData->mpTask);
421  if (pSchedulerData->mpTask->IsActive())
422  {
423  nReadyPeriod = pSchedulerData->mpTask->UpdateMinPeriod( nTime );
424  if (ImmediateTimeoutMs == nReadyPeriod)
425  {
426  if (!pMostUrgent)
427  {
428  pPrevMostUrgent = pPrevSchedulerData;
429  pMostUrgent = pSchedulerData;
430  nMostUrgentPriority = nTaskPriority;
431  }
432  else
433  {
434  nMinPeriod = ImmediateTimeoutMs;
435  break;
436  }
437  }
438  else if (nMinPeriod > nReadyPeriod)
439  nMinPeriod = nReadyPeriod;
440  }
441 
442  pPrevSchedulerData = pSchedulerData;
443  pSchedulerData = pSchedulerData->mpNext;
444  }
445 
446  if (ImmediateTimeoutMs == nMinPeriod)
447  break;
448  }
449 
450  if ( InfiniteTimeoutMs != nMinPeriod )
451  SAL_INFO("vcl.schedule", "Calculated minimum timeout as " << nMinPeriod
452  << " of " << nTasks << " tasks" );
453  UpdateSystemTimer( rSchedCtx, nMinPeriod, true, nTime );
454 
455  if ( pMostUrgent )
456  {
457  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
458  << pMostUrgent << " invoke-in " << *pMostUrgent->mpTask );
459 
460  Task *pTask = pMostUrgent->mpTask;
461 
462  comphelper::ProfileZone aZone( pTask->GetDebugName() );
463 
464  // prepare Scheduler object for deletion after handling
465  pTask->SetDeletionFlags();
466 
467  pMostUrgent->mbInScheduler = true;
468 
469  // always push the stack, as we don't traverse the whole list to push later
470  DropSchedulerData(rSchedCtx, pPrevMostUrgent, pMostUrgent, nMostUrgentPriority);
471  pMostUrgent->mpNext = rSchedCtx.mpSchedulerStack;
472  rSchedCtx.mpSchedulerStack = pMostUrgent;
473  rSchedCtx.mpSchedulerStackTop = pMostUrgent;
474 
475  // invoke the task
476  sal_uInt32 nLockCount = Unlock( true );
477  /*
478  * Current policy is that scheduler tasks aren't allowed to throw an exception.
479  * Because otherwise the exception is caught somewhere totally unrelated.
480  * TODO Ideally we could capture a proper backtrace and feed this into breakpad,
481  * which is do-able, but requires writing some assembly.
482  * See also SalUserEventList::DispatchUserEvents
483  */
484  try
485  {
486  pTask->Invoke();
487  }
488  catch (css::uno::Exception&)
489  {
490  TOOLS_WARN_EXCEPTION("vcl.schedule", "Uncaught");
491  std::abort();
492  }
493  catch (std::exception& e)
494  {
495  SAL_WARN("vcl.schedule", "Uncaught " << typeid(e).name() << " " << e.what());
496  std::abort();
497  }
498  catch (...)
499  {
500  SAL_WARN("vcl.schedule", "Uncaught exception during Task::Invoke()!");
501  std::abort();
502  }
503  Lock( nLockCount );
504  pMostUrgent->mbInScheduler = false;
505 
506  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
507  << pMostUrgent << " invoke-out" );
508 
509  // pop the scheduler stack
510  pSchedulerData = rSchedCtx.mpSchedulerStack;
511  assert(pSchedulerData == pMostUrgent);
512  rSchedCtx.mpSchedulerStack = pSchedulerData->mpNext;
513 
514  const bool bTaskAlive = pMostUrgent->mpTask && pMostUrgent->mpTask->IsActive();
515  if (!bTaskAlive)
516  {
517  if (pMostUrgent->mpTask)
518  pMostUrgent->mpTask->mpSchedulerData = nullptr;
519  delete pMostUrgent;
520  }
521  else
522  AppendSchedulerData(rSchedCtx, pMostUrgent);
523 
524  // this just happens for nested calls, which renders all accounting
525  // invalid, so we just enforce a rescheduling!
526  if (rSchedCtx.mpSchedulerStackTop != pSchedulerData)
527  {
528  UpdateSystemTimer( rSchedCtx, ImmediateTimeoutMs, true,
530  }
531  else if (bTaskAlive)
532  {
533  pMostUrgent->mnUpdateTime = nTime;
534  nReadyPeriod = pMostUrgent->mpTask->UpdateMinPeriod( nTime );
535  if ( nMinPeriod > nReadyPeriod )
536  nMinPeriod = nReadyPeriod;
537  UpdateSystemTimer( rSchedCtx, nMinPeriod, false, nTime );
538  }
539  }
540 
541  return !!pMostUrgent;
542 }
543 
545 {
547 }
548 
549 void Task::StartTimer( sal_uInt64 nMS )
550 {
552 }
553 
555 {
556  mbActive = false;
557 }
558 
560 {
561  ImplSVData *const pSVData = ImplGetSVData();
562  ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
563 
564  SchedulerGuard aSchedulerGuard;
565  if ( !rSchedCtx.mbActive )
566  return;
567 
568  // is the task scheduled in the correct priority queue?
569  // if not we have to get a new data object, as we don't want to traverse
570  // the whole list to move the data to the correct list, as the task list
571  // is just single linked.
572  // Task priority doesn't change that often AFAIK, or we might need to
573  // start caching ImplSchedulerData objects.
575  {
576  mpSchedulerData->mpTask = nullptr;
577  mpSchedulerData = nullptr;
578  }
579  mbActive = true;
580 
581  if ( !mpSchedulerData )
582  {
583  // insert Task
584  ImplSchedulerData* pSchedulerData = new ImplSchedulerData;
585  pSchedulerData->mpTask = this;
586  pSchedulerData->mbInScheduler = false;
587  // mePriority is set in AppendSchedulerData
588  mpSchedulerData = pSchedulerData;
589 
590  AppendSchedulerData( rSchedCtx, pSchedulerData );
591  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
592  << " " << mpSchedulerData << " added " << *this );
593  }
594  else
595  SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
596  << " " << mpSchedulerData << " restarted " << *this );
597 
599 }
600 
602 {
604  << " " << mpSchedulerData << " stopped " << *this );
605  mbActive = false;
606 }
607 
609 {
610  // you don't actually need to call Stop() before but Start() after, but we
611  // can't check that and don't know when Start() should be called.
612  SAL_WARN_IF(mpSchedulerData && mbActive, "vcl.schedule",
613  "Stop the task before changing the priority, as it will just "
614  "change after the task was scheduled with the old prio!");
615  mePriority = ePriority;
616 }
617 
618 Task& Task::operator=( const Task& rTask )
619 {
620  if(this == &rTask)
621  return *this;
622 
623  if ( IsActive() )
624  Stop();
625 
626  mbActive = false;
627  mePriority = rTask.mePriority;
628 
629  if ( rTask.IsActive() )
630  Start();
631 
632  return *this;
633 }
634 
635 Task::Task( const char *pDebugName )
636  : mpSchedulerData( nullptr )
637  , mpDebugName( pDebugName )
638  , mePriority( TaskPriority::DEFAULT )
639  , mbActive( false )
640  , mbStatic( false )
641 {
642 }
643 
644 Task::Task( const Task& rTask )
645  : mpSchedulerData( nullptr )
646  , mpDebugName( rTask.mpDebugName )
647  , mePriority( rTask.mePriority )
648  , mbActive( false )
649  , mbStatic( false )
650 {
651  if ( rTask.IsActive() )
652  Start();
653 }
654 
655 Task::~Task() COVERITY_NOEXCEPT_FALSE
656 {
657  if ( !IsStatic() )
658  {
659  SchedulerGuard aSchedulerGuard;
660  if ( mpSchedulerData )
661  mpSchedulerData->mpTask = nullptr;
662  }
663  else
665 }
666 
667 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static void AppendSchedulerData(ImplSchedulerContext &rSchedCtx, ImplSchedulerData *const pSchedulerData)
Definition: scheduler.cxx:318
SchedulerMutex maMutex
lock counting mutex for scheduler locking
Definition: svdata.hxx:372
static void Wakeup()
Wakes up the scheduler.
Definition: scheduler.cxx:544
#define SAL_INFO_IF(condition, area, stream)
#define PRIO_COUNT
Definition: task.hxx:39
TaskPriority mePriority
Task priority.
void SetCallback(SALTIMERPROC pProc)
Definition: saltimer.hxx:46
static void Lock(sal_uInt32 nLockCount=1)
Definition: scheduler.cxx:232
SalTimer * mpSalTimer
interface to sal event loop / system timer
Definition: svdata.hxx:369
static bool ProcessTaskScheduling()
Process one pending task ahead of time with highest priority.
Definition: scheduler.cxx:358
ImplSchedulerData * mpFirstSchedulerData[PRIO_COUNT]
list of all active tasks per priority
Definition: svdata.hxx:365
sal_uInt64 mnUpdateTime
Last Update Time.
bool IsActive() const
Definition: task.hxx:90
virtual void Stop()=0
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
ImplSchedulerData * mpSchedulerData
Pointer to the element in scheduler list.
Definition: task.hxx:46
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:253
ImplSchedulerData * mpNext
Pointer to the next element in list.
bool mbActive
virtual void Start()
Definition: scheduler.cxx:559
virtual void Invoke()=0
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:76
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:303
#define SAL_MAX_UINT64
sal_uInt64 GetTimeout() const
Definition: timer.hxx:60
int i
Task(const char *pDebugName)
Definition: scheduler.cxx:635
TaskPriority mePriority
Task priority.
Definition: task.hxx:48
Task * mpTask
Pointer to VCL Task instance.
ImplSchedulerData * mpSchedulerStack
stack of invoked tasks
Definition: svdata.hxx:367
static sal_uInt32 Unlock(bool bUnlockAll=false)
Definition: scheduler.cxx:239
void SetStatic()
This function must be called for static tasks, so the Task destructor ignores the SchedulerMutex...
Definition: task.hxx:98
sal_uInt32 mnLockDepth
ImplSchedulerData * mpLastSchedulerData[PRIO_COUNT]
last item of each mpFirstSchedulerData list
Definition: svdata.hxx:366
bool mbActive
Currently in the scheduler.
Definition: task.hxx:49
TaskPriority GetPriority() const
Definition: task.hxx:79
static constexpr sal_uInt64 ImmediateTimeoutMs
Definition: scheduler.hxx:43
osl::Mutex maMutex
Task & operator=(const Task &rTask)
Definition: scheduler.cxx:618
ImplSchedulerContext maSchedCtx
Definition: svdata.hxx:391
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:291
static bool GetDeterministicMode()
Return the current state of deterministic mode.
Definition: scheduler.cxx:298
sal_uInt64 mnTimerStart
start time of the timer
Definition: svdata.hxx:370
static constexpr sal_uInt64 InfiniteTimeoutMs
Definition: scheduler.hxx:44
void acquire(sal_uInt32 nLockCount=1)
Definition: scheduler.cxx:209
sal_uInt32 lockDepth() const
bool IsStatic() const
Definition: task.hxx:99
virtual void SetDeletionFlags()
Definition: scheduler.cxx:554
virtual ~Task() COVERITY_NOEXCEPT_FALSE
Definition: scheduler.cxx:655
void Stop()
Definition: scheduler.cxx:601
#define SAL_WARN_IF(condition, area, stream)
static void StartTimer(sal_uInt64 nMS)
Definition: scheduler.cxx:549
static void CallbackTaskScheduling()
Process one pending Timer with highest priority.
Definition: scheduler.cxx:285
#define SAL_INFO(area, stream)
bool mbActive
is the scheduler active?
Definition: svdata.hxx:373
static void SetDeterministicMode(bool bDeterministic)
Control the deterministic mode.
Definition: scheduler.cxx:293
TaskPriority
Definition: task.hxx:27
static void ProcessEventsToIdle()
Process all events until none is pending.
Definition: svapp.cxx:462
const char * name
static sal_uInt64 GetSystemTicks()
ImplSchedulerData * mpSchedulerStackTop
top most stack entry to detect needed rescheduling during pop
Definition: svdata.hxx:368
friend struct ImplSchedulerData
Definition: task.hxx:44
#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:608
#define DBG_TESTSOLARMUTEX()
if(!pCandidateA->getEnd().equal(pCandidateB->getStart()))
sal_uInt64 mnTimerPeriod
current timer period
Definition: svdata.hxx:371
Definition: task.hxx:41
const char * GetDebugName() const
Definition: task.hxx:82
static void ImplDeInitScheduler()
Definition: scheduler.cxx:101
SalInstance * mpDefInst
Definition: svdata.hxx:381
An idle is a timer to be scheduled immediately.
Definition: idle.hxx:30
bool mbInScheduler
Task currently processed?
static ImplSchedulerData * DropSchedulerData(ImplSchedulerContext &rSchedCtx, ImplSchedulerData *const pPrevSchedulerData, const ImplSchedulerData *const pSchedulerData, const int nTaskPriority)
Definition: scheduler.cxx:338
sal_uInt32 release(bool bUnlockAll=false)
Definition: scheduler.cxx:219