bump product version to 6.4.0.3
[LibreOffice.git] / vcl / source / app / scheduler.cxx
blob7081383545ec777302b2370b8b52b958400408ea
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 <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>
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 sal_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 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;
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 the sfx::SfxItemDisruptor_Impl Idles
127 ProcessEventsToIdle();
128 #endif
129 rSchedCtx.mbActive = false;
131 assert( nullptr == rSchedCtx.mpSchedulerStack );
132 assert( 1 == rSchedCtx.maMutex.lockDepth() );
134 if (rSchedCtx.mpSalTimer) rSchedCtx.mpSalTimer->Stop();
135 DELETEZ( rSchedCtx.mpSalTimer );
137 #if OSL_DEBUG_LEVEL > 0
138 sal_uInt32 nActiveTasks = 0, nIgnoredTasks = 0;
139 #endif
140 nTaskPriority = 0;
141 ImplSchedulerData* pSchedulerData = nullptr;
143 next_priority:
144 pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
145 while ( pSchedulerData )
147 Task *pTask = pSchedulerData->mpTask;
148 if ( pTask )
150 if ( pTask->mbActive )
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" )
170 sIgnored = " (ignored)";
171 ++nIgnoredTasks;
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;
181 pTask->mpSchedulerData = nullptr;
182 pTask->SetStatic();
184 ImplSchedulerData* pDeleteSchedulerData = pSchedulerData;
185 pSchedulerData = pSchedulerData->mpNext;
186 delete pDeleteSchedulerData;
189 ++nTaskPriority;
190 if (nTaskPriority < PRIO_COUNT)
191 goto next_priority;
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
200 for (nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
202 rSchedCtx.mpFirstSchedulerData[nTaskPriority] = nullptr;
203 rSchedCtx.mpLastSchedulerData[nTaskPriority] = nullptr;
205 rSchedCtx.mnTimerPeriod = InfiniteTimeoutMs;
208 void SchedulerMutex::acquire( sal_uInt32 nLockCount )
210 assert(nLockCount > 0);
211 for (sal_uInt32 i = 0; i != nLockCount; ++i) {
212 if (!maMutex.acquire())
213 abort();
215 mnLockDepth += nLockCount;
218 sal_uInt32 SchedulerMutex::release( bool bUnlockAll )
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();
228 return nLockCount;
231 void Scheduler::Lock( sal_uInt32 nLockCount )
233 ImplSVData* pSVData = ImplGetSVData();
234 assert( pSVData != nullptr );
235 pSVData->maSchedCtx.maMutex.acquire( nLockCount );
238 sal_uInt32 Scheduler::Unlock( bool bUnlockAll )
240 ImplSVData* pSVData = ImplGetSVData();
241 assert( pSVData != nullptr );
242 return pSVData->maSchedCtx.maMutex.release( bUnlockAll );
246 * Start a new timer if we need to for nMS duration.
248 * if this is longer than the existing duration we're
249 * waiting for, do nothing - unless bForce - which means
250 * to reset the minimum period; used by the scheduled itself.
252 void Scheduler::ImplStartTimer(sal_uInt64 nMS, bool bForce, sal_uInt64 nTime)
254 ImplSVData* pSVData = ImplGetSVData();
255 ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
256 if ( !rSchedCtx.mbActive )
257 return;
259 if (!rSchedCtx.mpSalTimer)
261 rSchedCtx.mnTimerStart = 0;
262 rSchedCtx.mnTimerPeriod = InfiniteTimeoutMs;
263 rSchedCtx.mpSalTimer = pSVData->mpDefInst->CreateSalTimer();
264 rSchedCtx.mpSalTimer->SetCallback(Scheduler::CallbackTaskScheduling);
267 assert(SAL_MAX_UINT64 - nMS >= nTime);
269 sal_uInt64 nProposedTimeout = nTime + nMS;
270 sal_uInt64 nCurTimeout = ( rSchedCtx.mnTimerPeriod == InfiniteTimeoutMs )
271 ? SAL_MAX_UINT64 : rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod;
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))
277 SAL_INFO( "vcl.schedule", " Starting scheduler system timer (" << nMS << "ms)" );
278 rSchedCtx.mnTimerStart = nTime;
279 rSchedCtx.mnTimerPeriod = nMS;
280 rSchedCtx.mpSalTimer->Start( nMS );
284 void Scheduler::CallbackTaskScheduling()
286 // this function is for the saltimer callback
287 Scheduler::ProcessTaskScheduling();
290 static bool g_bDeterministicMode = false;
292 void Scheduler::SetDeterministicMode(bool bDeterministic)
294 g_bDeterministicMode = bDeterministic;
297 bool Scheduler::GetDeterministicMode()
299 return g_bDeterministicMode;
302 inline void Scheduler::UpdateSystemTimer( ImplSchedulerContext &rSchedCtx,
303 const sal_uInt64 nMinPeriod,
304 const bool bForce, const sal_uInt64 nTime )
306 if ( InfiniteTimeoutMs == nMinPeriod )
308 SAL_INFO("vcl.schedule", " Stopping system timer");
309 if ( rSchedCtx.mpSalTimer )
310 rSchedCtx.mpSalTimer->Stop();
311 rSchedCtx.mnTimerPeriod = nMinPeriod;
313 else
314 Scheduler::ImplStartTimer( nMinPeriod, bForce, nTime );
317 static void AppendSchedulerData( ImplSchedulerContext &rSchedCtx,
318 ImplSchedulerData * const pSchedulerData)
320 assert(pSchedulerData->mpTask);
321 pSchedulerData->mePriority = pSchedulerData->mpTask->GetPriority();
322 pSchedulerData->mpNext = nullptr;
324 const int nTaskPriority = static_cast<int>(pSchedulerData->mePriority);
325 if (!rSchedCtx.mpLastSchedulerData[nTaskPriority])
327 rSchedCtx.mpFirstSchedulerData[nTaskPriority] = pSchedulerData;
328 rSchedCtx.mpLastSchedulerData[nTaskPriority] = pSchedulerData;
330 else
332 rSchedCtx.mpLastSchedulerData[nTaskPriority]->mpNext = pSchedulerData;
333 rSchedCtx.mpLastSchedulerData[nTaskPriority] = pSchedulerData;
337 static ImplSchedulerData* DropSchedulerData(
338 ImplSchedulerContext &rSchedCtx, ImplSchedulerData * const pPrevSchedulerData,
339 const ImplSchedulerData * const pSchedulerData, const int nTaskPriority)
341 assert( pSchedulerData );
342 if ( pPrevSchedulerData )
343 assert( pPrevSchedulerData->mpNext == pSchedulerData );
344 else
345 assert(rSchedCtx.mpFirstSchedulerData[nTaskPriority] == pSchedulerData);
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;
357 bool Scheduler::ProcessTaskScheduling()
359 ImplSVData *pSVData = ImplGetSVData();
360 ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
362 DBG_TESTSOLARMUTEX();
364 SchedulerGuard aSchedulerGuard;
365 if ( !rSchedCtx.mbActive || InfiniteTimeoutMs == rSchedCtx.mnTimerPeriod )
366 return false;
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)
372 int nSleep = rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod - nTime;
373 UpdateSystemTimer(rSchedCtx, nSleep, true, nTime);
374 return false;
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;
387 for (; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
389 pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
390 pPrevSchedulerData = nullptr;
391 while (pSchedulerData)
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)" );
406 // Should the Task be released from scheduling?
407 assert(!pSchedulerData->mbInScheduler);
408 if (!pSchedulerData->mpTask || !pSchedulerData->mpTask->IsActive())
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;
419 assert(pSchedulerData->mpTask);
420 if (pSchedulerData->mpTask->IsActive())
422 nReadyPeriod = pSchedulerData->mpTask->UpdateMinPeriod( nTime );
423 if (ImmediateTimeoutMs == nReadyPeriod)
425 if (!pMostUrgent)
427 pPrevMostUrgent = pPrevSchedulerData;
428 pMostUrgent = pSchedulerData;
429 nMostUrgentPriority = nTaskPriority;
431 else
433 nMinPeriod = ImmediateTimeoutMs;
434 break;
437 else if (nMinPeriod > nReadyPeriod)
438 nMinPeriod = nReadyPeriod;
441 pPrevSchedulerData = pSchedulerData;
442 pSchedulerData = pSchedulerData->mpNext;
445 if (ImmediateTimeoutMs == nMinPeriod)
446 break;
449 if ( InfiniteTimeoutMs != nMinPeriod )
450 SAL_INFO("vcl.schedule", "Calculated minimum timeout as " << nMinPeriod
451 << " of " << nTasks << " tasks" );
452 UpdateSystemTimer( rSchedCtx, nMinPeriod, true, nTime );
454 if ( pMostUrgent )
456 SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
457 << pMostUrgent << " invoke-in " << *pMostUrgent->mpTask );
459 Task *pTask = pMostUrgent->mpTask;
461 comphelper::ProfileZone aZone( pTask->GetDebugName() );
463 // prepare Scheduler object for deletion after handling
464 pTask->SetDeletionFlags();
466 pMostUrgent->mbInScheduler = true;
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;
474 // invoke the task
475 sal_uInt32 nLockCount = Unlock( true );
478 pTask->Invoke();
480 catch (css::uno::Exception&)
482 TOOLS_WARN_EXCEPTION("vcl.schedule", "Uncaught");
483 std::abort();
485 catch (std::exception& e)
487 SAL_WARN("vcl.schedule", "Uncaught " << typeid(e).name() << " " << e.what());
488 std::abort();
490 catch (...)
492 SAL_WARN("vcl.schedule", "Uncaught exception during Task::Invoke()!");
493 std::abort();
495 Lock( nLockCount );
496 pMostUrgent->mbInScheduler = false;
498 SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
499 << pMostUrgent << " invoke-out" );
501 // pop the scheduler stack
502 pSchedulerData = rSchedCtx.mpSchedulerStack;
503 assert(pSchedulerData == pMostUrgent);
504 rSchedCtx.mpSchedulerStack = pSchedulerData->mpNext;
506 const bool bTaskAlive = pMostUrgent->mpTask && pMostUrgent->mpTask->IsActive();
507 if (!bTaskAlive)
509 if (pMostUrgent->mpTask)
510 pMostUrgent->mpTask->mpSchedulerData = nullptr;
511 delete pMostUrgent;
513 else
514 AppendSchedulerData(rSchedCtx, pMostUrgent);
516 // this just happens for nested calls, which renders all accounting
517 // invalid, so we just enforce a rescheduling!
518 if (rSchedCtx.mpSchedulerStackTop != pSchedulerData)
520 UpdateSystemTimer( rSchedCtx, ImmediateTimeoutMs, true,
521 tools::Time::GetSystemTicks() );
523 else if (bTaskAlive)
525 pMostUrgent->mnUpdateTime = nTime;
526 nReadyPeriod = pMostUrgent->mpTask->UpdateMinPeriod( nTime );
527 if ( nMinPeriod > nReadyPeriod )
528 nMinPeriod = nReadyPeriod;
529 UpdateSystemTimer( rSchedCtx, nMinPeriod, false, nTime );
533 return !!pMostUrgent;
536 void Scheduler::Wakeup()
538 Scheduler::ImplStartTimer( 0, false, tools::Time::GetSystemTicks() );
541 void Task::StartTimer( sal_uInt64 nMS )
543 Scheduler::ImplStartTimer( nMS, false, tools::Time::GetSystemTicks() );
546 void Task::SetDeletionFlags()
548 mbActive = false;
551 void Task::Start()
553 ImplSVData *const pSVData = ImplGetSVData();
554 ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
556 SchedulerGuard aSchedulerGuard;
557 if ( !rSchedCtx.mbActive )
558 return;
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.
566 if (mpSchedulerData && mpSchedulerData->mePriority != mePriority)
568 mpSchedulerData->mpTask = nullptr;
569 mpSchedulerData = nullptr;
571 mbActive = true;
573 if ( !mpSchedulerData )
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;
582 AppendSchedulerData( rSchedCtx, pSchedulerData );
583 SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
584 << " " << mpSchedulerData << " added " << *this );
586 else
587 SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
588 << " " << mpSchedulerData << " restarted " << *this );
590 mpSchedulerData->mnUpdateTime = tools::Time::GetSystemTicks();
593 void Task::Stop()
595 SAL_INFO_IF( mbActive, "vcl.schedule", tools::Time::GetSystemTicks()
596 << " " << mpSchedulerData << " stopped " << *this );
597 mbActive = false;
600 void Task::SetPriority(TaskPriority ePriority)
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;
610 Task& Task::operator=( const Task& rTask )
612 if(this == &rTask)
613 return *this;
615 if ( IsActive() )
616 Stop();
618 mbActive = false;
619 mePriority = rTask.mePriority;
621 if ( rTask.IsActive() )
622 Start();
624 return *this;
627 Task::Task( const sal_Char *pDebugName )
628 : mpSchedulerData( nullptr )
629 , mpDebugName( pDebugName )
630 , mePriority( TaskPriority::DEFAULT )
631 , mbActive( false )
632 , mbStatic( false )
636 Task::Task( const Task& rTask )
637 : mpSchedulerData( nullptr )
638 , mpDebugName( rTask.mpDebugName )
639 , mePriority( rTask.mePriority )
640 , mbActive( false )
641 , mbStatic( false )
643 if ( rTask.IsActive() )
644 Start();
647 Task::~Task() COVERITY_NOEXCEPT_FALSE
649 if ( !IsStatic() )
651 SchedulerGuard aSchedulerGuard;
652 if ( mpSchedulerData )
653 mpSchedulerData->mpTask = nullptr;
655 else
656 assert(nullptr == mpSchedulerData || utl::ConfigManager::IsFuzzing());
659 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */