mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'bugfix/spi_flash_deadlock' into 'master'
spi_flash: raise priority of the task performing spi_flash operation See merge request idf/esp-idf!2609
This commit is contained in:
commit
59c96ae331
@ -110,6 +110,10 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu()
|
||||
assert(other_cpuid == 1);
|
||||
spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]);
|
||||
} else {
|
||||
// Temporarily raise current task priority to prevent a deadlock while
|
||||
// waiting for IPC task to start on the other CPU
|
||||
int old_prio = uxTaskPriorityGet(NULL);
|
||||
vTaskPrioritySet(NULL, configMAX_PRIORITIES - 1);
|
||||
// Signal to the spi_flash_op_block_task on the other CPU that we need it to
|
||||
// disable cache there and block other tasks from executing.
|
||||
s_flash_op_can_start = false;
|
||||
@ -121,6 +125,8 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu()
|
||||
}
|
||||
// Disable scheduler on the current CPU
|
||||
vTaskSuspendAll();
|
||||
// Can now set the priority back to the normal one
|
||||
vTaskPrioritySet(NULL, old_prio);
|
||||
// This is guaranteed to run on CPU <cpuid> because the other CPU is now
|
||||
// occupied by highest priority task
|
||||
assert(xPortGetCoreID() == cpuid);
|
||||
|
@ -167,3 +167,61 @@ TEST_CASE("spi flash functions can run along with IRAM interrupts", "[spi_flash]
|
||||
free(read_arg.buf);
|
||||
}
|
||||
|
||||
|
||||
#if portNUM_PROCESSORS > 1
|
||||
TEST_CASE("spi_flash deadlock with high priority busy-waiting task", "[spi_flash]")
|
||||
{
|
||||
typedef struct {
|
||||
QueueHandle_t queue;
|
||||
volatile bool done;
|
||||
} deadlock_test_arg_t;
|
||||
|
||||
/* Create two tasks: high-priority consumer on CPU0, low-priority producer on CPU1.
|
||||
* Consumer polls the queue until it gets some data, then yields.
|
||||
* Run flash operation on CPU0. Check that when IPC1 task blocks out the producer,
|
||||
* the task which does flash operation does not get blocked by the consumer.
|
||||
*/
|
||||
|
||||
void producer_task(void* varg)
|
||||
{
|
||||
int dummy = 0;
|
||||
deadlock_test_arg_t* arg = (deadlock_test_arg_t*) varg;
|
||||
while (!arg->done) {
|
||||
xQueueSend(arg->queue, &dummy, 0);
|
||||
vTaskDelay(1);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void consumer_task(void* varg)
|
||||
{
|
||||
int dummy;
|
||||
deadlock_test_arg_t* arg = (deadlock_test_arg_t*) varg;
|
||||
while (!arg->done) {
|
||||
if (xQueueReceive(arg->queue, &dummy, 0) == pdTRUE) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
deadlock_test_arg_t arg = {
|
||||
.queue = xQueueCreate(32, sizeof(int)),
|
||||
.done = false
|
||||
};
|
||||
|
||||
TEST_ASSERT(xTaskCreatePinnedToCore(&producer_task, "producer", 4096, &arg, 5, NULL, 1));
|
||||
TEST_ASSERT(xTaskCreatePinnedToCore(&consumer_task, "consumer", 4096, &arg, 10, NULL, 0));
|
||||
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
uint32_t dummy;
|
||||
TEST_ESP_OK(spi_flash_read(0, &dummy, sizeof(dummy)));
|
||||
}
|
||||
|
||||
arg.done = true;
|
||||
vTaskDelay(5);
|
||||
vQueueDelete(arg.queue);
|
||||
|
||||
/* Check that current task priority is still correct */
|
||||
TEST_ASSERT_EQUAL_INT(uxTaskPriorityGet(NULL), UNITY_FREERTOS_PRIORITY);
|
||||
}
|
||||
#endif // portNUM_PROCESSORS > 1
|
||||
|
Loading…
Reference in New Issue
Block a user