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:
Angus Gratton 2017-09-28 12:08:34 +10:00 committed by Angus Gratton
parent 3e62c2e052
commit 353e81da63
2 changed files with 64 additions and 6 deletions

View file

@ -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 )

View file

@ -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