1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-14 06:42:58 +08:00

fix(freertos): notifiy-based sync can be initialized from any task (#6692)

This commit is contained in:
Liam 2024-08-26 10:17:12 -04:00 committed by GitHub
parent c46f6b0a41
commit 0bd8cbcc9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 75 additions and 39 deletions

View File

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

View File

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