Workaround static Task destruction error

A task has to get the SchedulerLock to remove itself from the
Scheduler list. This doesn't work, if the Task is static, as the
static Scheduler might be destroyed earlier. In this case we fail
with the following backtrace:

 #0 SchedulerMutex::acquire
 #1 Task::~Task
 #2 __run_exit_handlers

Thanks to Michael Stahl to catching this backtrace.

As a workaround this marks static tasks, so they ignore the
SchedulerMutex in the destructor, We also mark all scheduled Tasks
as "static" in DeInitScheduler, as their cleanup was already done.

In the end all Tasks should be removed from static objects.

Change-Id: I38be3206378b9449193efaccbc96896ac8de9478
Reviewed-on: https://gerrit.libreoffice.org/42574
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de>
This commit is contained in:
Jan-Marek Glogowski 2017-08-23 16:07:50 +02:00
parent 1cfcbf3573
commit 06ce312f79
5 changed files with 30 additions and 4 deletions

View File

@ -47,6 +47,7 @@ class VCL_DLLPUBLIC Task
const sal_Char *mpDebugName; ///< Useful for debugging
TaskPriority mePriority; ///< Task priority
bool mbActive; ///< Currently in the scheduler
bool mbStatic; ///< Is a static object
protected:
static void StartTimer( sal_uInt64 nMS );
@ -88,6 +89,15 @@ public:
void Stop();
bool IsActive() const { return mbActive; }
/**
* This function must be called for static tasks, so the Task destructor
* ignores the SchedulerMutex, as it may not be available anymore.
* The cleanup is still correct, as it has already happened in
* DeInitScheduler call well before the static destructor calls.
*/
void SetStatic() { mbStatic = true; }
bool IsStatic() const { return mbStatic; }
};
#endif // INCLUDED_VCL_TASK_HXX

View File

@ -112,6 +112,7 @@ OLEObjCache::OLEObjCache()
pTimer = new AutoTimer( "svx OLEObjCache pTimer UnloadCheck" );
pTimer->SetInvokeHandler( LINK(this, OLEObjCache, UnloadCheckHdl) );
pTimer->SetTimeout(20000);
pTimer->SetStatic();
}
OLEObjCache::~OLEObjCache()

View File

@ -172,6 +172,13 @@ Since the Scheduler is always handled by the system message queue, there is
really no more reasoning to stop after 100 events to prevent LO Scheduler
starvation.
== Drop static inherited or composed Task objects ==
The sequence of destruction of static objects is not defined. So a static Task
can not be guaranteed to happen before the Scheduler. When dynamic unloading
is involved, this becomes an even worse problem. This way we could drop the
mbStatic workaround from the Task class.
== Run the LO application in its own thread ==
This would probably get rid of most of the MacOS and Windows implementation

View File

@ -160,6 +160,7 @@ void Scheduler::ImplDeInitScheduler()
pTask->mbActive = false;
}
pTask->mpSchedulerData = nullptr;
pTask->SetStatic();
}
ImplSchedulerData* pDeleteSchedulerData = pSchedulerData;
pSchedulerData = pSchedulerData->mpNext;
@ -548,6 +549,7 @@ Task::Task( const sal_Char *pDebugName )
, mpDebugName( pDebugName )
, mePriority( TaskPriority::DEFAULT )
, mbActive( false )
, mbStatic( false )
{
}
@ -556,16 +558,22 @@ Task::Task( const Task& rTask )
, mpDebugName( rTask.mpDebugName )
, mePriority( rTask.mePriority )
, mbActive( false )
, mbStatic( false )
{
if ( rTask.IsActive() )
Start();
}
Task::~Task() COVERITY_NOEXCEPT_FALSE
{
if ( !IsStatic() )
{
SchedulerGuard aSchedulerGuard;
if ( mpSchedulerData )
mpSchedulerData->mpTask = nullptr;
}
else
assert( nullptr == mpSchedulerData );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -80,7 +80,7 @@ public:
maEntries()
{
SetTimeout(1000);
Stop();
SetStatic();
}
~GdiPlusBuffer() override