mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 04:04:31 +02:00
freertos: Also test (& handle) the case where scheduler is disabled on other CPU...
ie CPU A has scheduler disabled and task blocked on Q. CPU B sends to Q (or gives mutex, etc.) Task on CPU A should be woken on scheduler resume.
This commit is contained in:
committed by
Angus Gratton
parent
3e62c2e052
commit
353e81da63
@@ -3039,7 +3039,7 @@ BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )
|
|||||||
TCB_t *pxUnblockedTCB;
|
TCB_t *pxUnblockedTCB;
|
||||||
BaseType_t xReturn;
|
BaseType_t xReturn;
|
||||||
BaseType_t xTaskCanBeReady;
|
BaseType_t xTaskCanBeReady;
|
||||||
UBaseType_t i;
|
UBaseType_t i, uxTargetCPU;
|
||||||
|
|
||||||
/* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be
|
/* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be
|
||||||
called from a critical section within an ISR. */
|
called from a critical section within an ISR. */
|
||||||
@@ -3067,6 +3067,7 @@ UBaseType_t i;
|
|||||||
the task is pinned to is running or because a scheduler is running on any CPU. */
|
the task is pinned to is running or because a scheduler is running on any CPU. */
|
||||||
xTaskCanBeReady = pdFALSE;
|
xTaskCanBeReady = pdFALSE;
|
||||||
if ( pxUnblockedTCB->xCoreID == tskNO_AFFINITY ) {
|
if ( pxUnblockedTCB->xCoreID == tskNO_AFFINITY ) {
|
||||||
|
uxTargetCPU = xPortGetCoreID();
|
||||||
for (i = 0; i < portNUM_PROCESSORS; i++) {
|
for (i = 0; i < portNUM_PROCESSORS; i++) {
|
||||||
if ( uxSchedulerSuspended[ i ] == ( UBaseType_t ) pdFALSE ) {
|
if ( uxSchedulerSuspended[ i ] == ( UBaseType_t ) pdFALSE ) {
|
||||||
xTaskCanBeReady = pdTRUE;
|
xTaskCanBeReady = pdTRUE;
|
||||||
@@ -3074,7 +3075,9 @@ UBaseType_t i;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
xTaskCanBeReady = uxSchedulerSuspended[ pxUnblockedTCB->xCoreID ] == ( UBaseType_t ) pdFALSE;
|
uxTargetCPU = pxUnblockedTCB->xCoreID;
|
||||||
|
xTaskCanBeReady = uxSchedulerSuspended[ uxTargetCPU ] == ( UBaseType_t ) pdFALSE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( xTaskCanBeReady )
|
if( xTaskCanBeReady )
|
||||||
@@ -3086,7 +3089,7 @@ UBaseType_t i;
|
|||||||
{
|
{
|
||||||
/* The delayed and ready lists cannot be accessed, so hold this task
|
/* The delayed and ready lists cannot be accessed, so hold this task
|
||||||
pending until the scheduler is resumed on this CPU. */
|
pending until the scheduler is resumed on this CPU. */
|
||||||
vListInsertEnd( &( xPendingReadyList[ xPortGetCoreID() ] ), &( pxUnblockedTCB->xEventListItem ) );
|
vListInsertEnd( &( xPendingReadyList[ uxTargetCPU ] ), &( pxUnblockedTCB->xEventListItem ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( tskCAN_RUN_HERE(pxUnblockedTCB->xCoreID) && pxUnblockedTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
|
if ( tskCAN_RUN_HERE(pxUnblockedTCB->xCoreID) && pxUnblockedTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
|
||||||
|
@@ -49,7 +49,7 @@ static void counter_task_fn(void *vp_config)
|
|||||||
|
|
||||||
In the FreeRTOS implementation, this exercises the xPendingReadyList for that core.
|
In the FreeRTOS implementation, this exercises the xPendingReadyList for that core.
|
||||||
*/
|
*/
|
||||||
TEST_CASE("Handle pending context switch while scheduler disabled", "[freertos]")
|
TEST_CASE("Scheduler disabled can handle a pending context switch on resume", "[freertos]")
|
||||||
{
|
{
|
||||||
isr_count = 0;
|
isr_count = 0;
|
||||||
isr_semaphore = xSemaphoreCreateMutex();
|
isr_semaphore = xSemaphoreCreateMutex();
|
||||||
@@ -122,7 +122,7 @@ TEST_CASE("Handle pending context switch while scheduler disabled", "[freertos]"
|
|||||||
while scheduler is suspended, and should be started once the scheduler
|
while scheduler is suspended, and should be started once the scheduler
|
||||||
resumes.
|
resumes.
|
||||||
*/
|
*/
|
||||||
TEST_CASE("Handle waking multiple tasks while scheduler suspended", "[freertos]")
|
TEST_CASE("Scheduler disabled can wake multiple tasks on resume", "[freertos]")
|
||||||
{
|
{
|
||||||
#define TASKS_PER_PROC 4
|
#define TASKS_PER_PROC 4
|
||||||
TaskHandle_t tasks[portNUM_PROCESSORS][TASKS_PER_PROC] = { 0 };
|
TaskHandle_t tasks[portNUM_PROCESSORS][TASKS_PER_PROC] = { 0 };
|
||||||
@@ -163,7 +163,7 @@ TEST_CASE("Handle waking multiple tasks while scheduler suspended", "[freertos]"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ets_delay_us(1000); /* Let the other CPU do some things */
|
ets_delay_us(200); /* Let the other CPU do some things */
|
||||||
|
|
||||||
for (int p = 0; p < portNUM_PROCESSORS; p++) {
|
for (int p = 0; p < portNUM_PROCESSORS; p++) {
|
||||||
for (int t = 0; t < TASKS_PER_PROC; t++) {
|
for (int t = 0; t < TASKS_PER_PROC; t++) {
|
||||||
@@ -192,3 +192,58 @@ TEST_CASE("Handle waking multiple tasks while scheduler suspended", "[freertos]"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static volatile bool sched_suspended;
|
||||||
|
static void suspend_scheduler_5ms_task_fn(void *ignore)
|
||||||
|
{
|
||||||
|
vTaskSuspendAll();
|
||||||
|
sched_suspended = true;
|
||||||
|
for (int i = 0; i <5; i++) {
|
||||||
|
ets_delay_us(1000);
|
||||||
|
}
|
||||||
|
xTaskResumeAll();
|
||||||
|
sched_suspended = false;
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_FREERTOS_UNICORE
|
||||||
|
/* If the scheduler is disabled on one CPU (A) with a task blocked on something, and a task
|
||||||
|
on B (where scheduler is running) wakes it, then the task on A should be woken on resume.
|
||||||
|
*/
|
||||||
|
TEST_CASE("Scheduler disabled on CPU B, tasks on A can wake", "[freertos]")
|
||||||
|
{
|
||||||
|
TaskHandle_t counter_task;
|
||||||
|
SemaphoreHandle_t wake_sem = xSemaphoreCreateMutex();
|
||||||
|
xSemaphoreTake(wake_sem, 0);
|
||||||
|
counter_config_t count_config = {
|
||||||
|
.trigger_sem = wake_sem,
|
||||||
|
.counter = 0,
|
||||||
|
};
|
||||||
|
xTaskCreatePinnedToCore(counter_task_fn, "counter", 2048,
|
||||||
|
&count_config, UNITY_FREERTOS_PRIORITY + 1,
|
||||||
|
&counter_task, !UNITY_FREERTOS_CPU);
|
||||||
|
|
||||||
|
xTaskCreatePinnedToCore(suspend_scheduler_5ms_task_fn, "suspender", 2048,
|
||||||
|
NULL, UNITY_FREERTOS_PRIORITY - 1,
|
||||||
|
NULL, !UNITY_FREERTOS_CPU);
|
||||||
|
|
||||||
|
/* counter task is now blocked on other CPU, waiting for wake_sem, and we expect
|
||||||
|
that this CPU's scheduler will be suspended for 5ms shortly... */
|
||||||
|
while(!sched_suspended) { }
|
||||||
|
|
||||||
|
xSemaphoreGive(wake_sem);
|
||||||
|
ets_delay_us(1000);
|
||||||
|
// Bit of a race here if the other CPU resumes its scheduler, but 5ms is a long time... */
|
||||||
|
TEST_ASSERT(sched_suspended);
|
||||||
|
TEST_ASSERT_EQUAL(0, count_config.counter); // the other task hasn't woken yet, because scheduler is off
|
||||||
|
TEST_ASSERT(sched_suspended);
|
||||||
|
|
||||||
|
/* wait for the rest of the 5ms... */
|
||||||
|
while(sched_suspended) { }
|
||||||
|
|
||||||
|
ets_delay_us(100);
|
||||||
|
TEST_ASSERT_EQUAL(1, count_config.counter); // when scheduler resumes, counter task should immediately count
|
||||||
|
|
||||||
|
vTaskDelete(counter_task);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Reference in New Issue
Block a user