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:
parent
3e62c2e052
commit
353e81da63
2 changed files with 64 additions and 6 deletions
|
@ -3039,7 +3039,7 @@ BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )
|
|||
TCB_t *pxUnblockedTCB;
|
||||
BaseType_t xReturn;
|
||||
BaseType_t xTaskCanBeReady;
|
||||
UBaseType_t i;
|
||||
UBaseType_t i, uxTargetCPU;
|
||||
|
||||
/* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be
|
||||
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. */
|
||||
xTaskCanBeReady = pdFALSE;
|
||||
if ( pxUnblockedTCB->xCoreID == tskNO_AFFINITY ) {
|
||||
uxTargetCPU = xPortGetCoreID();
|
||||
for (i = 0; i < portNUM_PROCESSORS; i++) {
|
||||
if ( uxSchedulerSuspended[ i ] == ( UBaseType_t ) pdFALSE ) {
|
||||
xTaskCanBeReady = pdTRUE;
|
||||
|
@ -3074,7 +3075,9 @@ UBaseType_t i;
|
|||
}
|
||||
}
|
||||
} else {
|
||||
xTaskCanBeReady = uxSchedulerSuspended[ pxUnblockedTCB->xCoreID ] == ( UBaseType_t ) pdFALSE;
|
||||
uxTargetCPU = pxUnblockedTCB->xCoreID;
|
||||
xTaskCanBeReady = uxSchedulerSuspended[ uxTargetCPU ] == ( UBaseType_t ) pdFALSE;
|
||||
|
||||
}
|
||||
|
||||
if( xTaskCanBeReady )
|
||||
|
@ -3086,7 +3089,7 @@ UBaseType_t i;
|
|||
{
|
||||
/* The delayed and ready lists cannot be accessed, so hold this task
|
||||
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 )
|
||||
|
|
|
@ -49,7 +49,7 @@ static void counter_task_fn(void *vp_config)
|
|||
|
||||
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_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
|
||||
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
|
||||
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 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
|
||||
|
|
Loading…
Reference in a new issue