From 0bd8cbcc9ec1810fe6a4248984144948ef8e132a Mon Sep 17 00:00:00 2001 From: Liam <30486941+liamHowatt@users.noreply.github.com> Date: Mon, 26 Aug 2024 10:17:12 -0400 Subject: [PATCH] fix(freertos): notifiy-based sync can be initialized from any task (#6692) --- src/osal/lv_freertos.c | 104 +++++++++++++++++++++++++++-------------- src/osal/lv_freertos.h | 10 ++-- 2 files changed, 75 insertions(+), 39 deletions(-) diff --git a/src/osal/lv_freertos.c b/src/osal/lv_freertos.c index 33fd5f6e0..1c81a8e05 100644 --- a/src/osal/lv_freertos.c +++ b/src/osal/lv_freertos.c @@ -50,11 +50,11 @@ static void prvMutexInit(lv_mutex_t * pxMutex); static void prvCheckMutexInit(lv_mutex_t * pxMutex); -#if !USE_FREERTOS_TASK_NOTIFY static void prvCondInit(lv_thread_sync_t * pxCond); static void prvCheckCondInit(lv_thread_sync_t * pxCond); +#if !USE_FREERTOS_TASK_NOTIFY static void prvTestAndDecrement(lv_thread_sync_t * pxCond, uint32_t ulLocalWaitingThreads); #endif @@ -87,7 +87,7 @@ lv_result_t lv_thread_init(lv_thread_t * pxThread, lv_thread_prio_t xSchedPriori void (*pvStartRoutine)(void *), size_t usStackSize, void * xAttr) { - pxThread->xTaskArg = xAttr; + pxThread->pTaskArg = xAttr; pxThread->pvStartRoutine = pvStartRoutine; BaseType_t xTaskCreateStatus = xTaskCreate( @@ -182,13 +182,8 @@ lv_result_t lv_mutex_delete(lv_mutex_t * pxMutex) lv_result_t lv_thread_sync_init(lv_thread_sync_t * pxCond) { -#if USE_FREERTOS_TASK_NOTIFY - /* Store the handle of the calling task. */ - pxCond->xTaskToNotify = xTaskGetCurrentTaskHandle(); -#else /* If the cond is uninitialized, perform initialization. */ prvCheckCondInit(pxCond); -#endif return LV_RESULT_OK; } @@ -197,17 +192,30 @@ lv_result_t lv_thread_sync_wait(lv_thread_sync_t * pxCond) { lv_result_t lvRes = LV_RESULT_OK; -#if USE_FREERTOS_TASK_NOTIFY - LV_UNUSED(pxCond); - - /* Wait for other task to notify this task. */ - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); -#else - uint32_t ulLocalWaitingThreads; - /* If the cond is uninitialized, perform initialization. */ prvCheckCondInit(pxCond); +#if USE_FREERTOS_TASK_NOTIFY + TaskHandle_t current_task_handle = xTaskGetCurrentTaskHandle(); + + _enter_critical(); + BaseType_t signal_sent = pxCond->xSyncSignal; + pxCond->xSyncSignal = pdFALSE; + if(signal_sent == pdFALSE) { + /* The signal hasn't been sent yet. Tell the sender to notify this task */ + pxCond->xTaskToNotify = current_task_handle; + } + /* If we have a signal from the other task, we should not ask to be notified */ + _exit_critical(); + + if(signal_sent == pdFALSE) { + /* Wait for other task to notify this task. */ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + } + /* If the signal was received, no wait needs to be done */ +#else + uint32_t ulLocalWaitingThreads; + /* Acquire the mutex. */ xSemaphoreTake(pxCond->xSyncMutex, portMAX_DELAY); @@ -264,13 +272,26 @@ lv_result_t lv_thread_sync_wait(lv_thread_sync_t * pxCond) lv_result_t lv_thread_sync_signal(lv_thread_sync_t * pxCond) { -#if USE_FREERTOS_TASK_NOTIFY - /* Send a notification to the task waiting. */ - xTaskNotifyGive(pxCond->xTaskToNotify); -#else /* If the cond is uninitialized, perform initialization. */ prvCheckCondInit(pxCond); +#if USE_FREERTOS_TASK_NOTIFY + _enter_critical(); + TaskHandle_t task_to_notify = pxCond->xTaskToNotify; + pxCond->xTaskToNotify = NULL; + if(task_to_notify == NULL) { + /* No task waiting to be notified. Send this signal for later */ + pxCond->xSyncSignal = pdTRUE; + } + /* If a task is already waiting, there is no need to set the sync signal */ + _exit_critical(); + + if(task_to_notify != NULL) { + /* There is a task waiting. Send a notification to it */ + xTaskNotifyGive(task_to_notify); + } + /* If there was no task waiting to be notified, we sent a signal for it to see later. */ +#else /* Acquire the mutex. */ xSemaphoreTake(pxCond->xSyncMutex, portMAX_DELAY); @@ -308,16 +329,14 @@ lv_result_t lv_thread_sync_signal(lv_thread_sync_t * pxCond) lv_result_t lv_thread_sync_delete(lv_thread_sync_t * pxCond) { -#if USE_FREERTOS_TASK_NOTIFY - LV_UNUSED(pxCond); -#else +#if !USE_FREERTOS_TASK_NOTIFY /* Cleanup all resources used by the cond. */ vSemaphoreDelete(pxCond->xCondWaitSemaphore); vSemaphoreDelete(pxCond->xSyncMutex); pxCond->ulWaitingThreads = 0; pxCond->xSyncSignal = pdFALSE; - pxCond->xIsInitialized = pdFALSE; #endif + pxCond->xIsInitialized = pdFALSE; return LV_RESULT_OK; } @@ -325,14 +344,28 @@ lv_result_t lv_thread_sync_delete(lv_thread_sync_t * pxCond) lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * pxCond) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; -#if USE_FREERTOS_TASK_NOTIFY - /* Send a notification to the task waiting. */ - vTaskNotifyGiveFromISR(pxCond->xTaskToNotify, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -#else + /* If the cond is uninitialized, perform initialization. */ prvCheckCondInit(pxCond); +#if USE_FREERTOS_TASK_NOTIFY + _enter_critical(); + TaskHandle_t task_to_notify = pxCond->xTaskToNotify; + pxCond->xTaskToNotify = NULL; + if(task_to_notify == NULL) { + /* No task waiting to be notified. Send this signal for later */ + pxCond->xSyncSignal = pdTRUE; + } + /* If a task is already waiting, there is no need to set the sync signal */ + _exit_critical(); + + if(task_to_notify != NULL) { + /* There is a task waiting. Send a notification to it */ + vTaskNotifyGiveFromISR(task_to_notify, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + } + /* If there was no task waiting to be notified, we sent a signal for it to see later. */ +#else /* Enter critical section to prevent preemption. */ _enter_critical(); @@ -393,7 +426,7 @@ static void prvRunThread(void * pxArg) lv_thread_t * pxThread = (lv_thread_t *)pxArg; /* Run the thread routine. */ - pxThread->pvStartRoutine((void *)pxThread->xTaskArg); + pxThread->pvStartRoutine((void *)pxThread->pTaskArg); vTaskDelete(NULL); } @@ -432,9 +465,14 @@ static void prvCheckMutexInit(lv_mutex_t * pxMutex) } } -#if !USE_FREERTOS_TASK_NOTIFY static void prvCondInit(lv_thread_sync_t * pxCond) { + pxCond->xIsInitialized = pdTRUE; + pxCond->xSyncSignal = pdFALSE; + +#if USE_FREERTOS_TASK_NOTIFY + pxCond->xTaskToNotify = NULL; +#else pxCond->xCondWaitSemaphore = xSemaphoreCreateCounting(ulMAX_COUNT, 0U); /* Ensure that the FreeRTOS semaphore was successfully created. */ @@ -455,14 +493,11 @@ static void prvCondInit(lv_thread_sync_t * pxCond) /* Condition variable successfully created. */ pxCond->ulWaitingThreads = 0; - pxCond->xSyncSignal = pdFALSE; - pxCond->xIsInitialized = pdTRUE; +#endif } static void prvCheckCondInit(lv_thread_sync_t * pxCond) { - BaseType_t xSemCreateStatus = pdTRUE; - /* Check if the condition variable needs to be initialized. */ if(pxCond->xIsInitialized == pdFALSE) { /* Cond initialization must be in a critical section to prevent two @@ -481,6 +516,7 @@ static void prvCheckCondInit(lv_thread_sync_t * pxCond) } } +#if !USE_FREERTOS_TASK_NOTIFY static void prvTestAndDecrement(lv_thread_sync_t * pxCond, uint32_t ulLocalWaitingThreads) { diff --git a/src/osal/lv_freertos.h b/src/osal/lv_freertos.h index 5de9a95a8..2e2384d37 100644 --- a/src/osal/lv_freertos.h +++ b/src/osal/lv_freertos.h @@ -51,7 +51,7 @@ extern "C" { typedef struct { void (*pvStartRoutine)(void *); /**< Application thread function. */ - void * xTaskArg; /**< Arguments for application thread function. */ + void * pTaskArg; /**< Arguments for application thread function. */ TaskHandle_t xTaskHandle; /**< FreeRTOS task handle. */ } lv_thread_t; @@ -61,15 +61,15 @@ typedef struct { } lv_mutex_t; typedef struct { -#if USE_FREERTOS_TASK_NOTIFY - TaskHandle_t xTaskToNotify; -#else BaseType_t xIsInitialized; /**< Set to pdTRUE if this condition variable is initialized, pdFALSE otherwise. */ + BaseType_t xSyncSignal; /**< Set to pdTRUE if the thread is signaled, pdFALSE otherwise. */ +#if USE_FREERTOS_TASK_NOTIFY + TaskHandle_t xTaskToNotify; /**< The task waiting to be signalled. NULL if nothing is waiting. */ +#else SemaphoreHandle_t xCondWaitSemaphore; /**< Threads block on this semaphore in lv_thread_sync_wait. */ uint32_t ulWaitingThreads; /**< The number of threads currently waiting on this condition variable. */ SemaphoreHandle_t xSyncMutex; /**< Threads take this mutex before accessing the condition variable. */ - BaseType_t xSyncSignal; /**< Set to pdTRUE if the thread is signaled, pdFALSE otherwise. */ #endif } lv_thread_sync_t;