Merge branch 'bugfix/freertos_event_groups' into 'master'

FreeRTOS: Fix cross-core event group sync

As above

Also includes fixes which allowed removing some semi-hacky bits from the event group unit tests - specifically, higher priority tasks will always be started immediately even if they run on the opposite core.

See merge request !535
This commit is contained in:
Ivan Grokhotkov
2017-03-03 11:45:59 +08:00
4 changed files with 120 additions and 79 deletions
@@ -11,9 +11,10 @@
#define BIT_RESPONSE(TASK) (1 << (TASK+1))
#define ALL_RESPONSE_BITS (((1 << NUM_TASKS) - 1) << 1)
static const int NUM_TASKS = 4;
static const int COUNT = 4000;
static const int NUM_TASKS = 8;
static const int COUNT = 1000;
static EventGroupHandle_t eg;
static SemaphoreHandle_t done_sem;
static void task_event_group_call_response(void *param)
{
@@ -24,47 +25,51 @@ static void task_event_group_call_response(void *param)
for (int i = 0; i < COUNT; i++) {
/* Wait until the common "call" bit is set, starts off all tasks
(clear on return) */
while (!xEventGroupWaitBits(eg, BIT_CALL, true, false, portMAX_DELAY)) {
}
TEST_ASSERT( xEventGroupWaitBits(eg, BIT_CALL, true, false, portMAX_DELAY) );
/* Set our individual "response" bit */
xEventGroupSetBits(eg, BIT_RESPONSE(task_num));
}
printf("Task %d done\n", task_num);
/* Delay is due to not-yet-fixed bug with deleting tasks at same time */
vTaskDelay(100 / portTICK_PERIOD_MS);
xSemaphoreGive(done_sem);
vTaskDelete(NULL);
}
TEST_CASE("FreeRTOS Event Groups", "[freertos][ignore]")
TEST_CASE("FreeRTOS Event Groups", "[freertos]")
{
eg = xEventGroupCreate();
done_sem = xSemaphoreCreateCounting(NUM_TASKS, 0);
/* Note: task_event_group_call_response all have higher priority than us, so will block together.
/* Note: task_event_group_call_response all have higher priority than this task, so on this core
they will always preempt this task.
This is important because we need to know they'll all have blocked on BIT_CALL each time we
signal it, or they get out of sync.
This is important because we need to know all tasks have blocked on BIT_CALL each time we signal it,
or they get out of sync.
*/
for (int c = 0; c < NUM_TASKS; c++) {
xTaskCreatePinnedToCore(task_event_group_call_response, "tsk_call_resp", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS);
}
/* Scheduler weirdness, if we don't sleep a few ticks here then the tasks on the other CPU aren't running yet... */
vTaskDelay(10);
/* Tasks all start instantly, but this task will resume running at the same time as the higher priority tasks on the
other processor may still be setting up, so give a tick for them to also block on BIT_CALL... */
vTaskDelay(1);
for (int i = 0; i < COUNT; i++) {
if (i % 100 == 0) {
//printf("Call %d\n", i);
}
/* signal all tasks with "CALL" bit... */
xEventGroupSetBits(eg, BIT_CALL);
while (xEventGroupWaitBits(eg, ALL_RESPONSE_BITS, true, true, portMAX_DELAY) != ALL_RESPONSE_BITS) {
}
TEST_ASSERT_EQUAL_HEX16(ALL_RESPONSE_BITS, xEventGroupWaitBits(eg, ALL_RESPONSE_BITS, true, true, 100 / portMAX_DELAY));
}
}
/* Ensure all tasks cleaned up correctly */
for (int c = 0; c < NUM_TASKS; c++) {
TEST_ASSERT( xSemaphoreTake(done_sem, 100/portTICK_PERIOD_MS) );
}
vSemaphoreDelete(done_sem);
vEventGroupDelete(eg);
}
#define BIT_DONE(X) (1<<(NUM_TASKS+1+X))
@@ -82,24 +87,32 @@ static void task_test_sync(void *param)
}
int after_done = xEventGroupSetBits(eg, BIT_DONE(task_num));
printf("Done %d = %x\n", task_num, after_done);
printf("Done %d = 0x%08x\n", task_num, after_done);
/* Delay is due to not-yet-fixed bug with deleting tasks at same time */
vTaskDelay(100 / portTICK_PERIOD_MS);
xSemaphoreGive(done_sem);
vTaskDelete(NULL);
}
TEST_CASE("FreeRTOS Event Group Sync", "[freertos][ignore]")
TEST_CASE("FreeRTOS Event Group Sync", "[freertos]")
{
eg = xEventGroupCreate();
done_sem = xSemaphoreCreateCounting(NUM_TASKS, 0);
for (int c = 0; c < NUM_TASKS; c++) {
xTaskCreatePinnedToCore(task_test_sync, "task_test_sync", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS);
}
for (int c = 0; c < NUM_TASKS; c++) {
printf("Waiting on %d (%x)\n", c, BIT_DONE(c));
xEventGroupWaitBits(eg, BIT_DONE(c), false, false, portMAX_DELAY);
printf("Waiting on %d (0x%08x)\n", c, BIT_DONE(c));
TEST_ASSERT( xEventGroupWaitBits(eg, BIT_DONE(c), false, false, portMAX_DELAY) );
}
/* Ensure all tasks cleaned up correctly */
for (int c = 0; c < NUM_TASKS; c++) {
TEST_ASSERT( xSemaphoreTake(done_sem, 100/portTICK_PERIOD_MS) );
}
vSemaphoreDelete(done_sem);
vEventGroupDelete(eg);
}
@@ -10,13 +10,17 @@
static void task_delete_self(void *param)
{
printf("Task %p running on core %d. Deleting shortly...\n", xTaskGetCurrentTaskHandle(), xPortGetCoreID());
vTaskDelay(5);
vTaskDelete(NULL);
}
TEST_CASE("FreeRTOS Delete Tasks", "[freertos][ignore]")
TEST_CASE("FreeRTOS Delete Tasks", "[freertos]")
{
uint32_t before_count = uxTaskGetNumberOfTasks();
xTaskCreatePinnedToCore(task_delete_self, "tsk_self_a", 4096, NULL, configMAX_PRIORITIES - 1, NULL, 0);
xTaskCreatePinnedToCore(task_delete_self, "tsk_self_a", 4096, NULL, configMAX_PRIORITIES - 1, NULL, 0);
TEST_ASSERT_EQUAL(before_count + 2, uxTaskGetNumberOfTasks());
vTaskDelay(200 / portTICK_PERIOD_MS);
printf("Done?\n");
TEST_ASSERT_EQUAL(before_count, uxTaskGetNumberOfTasks());
}