Fix typo
[LibreOffice.git] / vcl / source / app / scheduler.cxx
blobeaca69adafa11c6f8814e729188bc2472734da69
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <cassert>
23 #include <cstdlib>
24 #include <exception>
25 #include <typeinfo>
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 <comphelper/diagnose_ex.hxx>
34 #include <comphelper/configuration.hxx>
35 #include <vcl/TaskStopwatch.hxx>
36 #include <vcl/scheduler.hxx>
37 #include <vcl/idle.hxx>
38 #include <saltimer.hxx>
39 #include <salinst.hxx>
40 #include <comphelper/profilezone.hxx>
41 #include <schedulerimpl.hxx>
43 namespace {
45 template< typename charT, typename traits >
46 std::basic_ostream<charT, traits> & operator <<(
47 std::basic_ostream<charT, traits> & stream, const Task& task )
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;
57 /**
58 * clang won't compile this in the Timer.hxx header, even with a class Idle
59 * forward definition, due to the incomplete Idle type in the template.
60 * Currently the code is just used in the Scheduler, so we keep it local.
62 * @see http://clang.llvm.org/compatibility.html#undep_incomplete
64 template< typename charT, typename traits >
65 std::basic_ostream<charT, traits> & operator <<(
66 std::basic_ostream<charT, traits> & stream, const Timer& timer )
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;
82 template< typename charT, typename traits >
83 std::basic_ostream<charT, traits> & operator <<(
84 std::basic_ostream<charT, traits> & stream, const Idle& idle )
86 return stream << static_cast<const Timer*>( &idle );
89 template< typename charT, typename traits >
90 std::basic_ostream<charT, traits> & operator <<(
91 std::basic_ostream<charT, traits> & stream, const ImplSchedulerData& data )
93 stream << " i: " << data.mbInScheduler;
94 return stream;
97 } // end anonymous namespace
99 unsigned int TaskStopwatch::m_nTimeSlice = TaskStopwatch::nDefaultTimeSlice;
101 void Scheduler::ImplDeInitScheduler()
103 ImplSVData* pSVData = ImplGetSVData();
104 assert( pSVData != nullptr );
105 ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
107 DBG_TESTSOLARMUTEX();
109 SchedulerGuard aSchedulerGuard;
111 int nTaskPriority = 0;
112 #if OSL_DEBUG_LEVEL > 0
113 sal_uInt32 nTasks = 0;
114 for (nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
116 ImplSchedulerData* pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
117 while ( pSchedulerData )
119 ++nTasks;
120 pSchedulerData = pSchedulerData->mpNext;
123 SAL_INFO( "vcl.schedule.deinit",
124 "DeInit the scheduler - pending tasks: " << nTasks );
126 // clean up all Idles
127 Unlock();
128 ProcessEventsToIdle();
129 Lock();
130 #endif
131 rSchedCtx.mbActive = false;
133 assert( nullptr == rSchedCtx.mpSchedulerStack || (!rSchedCtx.mpSchedulerStack->mpTask && !rSchedCtx.mpSchedulerStack->mpNext) );
135 if (rSchedCtx.mpSalTimer) rSchedCtx.mpSalTimer->Stop();
136 delete rSchedCtx.mpSalTimer;
137 rSchedCtx.mpSalTimer = nullptr;
139 #if OSL_DEBUG_LEVEL > 0
140 sal_uInt32 nActiveTasks = 0, nIgnoredTasks = 0;
141 #endif
142 nTaskPriority = 0;
143 ImplSchedulerData* pSchedulerData = nullptr;
145 next_priority:
146 pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
147 while ( pSchedulerData )
149 Task *pTask = pSchedulerData->mpTask;
150 if ( pTask )
152 if ( pTask->mbActive )
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(), "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" )
171 sIgnored = " (ignored)";
172 ++nIgnoredTasks;
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;
182 pTask->mpSchedulerData = nullptr;
183 pTask->SetStatic();
185 ImplSchedulerData* pDeleteSchedulerData = pSchedulerData;
186 pSchedulerData = pSchedulerData->mpNext;
187 delete pDeleteSchedulerData;
190 ++nTaskPriority;
191 if (nTaskPriority < PRIO_COUNT)
192 goto next_priority;
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
201 for (nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
203 rSchedCtx.mpFirstSchedulerData[nTaskPriority] = nullptr;
204 rSchedCtx.mpLastSchedulerData[nTaskPriority] = nullptr;
206 rSchedCtx.mnTimerPeriod = InfiniteTimeoutMs;
209 void Scheduler::Lock()
211 ImplSVData* pSVData = ImplGetSVData();
212 assert( pSVData != nullptr );
213 pSVData->maSchedCtx.maMutex.lock();
216 void Scheduler::Unlock()
218 ImplSVData* pSVData = ImplGetSVData();
219 assert( pSVData != nullptr );
220 pSVData->maSchedCtx.maMutex.unlock();
224 * Start a new timer if we need to for nMS duration.
226 * if this is longer than the existing duration we're
227 * waiting for, do nothing - unless bForce - which means
228 * to reset the minimum period; used by the scheduled itself.
230 void Scheduler::ImplStartTimer(sal_uInt64 nMS, bool bForce, sal_uInt64 nTime)
232 ImplSVData* pSVData = ImplGetSVData();
233 ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
234 if ( !rSchedCtx.mbActive )
235 return;
237 if (!rSchedCtx.mpSalTimer)
239 rSchedCtx.mnTimerStart = 0;
240 rSchedCtx.mnTimerPeriod = InfiniteTimeoutMs;
241 rSchedCtx.mpSalTimer = pSVData->mpDefInst->CreateSalTimer();
242 rSchedCtx.mpSalTimer->SetCallback(Scheduler::CallbackTaskScheduling);
245 assert(SAL_MAX_UINT64 - nMS >= nTime);
247 sal_uInt64 nProposedTimeout = nTime + nMS;
248 sal_uInt64 nCurTimeout = ( rSchedCtx.mnTimerPeriod == InfiniteTimeoutMs )
249 ? SAL_MAX_UINT64 : rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod;
251 // Only if smaller timeout, to avoid skipping.
252 // Force instant wakeup on 0ms, if the previous period was not 0ms
253 if (bForce || nProposedTimeout < nCurTimeout || (!nMS && rSchedCtx.mnTimerPeriod))
255 SAL_INFO( "vcl.schedule", " Starting scheduler system timer (" << nMS << "ms)" );
256 rSchedCtx.mnTimerStart = nTime;
257 rSchedCtx.mnTimerPeriod = nMS;
258 rSchedCtx.mpSalTimer->Start( nMS );
262 static bool g_bDeterministicMode = false;
264 void Scheduler::SetDeterministicMode(bool bDeterministic)
266 g_bDeterministicMode = bDeterministic;
269 bool Scheduler::GetDeterministicMode()
271 return g_bDeterministicMode;
274 Scheduler::IdlesLockGuard::IdlesLockGuard()
276 ImplSVData* pSVData = ImplGetSVData();
277 ImplSchedulerContext& rSchedCtx = pSVData->maSchedCtx;
278 osl_atomic_increment(&rSchedCtx.mnIdlesLockCount);
279 if (!Application::IsMainThread())
281 // Make sure that main thread has reached the main message loop, so no idles are executing.
282 // It is important to ensure this, because e.g. ProcessEventsToIdle could be executed in a
283 // nested event loop, while an active processed idle in the main thread is waiting for some
284 // condition to proceed. Only main thread returning to Application::Execute guarantees that
285 // the flag really took effect.
286 pSVData->m_inExecuteCondtion.reset();
287 // Put an empty event to the application's queue, to make sure that it loops through the
288 // code that sets the condition, even when there's no other events in the queue
289 Application::PostUserEvent({});
290 SolarMutexReleaser releaser;
291 pSVData->m_inExecuteCondtion.wait();
295 Scheduler::IdlesLockGuard::~IdlesLockGuard()
297 ImplSchedulerContext& rSchedCtx = ImplGetSVData()->maSchedCtx;
298 osl_atomic_decrement(&rSchedCtx.mnIdlesLockCount);
301 inline void Scheduler::UpdateSystemTimer( ImplSchedulerContext &rSchedCtx,
302 const sal_uInt64 nMinPeriod,
303 const bool bForce, const sal_uInt64 nTime )
305 if ( InfiniteTimeoutMs == nMinPeriod )
307 SAL_INFO("vcl.schedule", " Stopping system timer");
308 if ( rSchedCtx.mpSalTimer )
309 rSchedCtx.mpSalTimer->Stop();
310 rSchedCtx.mnTimerPeriod = nMinPeriod;
312 else
313 Scheduler::ImplStartTimer( nMinPeriod, bForce, nTime );
316 static void AppendSchedulerData( ImplSchedulerContext &rSchedCtx,
317 ImplSchedulerData * const pSchedulerData)
319 assert(pSchedulerData->mpTask);
320 pSchedulerData->mePriority = pSchedulerData->mpTask->GetPriority();
321 pSchedulerData->mpNext = nullptr;
323 const int nTaskPriority = static_cast<int>(pSchedulerData->mePriority);
324 if (!rSchedCtx.mpLastSchedulerData[nTaskPriority])
326 rSchedCtx.mpFirstSchedulerData[nTaskPriority] = pSchedulerData;
327 rSchedCtx.mpLastSchedulerData[nTaskPriority] = pSchedulerData;
329 else
331 rSchedCtx.mpLastSchedulerData[nTaskPriority]->mpNext = pSchedulerData;
332 rSchedCtx.mpLastSchedulerData[nTaskPriority] = pSchedulerData;
336 static ImplSchedulerData* DropSchedulerData(
337 ImplSchedulerContext &rSchedCtx, ImplSchedulerData * const pPrevSchedulerData,
338 const ImplSchedulerData * const pSchedulerData, const int nTaskPriority)
340 assert( pSchedulerData );
341 if ( pPrevSchedulerData )
342 assert( pPrevSchedulerData->mpNext == pSchedulerData );
343 else
344 assert(rSchedCtx.mpFirstSchedulerData[nTaskPriority] == pSchedulerData);
346 ImplSchedulerData * const pSchedulerDataNext = pSchedulerData->mpNext;
347 if ( pPrevSchedulerData )
348 pPrevSchedulerData->mpNext = pSchedulerDataNext;
349 else
350 rSchedCtx.mpFirstSchedulerData[nTaskPriority] = pSchedulerDataNext;
351 if ( !pSchedulerDataNext )
352 rSchedCtx.mpLastSchedulerData[nTaskPriority] = pPrevSchedulerData;
353 return pSchedulerDataNext;
356 void Scheduler::CallbackTaskScheduling()
358 ImplSVData *pSVData = ImplGetSVData();
359 ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
361 DBG_TESTSOLARMUTEX();
363 SchedulerGuard aSchedulerGuard;
364 if ( !rSchedCtx.mbActive || InfiniteTimeoutMs == rSchedCtx.mnTimerPeriod )
365 return;
367 sal_uInt64 nTime = tools::Time::GetSystemTicks();
368 // Allow for decimals, so subtract in the compare (needed at least on iOS)
369 if ( nTime < rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod -1)
371 int nSleep = rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod - nTime;
372 UpdateSystemTimer(rSchedCtx, nSleep, true, nTime);
373 return;
376 ImplSchedulerData* pSchedulerData = nullptr;
377 ImplSchedulerData* pPrevSchedulerData = nullptr;
378 ImplSchedulerData *pMostUrgent = nullptr;
379 ImplSchedulerData *pPrevMostUrgent = nullptr;
380 int nMostUrgentPriority = 0;
381 sal_uInt64 nMinPeriod = InfiniteTimeoutMs;
382 sal_uInt64 nReadyPeriod = InfiniteTimeoutMs;
383 unsigned nTasks = 0;
384 int nTaskPriority = 0;
386 for (; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
388 // Related: tdf#152703 Eliminate potential blocking during live resize
389 // Only higher priority tasks need to be fired to redraw the window
390 // so skip firing potentially long-running tasks, such as the Writer
391 // idle layout timer, when a window is in live resize
392 if ( nTaskPriority == static_cast<int>(TaskPriority::LOWEST) && ( ImplGetSVData()->mpWinData->mbIsLiveResize || ImplGetSVData()->mpWinData->mbIsWaitingForNativeEvent ) )
393 continue;
395 pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
396 pPrevSchedulerData = nullptr;
397 while (pSchedulerData)
399 ++nTasks;
400 const Timer *timer = dynamic_cast<Timer*>( pSchedulerData->mpTask );
401 if ( timer )
402 SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
403 << pSchedulerData << " " << *pSchedulerData << " " << *timer );
404 else if ( pSchedulerData->mpTask )
405 SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
406 << pSchedulerData << " " << *pSchedulerData
407 << " " << *pSchedulerData->mpTask );
408 else
409 SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
410 << pSchedulerData << " " << *pSchedulerData << " (to be deleted)" );
412 // Should the Task be released from scheduling?
413 assert(!pSchedulerData->mbInScheduler);
414 if (!pSchedulerData->mpTask || !pSchedulerData->mpTask->IsActive())
416 ImplSchedulerData * const pSchedulerDataNext =
417 DropSchedulerData(rSchedCtx, pPrevSchedulerData, pSchedulerData, nTaskPriority);
418 if ( pSchedulerData->mpTask )
419 pSchedulerData->mpTask->mpSchedulerData = nullptr;
420 delete pSchedulerData;
421 pSchedulerData = pSchedulerDataNext;
422 continue;
425 assert(pSchedulerData->mpTask);
426 if (pSchedulerData->mpTask->IsActive())
428 nReadyPeriod = pSchedulerData->mpTask->UpdateMinPeriod( nTime );
429 if (ImmediateTimeoutMs == nReadyPeriod)
431 if (!pMostUrgent)
433 pPrevMostUrgent = pPrevSchedulerData;
434 pMostUrgent = pSchedulerData;
435 nMostUrgentPriority = nTaskPriority;
437 else
439 nMinPeriod = ImmediateTimeoutMs;
440 break;
443 else if (nMinPeriod > nReadyPeriod)
444 nMinPeriod = nReadyPeriod;
447 pPrevSchedulerData = pSchedulerData;
448 pSchedulerData = pSchedulerData->mpNext;
451 if (ImmediateTimeoutMs == nMinPeriod)
452 break;
455 if (InfiniteTimeoutMs != nMinPeriod)
456 SAL_INFO("vcl.schedule",
457 "Calculated minimum timeout as " << nMinPeriod << " of " << nTasks << " tasks");
458 UpdateSystemTimer(rSchedCtx, nMinPeriod, true, nTime);
460 if ( !pMostUrgent )
461 return;
463 SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
464 << pMostUrgent << " invoke-in " << *pMostUrgent->mpTask );
466 Task *pTask = pMostUrgent->mpTask;
468 comphelper::ProfileZone aZone( pTask->GetDebugName() );
470 assert(!pMostUrgent->mbInScheduler);
471 pMostUrgent->mbInScheduler = true;
473 // always push the stack, as we don't traverse the whole list to push later
474 DropSchedulerData(rSchedCtx, pPrevMostUrgent, pMostUrgent, nMostUrgentPriority);
475 pMostUrgent->mpNext = rSchedCtx.mpSchedulerStack;
476 rSchedCtx.mpSchedulerStack = pMostUrgent;
477 rSchedCtx.mpSchedulerStackTop = pMostUrgent;
479 bool bIsHighPriorityIdle = pMostUrgent->mePriority >= TaskPriority::HIGH_IDLE;
481 // invoke the task
482 Unlock();
484 // Delay invoking tasks with idle priorities as long as there are user input or repaint events
485 // in the OS event queue. This will often effectively compress such events and repaint only
486 // once at the end, improving performance in cases such as repeated zooming with a complex document.
487 bool bDelayInvoking
488 = bIsHighPriorityIdle
489 && (rSchedCtx.mnIdlesLockCount > 0
490 || Application::AnyInput(VclInputFlags::MOUSE | VclInputFlags::KEYBOARD | VclInputFlags::PAINT));
493 * Current policy is that scheduler tasks aren't allowed to throw an exception.
494 * Because otherwise the exception is caught somewhere totally unrelated.
495 * TODO Ideally we could capture a proper backtrace and feed this into breakpad,
496 * which is do-able, but requires writing some assembly.
497 * See also SalUserEventList::DispatchUserEvents
501 if (bDelayInvoking)
502 SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
503 << " idle priority task " << pTask->GetDebugName()
504 << " delayed, system events pending" );
505 else
507 // prepare Scheduler object for deletion after handling
508 pTask->SetDeletionFlags();
509 pTask->Invoke();
512 catch (css::uno::Exception&)
514 TOOLS_WARN_EXCEPTION("vcl.schedule", "Uncaught");
515 std::abort();
517 catch (std::exception& e)
519 SAL_WARN("vcl.schedule", "Uncaught " << typeid(e).name() << " " << e.what());
520 std::abort();
522 catch (...)
524 SAL_WARN("vcl.schedule", "Uncaught exception during Task::Invoke()!");
525 std::abort();
527 Lock();
529 assert(pMostUrgent->mbInScheduler);
530 pMostUrgent->mbInScheduler = false;
532 SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
533 << pMostUrgent << " invoke-out" );
535 // pop the scheduler stack
536 pSchedulerData = rSchedCtx.mpSchedulerStack;
537 assert(pSchedulerData == pMostUrgent);
538 rSchedCtx.mpSchedulerStack = pSchedulerData->mpNext;
540 // coverity[check_after_deref : FALSE] - pMostUrgent->mpTask is initially pMostUrgent->mpTask, but Task::Invoke can clear it
541 const bool bTaskAlive = pMostUrgent->mpTask && pMostUrgent->mpTask->IsActive();
542 if (!bTaskAlive)
544 if (pMostUrgent->mpTask)
545 pMostUrgent->mpTask->mpSchedulerData = nullptr;
546 delete pMostUrgent;
548 else
549 AppendSchedulerData(rSchedCtx, pMostUrgent);
551 // this just happens for nested calls, which renders all accounting
552 // invalid, so we just enforce a rescheduling!
553 if (rSchedCtx.mpSchedulerStackTop != pSchedulerData)
555 UpdateSystemTimer( rSchedCtx, ImmediateTimeoutMs, true,
556 tools::Time::GetSystemTicks() );
558 else if (bTaskAlive)
560 pMostUrgent->mnUpdateTime = nTime;
561 nReadyPeriod = pMostUrgent->mpTask->UpdateMinPeriod( nTime );
562 if ( nMinPeriod > nReadyPeriod )
563 nMinPeriod = nReadyPeriod;
564 UpdateSystemTimer( rSchedCtx, nMinPeriod, false, nTime );
568 void Scheduler::Wakeup()
570 Scheduler::ImplStartTimer( 0, false, tools::Time::GetSystemTicks() );
573 void Task::StartTimer( sal_uInt64 nMS )
575 Scheduler::ImplStartTimer( nMS, false, tools::Time::GetSystemTicks() );
578 void Task::SetDeletionFlags()
580 mbActive = false;
583 void Task::Start(const bool bStartTimer)
585 ImplSVData *const pSVData = ImplGetSVData();
586 ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
588 SchedulerGuard aSchedulerGuard;
589 if ( !rSchedCtx.mbActive )
590 return;
592 // is the task scheduled in the correct priority queue?
593 // if not we have to get a new data object, as we don't want to traverse
594 // the whole list to move the data to the correct list, as the task list
595 // is just single linked.
596 // Task priority doesn't change that often AFAIK, or we might need to
597 // start caching ImplSchedulerData objects.
598 if (mpSchedulerData && mpSchedulerData->mePriority != mePriority)
600 mpSchedulerData->mpTask = nullptr;
601 mpSchedulerData = nullptr;
603 mbActive = true;
605 if ( !mpSchedulerData )
607 // insert Task
608 ImplSchedulerData* pSchedulerData = new ImplSchedulerData;
609 pSchedulerData->mpTask = this;
610 pSchedulerData->mbInScheduler = false;
611 // mePriority is set in AppendSchedulerData
612 mpSchedulerData = pSchedulerData;
614 AppendSchedulerData( rSchedCtx, pSchedulerData );
615 SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
616 << " " << mpSchedulerData << " added " << *this );
618 else
619 SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
620 << " " << mpSchedulerData << " restarted " << *this );
622 mpSchedulerData->mnUpdateTime = tools::Time::GetSystemTicks();
624 if (bStartTimer)
625 Task::StartTimer(0);
628 void Task::Stop()
630 SAL_INFO_IF( mbActive, "vcl.schedule", tools::Time::GetSystemTicks()
631 << " " << mpSchedulerData << " stopped " << *this );
632 mbActive = false;
635 void Task::SetPriority(TaskPriority ePriority)
637 // you don't actually need to call Stop() before but Start() after, but we
638 // can't check that and don't know when Start() should be called.
639 SAL_WARN_IF(mpSchedulerData && mbActive, "vcl.schedule",
640 "Stop the task before changing the priority, as it will just "
641 "change after the task was scheduled with the old prio!");
642 mePriority = ePriority;
645 Task& Task::operator=( const Task& rTask )
647 if(this == &rTask)
648 return *this;
650 if ( IsActive() )
651 Stop();
653 mbActive = false;
654 mePriority = rTask.mePriority;
656 if ( rTask.IsActive() )
657 Start();
659 return *this;
662 Task::Task( const char *pDebugName )
663 : mpSchedulerData( nullptr )
664 , mpDebugName( pDebugName )
665 , mePriority( TaskPriority::DEFAULT )
666 , mbActive( false )
667 , mbStatic( false )
669 assert(mpDebugName);
672 Task::Task( const Task& rTask )
673 : mpSchedulerData( nullptr )
674 , mpDebugName( rTask.mpDebugName )
675 , mePriority( rTask.mePriority )
676 , mbActive( false )
677 , mbStatic( false )
679 assert(mpDebugName);
680 if ( rTask.IsActive() )
681 Start();
684 Task::~Task() COVERITY_NOEXCEPT_FALSE
686 if ( !IsStatic() )
688 SchedulerGuard aSchedulerGuard;
689 if ( mpSchedulerData )
690 mpSchedulerData->mpTask = nullptr;
692 else
693 assert(nullptr == mpSchedulerData || comphelper::IsFuzzing());
696 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */