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
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); static void prvCheckMutexInit(lv_mutex_t * pxMutex);
#if !USE_FREERTOS_TASK_NOTIFY
static void prvCondInit(lv_thread_sync_t * pxCond); static void prvCondInit(lv_thread_sync_t * pxCond);
static void prvCheckCondInit(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, static void prvTestAndDecrement(lv_thread_sync_t * pxCond,
uint32_t ulLocalWaitingThreads); uint32_t ulLocalWaitingThreads);
#endif #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 (*pvStartRoutine)(void *), size_t usStackSize,
void * xAttr) void * xAttr)
{ {
pxThread->xTaskArg = xAttr; pxThread->pTaskArg = xAttr;
pxThread->pvStartRoutine = pvStartRoutine; pxThread->pvStartRoutine = pvStartRoutine;
BaseType_t xTaskCreateStatus = xTaskCreate( 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) 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. */ /* If the cond is uninitialized, perform initialization. */
prvCheckCondInit(pxCond); prvCheckCondInit(pxCond);
#endif
return LV_RESULT_OK; 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; 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. */ /* If the cond is uninitialized, perform initialization. */
prvCheckCondInit(pxCond); 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. */ /* Acquire the mutex. */
xSemaphoreTake(pxCond->xSyncMutex, portMAX_DELAY); 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) 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. */ /* If the cond is uninitialized, perform initialization. */
prvCheckCondInit(pxCond); 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. */ /* Acquire the mutex. */
xSemaphoreTake(pxCond->xSyncMutex, portMAX_DELAY); 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) lv_result_t lv_thread_sync_delete(lv_thread_sync_t * pxCond)
{ {
#if USE_FREERTOS_TASK_NOTIFY #if !USE_FREERTOS_TASK_NOTIFY
LV_UNUSED(pxCond);
#else
/* Cleanup all resources used by the cond. */ /* Cleanup all resources used by the cond. */
vSemaphoreDelete(pxCond->xCondWaitSemaphore); vSemaphoreDelete(pxCond->xCondWaitSemaphore);
vSemaphoreDelete(pxCond->xSyncMutex); vSemaphoreDelete(pxCond->xSyncMutex);
pxCond->ulWaitingThreads = 0; pxCond->ulWaitingThreads = 0;
pxCond->xSyncSignal = pdFALSE; pxCond->xSyncSignal = pdFALSE;
pxCond->xIsInitialized = pdFALSE;
#endif #endif
pxCond->xIsInitialized = pdFALSE;
return LV_RESULT_OK; 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) lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * pxCond)
{ {
BaseType_t xHigherPriorityTaskWoken = pdFALSE; 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. */ /* If the cond is uninitialized, perform initialization. */
prvCheckCondInit(pxCond); 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 section to prevent preemption. */
_enter_critical(); _enter_critical();
@@ -393,7 +426,7 @@ static void prvRunThread(void * pxArg)
lv_thread_t * pxThread = (lv_thread_t *)pxArg; lv_thread_t * pxThread = (lv_thread_t *)pxArg;
/* Run the thread routine. */ /* Run the thread routine. */
pxThread->pvStartRoutine((void *)pxThread->xTaskArg); pxThread->pvStartRoutine((void *)pxThread->pTaskArg);
vTaskDelete(NULL); 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) 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); pxCond->xCondWaitSemaphore = xSemaphoreCreateCounting(ulMAX_COUNT, 0U);
/* Ensure that the FreeRTOS semaphore was successfully created. */ /* Ensure that the FreeRTOS semaphore was successfully created. */
@@ -455,14 +493,11 @@ static void prvCondInit(lv_thread_sync_t * pxCond)
/* Condition variable successfully created. */ /* Condition variable successfully created. */
pxCond->ulWaitingThreads = 0; pxCond->ulWaitingThreads = 0;
pxCond->xSyncSignal = pdFALSE; #endif
pxCond->xIsInitialized = pdTRUE;
} }
static void prvCheckCondInit(lv_thread_sync_t * pxCond) static void prvCheckCondInit(lv_thread_sync_t * pxCond)
{ {
BaseType_t xSemCreateStatus = pdTRUE;
/* Check if the condition variable needs to be initialized. */ /* Check if the condition variable needs to be initialized. */
if(pxCond->xIsInitialized == pdFALSE) { if(pxCond->xIsInitialized == pdFALSE) {
/* Cond initialization must be in a critical section to prevent two /* 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, static void prvTestAndDecrement(lv_thread_sync_t * pxCond,
uint32_t ulLocalWaitingThreads) uint32_t ulLocalWaitingThreads)
{ {

View File

@@ -51,7 +51,7 @@ extern "C" {
typedef struct { typedef struct {
void (*pvStartRoutine)(void *); /**< Application thread function. */ 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. */ TaskHandle_t xTaskHandle; /**< FreeRTOS task handle. */
} lv_thread_t; } lv_thread_t;
@@ -61,15 +61,15 @@ typedef struct {
} lv_mutex_t; } lv_mutex_t;
typedef struct { typedef struct {
#if USE_FREERTOS_TASK_NOTIFY
TaskHandle_t xTaskToNotify;
#else
BaseType_t BaseType_t
xIsInitialized; /**< Set to pdTRUE if this condition variable is initialized, pdFALSE otherwise. */ 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. */ 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. */ 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. */ 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 #endif
} lv_thread_sync_t; } lv_thread_sync_t;