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