Fixed race condition on task pool destruction sequence when a deferred job is scheduled.
@@ -289,6 +289,7 @@ IotTaskPoolError_t IotTaskPool_Destroy( IotTaskPool_t * pTaskPool )
TASKPOOL_FUNCTION_ENTRY( IOT_TASKPOOL_SUCCESS );
uint32_t count;
+ bool completeShutdown = true;
/* Track how many threads the task pool owns. */
uint32_t activeThreads;
@@ -328,21 +329,46 @@ IotTaskPoolError_t IotTaskPool_Destroy( IotTaskPool_t * pTaskPool )
} while( pItemLink );
/* (2) Clear the timer queue. */
- do
{
- pItemLink = NULL;
+ _taskPoolTimerEvent_t * pTimerEvent;
- pItemLink = IotListDouble_RemoveHead( &pTaskPool->timerEventsList );
+ /* A deferred job may have fired already. Since deferred jobs will go through the same mutex
+ * the shutdown sequence is holding at this stage, there is no risk for race conditions. Yet, we
+ * need to let the deferred job to destroy the task pool. */
+
+ pItemLink = IotListDouble_PeekHead( &pTaskPool->timerEventsList );
if( pItemLink != NULL )
{
- _taskPoolTimerEvent_t * pTimerEvent = IotLink_Container( _taskPoolTimerEvent_t, pItemLink, link );
+ uint64_t now = IotClock_GetTimeMs();
+
+ pTimerEvent = IotLink_Container( _taskPoolTimerEvent_t, pItemLink, link );
+
+ if( pTimerEvent->expirationTime <= now )
+ {
+ /* Timer may have fired already! Let the timer thread destroy
+ * complete the taskpool destruction sequence. */
+ completeShutdown = false;
+ }
+
+ /* Remove all timers from the timeout list. */
+ for( ; ; )
+ {
+ pItemLink = IotListDouble_RemoveHead( &pTaskPool->timerEventsList );
+
+ if( pItemLink == NULL )
+ {
+ break;
+ }
+
+ pTimerEvent = IotLink_Container( _taskPoolTimerEvent_t, pItemLink, link );
_destroyJob( pTimerEvent->pJob );
IotTaskPool_FreeTimerEvent( pTimerEvent );
}
- } while( pItemLink );
+ }
+ }
/* (3) Clear the job cache. */
do
@@ -374,7 +400,10 @@ IotTaskPoolError_t IotTaskPool_Destroy( IotTaskPool_t * pTaskPool )
IotTaskPool_Assert( pTaskPool->activeThreads == 0 );
/* (6) Destroy all signaling objects. */
+ if( completeShutdown == true )
+ {
_destroyTaskPool( pTaskPool );
+ }
TASKPOOL_NO_FUNCTION_CLEANUP();
}
@@ -1601,6 +1630,9 @@ static void _timerThread( void * pArgument )
{
TASKPOOL_EXIT_CRITICAL();
+ /* Complete the shutdown sequence. */
+ _destroyTaskPool( pTaskPool );
+
return;
}
