mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-04 02:50:58 +02:00
freertos: Fix event group task list race condition
FreeRTOS synchronization primitives (e.g., queues, eventgroups) use various event lists (i.e., task lists) to track what tasks are blocked on a current primitive. Usually these event lists are accessed via one of the event lists functions (such as vTask[PlaceOn|RemoveFrom]UnorderedEventList()), which in turn ensure that the global task list spinlock (xTaskQueueMutex) is taken when accessing these lists. However, some functions in event_groups.c manually traverse their event lists. Thus if a tick interrupt occurs on another core during traversal and that tick interrupt unblocks a task on the event list being traversed, the event list will be corrupted. This commit modifies the following event_groups.c functions so that they take the global task list lock before traversing their event list. - xEventGroupSetBits() - vEventGroupDelete()
This commit is contained in:
@@ -565,6 +565,10 @@ BaseType_t xMatchFound = pdFALSE;
|
||||
|
||||
vTaskSuspendAll();
|
||||
taskENTER_CRITICAL(&pxEventBits->eventGroupMux);
|
||||
/* The critical section above only takes the event groups spinlock. However, we are about to traverse a task list.
|
||||
Thus we need call the function below to take the task list spinlock located in tasks.c. Not doing so will risk
|
||||
the task list's being changed while be are traversing it. */
|
||||
vTaskTakeEventListLock();
|
||||
{
|
||||
traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );
|
||||
|
||||
@@ -636,6 +640,8 @@ BaseType_t xMatchFound = pdFALSE;
|
||||
bit was set in the control word. */
|
||||
pxEventBits->uxEventBits &= ~uxBitsToClear;
|
||||
}
|
||||
/* Release the previously held task list spinlock, then release the event group spinlock. */
|
||||
vTaskReleaseEventListLock();
|
||||
taskEXIT_CRITICAL(&pxEventBits->eventGroupMux);
|
||||
( void ) xTaskResumeAll();
|
||||
|
||||
@@ -650,6 +656,10 @@ void vEventGroupDelete( EventGroupHandle_t xEventGroup )
|
||||
|
||||
vTaskSuspendAll();
|
||||
taskENTER_CRITICAL( &pxEventBits->eventGroupMux );
|
||||
/* The critical section above only takes the event groups spinlock. However, we are about to traverse a task list.
|
||||
Thus we need call the function below to take the task list spinlock located in tasks.c. Not doing so will risk
|
||||
the task list's being changed while be are traversing it. */
|
||||
vTaskTakeEventListLock();
|
||||
{
|
||||
traceEVENT_GROUP_DELETE( xEventGroup );
|
||||
|
||||
@@ -661,6 +671,9 @@ void vEventGroupDelete( EventGroupHandle_t xEventGroup )
|
||||
( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
|
||||
}
|
||||
|
||||
/* Release the previously held task list spinlock. */
|
||||
vTaskReleaseEventListLock();
|
||||
|
||||
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
|
||||
{
|
||||
/* The event group can only have been allocated dynamically - free
|
||||
|
Reference in New Issue
Block a user