1
mirror of https://github.com/flipperdevices/flipperzero-firmware.git synced 2025-12-12 04:41:26 +04:00

Furi: A Lot of Fixes (#3942)

- BT Service: cleanup code
- Dialog: correct release order in file browser
- Rpc: rollback to pre #3881 state
- Kernel: fix inverted behavior in furi_kernel_is_running
- Log: properly take mutex when kernel is not running
- Thread: rework tread control block scrubbing procedure, ensure that we don't do stupid things in idle task, add new priority for init task
- Timer: add control queue flush method, force flush on stop
- Furi: system init task now performs thread scrubbing
- BleGlue: add some extra checks
- FreeRTOSConfig: fix bunch of issues that were preventing configuration from being properly applied and cleanup
This commit is contained in:
あく
2024-10-14 14:39:09 +01:00
committed by GitHub
parent 344118c346
commit 5190aace88
19 changed files with 204 additions and 122 deletions

View File

@@ -33,7 +33,7 @@ bool furi_kernel_is_irq_or_masked(void) {
}
bool furi_kernel_is_running(void) {
return xTaskGetSchedulerState() != taskSCHEDULER_RUNNING;
return xTaskGetSchedulerState() == taskSCHEDULER_RUNNING;
}
int32_t furi_kernel_lock(void) {
@@ -129,6 +129,8 @@ uint32_t furi_kernel_get_tick_frequency(void) {
void furi_delay_tick(uint32_t ticks) {
furi_check(!furi_kernel_is_irq_or_masked());
furi_check(furi_thread_get_current_id() != xTaskGetIdleTaskHandle());
if(ticks == 0U) {
taskYIELD();
} else {
@@ -138,6 +140,7 @@ void furi_delay_tick(uint32_t ticks) {
FuriStatus furi_delay_until_tick(uint32_t tick) {
furi_check(!furi_kernel_is_irq_or_masked());
furi_check(furi_thread_get_current_id() != xTaskGetIdleTaskHandle());
TickType_t tcnt, delay;
FuriStatus stat;

View File

@@ -108,10 +108,17 @@ void furi_log_puts(const char* data) {
}
void furi_log_print_format(FuriLogLevel level, const char* tag, const char* format, ...) {
if(level <= furi_log.log_level &&
furi_mutex_acquire(furi_log.mutex, FuriWaitForever) == FuriStatusOk) {
FuriString* string;
string = furi_string_alloc();
do {
if(level > furi_log.log_level) {
break;
}
if(furi_mutex_acquire(furi_log.mutex, furi_kernel_is_running() ? FuriWaitForever : 0) !=
FuriStatusOk) {
break;
}
FuriString* string = furi_string_alloc();
const char* color = _FURI_LOG_CLR_RESET;
const char* log_letter = " ";
@@ -157,7 +164,7 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form
furi_log_puts("\r\n");
furi_mutex_release(furi_log.mutex);
}
} while(0);
}
void furi_log_print_raw_format(FuriLogLevel level, const char* format, ...) {

View File

@@ -1,6 +1,7 @@
#include "thread.h"
#include "thread_i.h"
#include "thread_list_i.h"
#include "kernel.h"
#include "message_queue.h"
#include "memmgr.h"
#include "memmgr_heap.h"
#include "check.h"
@@ -67,6 +68,8 @@ static_assert(offsetof(FuriThread, container) == 0);
// Our idle priority should be equal to the one from FreeRTOS
static_assert(FuriThreadPriorityIdle == tskIDLE_PRIORITY);
static FuriMessageQueue* furi_thread_scrub_message_queue = NULL;
static size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, size_t size);
static int32_t __furi_thread_stdout_flush(FuriThread* thread);
@@ -125,7 +128,9 @@ static void furi_thread_body(void* context) {
furi_thread_set_state(thread, FuriThreadStateStopping);
vTaskDelete(NULL);
furi_message_queue_put(furi_thread_scrub_message_queue, &thread, FuriWaitForever);
vTaskSuspend(NULL);
furi_thread_catch();
}
@@ -159,6 +164,31 @@ static void furi_thread_init_common(FuriThread* thread) {
}
}
void furi_thread_init(void) {
furi_thread_scrub_message_queue = furi_message_queue_alloc(8, sizeof(FuriThread*));
}
void furi_thread_scrub(void) {
FuriThread* thread_to_scrub = NULL;
while(true) {
furi_check(
furi_message_queue_get(
furi_thread_scrub_message_queue, &thread_to_scrub, FuriWaitForever) ==
FuriStatusOk);
TaskHandle_t task = (TaskHandle_t)thread_to_scrub;
// Delete task: FreeRTOS will remove task from all lists where it may be
vTaskDelete(task);
// Sanity check: ensure that local storage is ours and clear it
furi_check(pvTaskGetThreadLocalStoragePointer(task, 0) == thread_to_scrub);
vTaskSetThreadLocalStoragePointer(task, 0, NULL);
// Deliver thread stopped callback
furi_thread_set_state(thread_to_scrub, FuriThreadStateStopped);
}
}
FuriThread* furi_thread_alloc(void) {
FuriThread* thread = malloc(sizeof(FuriThread));
@@ -358,16 +388,6 @@ void furi_thread_start(FuriThread* thread) {
&thread->container) == (TaskHandle_t)thread);
}
void furi_thread_cleanup_tcb_event(TaskHandle_t task) {
FuriThread* thread = pvTaskGetThreadLocalStoragePointer(task, 0);
if(thread) {
// clear thread local storage
vTaskSetThreadLocalStoragePointer(task, 0, NULL);
furi_check(thread == (FuriThread*)task);
furi_thread_set_state(thread, FuriThreadStateStopped);
}
}
bool furi_thread_join(FuriThread* thread) {
furi_check(thread);
// Cannot join a service thread

View File

@@ -21,10 +21,10 @@ extern "C" {
* Many of the FuriThread functions MUST ONLY be called when the thread is STOPPED.
*/
typedef enum {
FuriThreadStateStopped, /**< Thread is stopped and is safe to release */
FuriThreadStateStopping, /**< Thread is stopping */
FuriThreadStateStarting, /**< Thread is starting */
FuriThreadStateRunning, /**< Thread is running */
FuriThreadStateStopped, /**< Thread is stopped and is safe to release. Event delivered from system init thread(TCB cleanup routine). It is safe to release thread instance. */
FuriThreadStateStopping, /**< Thread is stopping. Event delivered from child thread. */
FuriThreadStateStarting, /**< Thread is starting. Event delivered from parent(self) thread. */
FuriThreadStateRunning, /**< Thread is running. Event delivered from child thread. */
} FuriThreadState;
/**
@@ -32,6 +32,7 @@ typedef enum {
*/
typedef enum {
FuriThreadPriorityIdle = 0, /**< Idle priority */
FuriThreadPriorityInit = 4, /**< Init System Thread Priority */
FuriThreadPriorityLowest = 14, /**< Lowest */
FuriThreadPriorityLow = 15, /**< Low */
FuriThreadPriorityNormal = 16, /**< Normal, system default */
@@ -77,13 +78,15 @@ typedef int32_t (*FuriThreadCallback)(void* context);
typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size);
/**
* @brief State change callback function pointer type.
* @brief State change callback function pointer type.
*
* The function to be used as a state callback MUST follow this signature.
* The function to be used as a state callback MUST follow this
* signature.
*
* @param[in] pointer to the FuriThread instance that changed the state
* @param[in] state identifier of the state the thread has transitioned to
* @param[in,out] context pointer to a user-specified object
* @param[in] thread to the FuriThread instance that changed the state
* @param[in] state identifier of the state the thread has transitioned
* to
* @param[in,out] context pointer to a user-specified object
*/
typedef void (*FuriThreadStateCallback)(FuriThread* thread, FuriThreadState state, void* context);

7
furi/core/thread_i.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include "thread.h"
void furi_thread_init(void);
void furi_thread_scrub(void);

View File

@@ -17,12 +17,24 @@ static_assert(offsetof(FuriTimer, container) == 0);
#define TIMER_DELETED_EVENT (1U << 0)
static void TimerCallback(TimerHandle_t hTimer) {
static void furi_timer_callback(TimerHandle_t hTimer) {
FuriTimer* instance = pvTimerGetTimerID(hTimer);
furi_check(instance);
instance->cb_func(instance->cb_context);
}
static void furi_timer_flush_epilogue(void* context, uint32_t arg) {
furi_assert(context);
UNUSED(arg);
EventGroupHandle_t hEvent = context;
// See https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/1142
vTaskSuspendAll();
xEventGroupSetBits(hEvent, TIMER_DELETED_EVENT);
(void)xTaskResumeAll();
}
FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* context) {
furi_check((furi_kernel_is_irq_or_masked() == 0U) && (func != NULL));
@@ -33,23 +45,13 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co
const UBaseType_t reload = (type == FuriTimerTypeOnce ? pdFALSE : pdTRUE);
const TimerHandle_t hTimer = xTimerCreateStatic(
NULL, portMAX_DELAY, reload, instance, TimerCallback, &instance->container);
NULL, portMAX_DELAY, reload, instance, furi_timer_callback, &instance->container);
furi_check(hTimer == (TimerHandle_t)instance);
return instance;
}
static void furi_timer_epilogue(void* context, uint32_t arg) {
furi_assert(context);
UNUSED(arg);
EventGroupHandle_t hEvent = context;
vTaskSuspendAll();
xEventGroupSetBits(hEvent, TIMER_DELETED_EVENT);
(void)xTaskResumeAll();
}
void furi_timer_free(FuriTimer* instance) {
furi_check(!furi_kernel_is_irq_or_masked());
furi_check(instance);
@@ -57,16 +59,21 @@ void furi_timer_free(FuriTimer* instance) {
TimerHandle_t hTimer = (TimerHandle_t)instance;
furi_check(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS);
furi_timer_flush();
free(instance);
}
void furi_timer_flush(void) {
StaticEventGroup_t event_container = {};
EventGroupHandle_t hEvent = xEventGroupCreateStatic(&event_container);
furi_check(xTimerPendFunctionCall(furi_timer_epilogue, hEvent, 0, portMAX_DELAY) == pdPASS);
furi_check(
xTimerPendFunctionCall(furi_timer_flush_epilogue, hEvent, 0, portMAX_DELAY) == pdPASS);
furi_check(
xEventGroupWaitBits(hEvent, TIMER_DELETED_EVENT, pdFALSE, pdTRUE, portMAX_DELAY) ==
TIMER_DELETED_EVENT);
vEventGroupDelete(hEvent);
free(instance);
}
FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) {
@@ -112,6 +119,8 @@ FuriStatus furi_timer_stop(FuriTimer* instance) {
furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS);
furi_timer_flush();
return FuriStatusOk;
}

View File

@@ -35,6 +35,12 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co
*/
void furi_timer_free(FuriTimer* instance);
/** Flush timer task control message queue
*
* Ensures that all commands before this point was processed.
*/
void furi_timer_flush(void);
/** Start timer
*
* @warning This is asynchronous call, real operation will happen as soon as
@@ -61,8 +67,7 @@ FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks);
/** Stop timer
*
* @warning This is asynchronous call, real operation will happen as soon as
* timer service process this request.
* @warning This is synchronous call that will be blocked till timer queue processed.
*
* @param instance The pointer to FuriTimer instance
*

View File

@@ -1,5 +1,7 @@
#include "furi.h"
#include "core/thread_i.h"
#include <FreeRTOS.h>
#include <queue.h>
@@ -7,6 +9,7 @@ void furi_init(void) {
furi_check(!furi_kernel_is_irq_or_masked());
furi_check(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED);
furi_thread_init();
furi_log_init();
furi_record_init();
}
@@ -18,3 +21,7 @@ void furi_run(void) {
/* Start the kernel scheduler */
vTaskStartScheduler();
}
void furi_background(void) {
furi_thread_scrub();
}

View File

@@ -35,6 +35,8 @@ void furi_init(void);
void furi_run(void);
void furi_background(void);
#ifdef __cplusplus
}
#endif