mirror of
https://github.com/flipperdevices/flipperzero-firmware.git
synced 2025-12-12 04:41:26 +04:00
Threading, Timers improvements (#3865)
* FuriTimer: Use a local variable to wait for deletion This combines the current synchronous behaviour (as we could have deferred the free call too) with a smaller FuriTimer - it's safe to pass a pointer to a local variable to this pending timer call, because we know it'll be finished before the caller returns * Tighten the use of FuriThread* vs FuriThreadId Event loop and Loader mixed those two, but the fact those are aliases should be an implementation detail. For this reason, thread.c is still allowed to mix them freely.
This commit is contained in:
@@ -717,7 +717,7 @@ static bool loader_do_signal(Loader* loader, uint32_t signal, void* arg) {
|
|||||||
|
|
||||||
static bool loader_do_get_application_name(Loader* loader, FuriString* name) {
|
static bool loader_do_get_application_name(Loader* loader, FuriString* name) {
|
||||||
if(loader_is_application_running(loader)) {
|
if(loader_is_application_running(loader)) {
|
||||||
furi_string_set(name, furi_thread_get_name(loader->app.thread));
|
furi_string_set(name, furi_thread_get_name(furi_thread_get_id(loader->app.thread)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ FuriEventLoop* furi_event_loop_alloc(void) {
|
|||||||
PendingQueue_init(instance->pending_queue);
|
PendingQueue_init(instance->pending_queue);
|
||||||
|
|
||||||
// Clear notification state and value
|
// Clear notification state and value
|
||||||
xTaskNotifyStateClearIndexed(instance->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX);
|
TaskHandle_t task = (TaskHandle_t)instance->thread_id;
|
||||||
ulTaskNotifyValueClearIndexed(
|
xTaskNotifyStateClearIndexed(task, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX);
|
||||||
instance->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, 0xFFFFFFFF);
|
ulTaskNotifyValueClearIndexed(task, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, 0xFFFFFFFF);
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ static void furi_event_loop_process_waiting_list(FuriEventLoop* instance) {
|
|||||||
static void furi_event_loop_restore_flags(FuriEventLoop* instance, uint32_t flags) {
|
static void furi_event_loop_restore_flags(FuriEventLoop* instance, uint32_t flags) {
|
||||||
if(flags) {
|
if(flags) {
|
||||||
xTaskNotifyIndexed(
|
xTaskNotifyIndexed(
|
||||||
instance->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, flags, eSetBits);
|
(TaskHandle_t)instance->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, flags, eSetBits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,10 +186,11 @@ void furi_event_loop_run(FuriEventLoop* instance) {
|
|||||||
furi_check(instance);
|
furi_check(instance);
|
||||||
furi_check(instance->thread_id == furi_thread_get_current_id());
|
furi_check(instance->thread_id == furi_thread_get_current_id());
|
||||||
|
|
||||||
|
FuriThread* thread = furi_thread_get_current();
|
||||||
|
|
||||||
// Set the default signal callback if none was previously set
|
// Set the default signal callback if none was previously set
|
||||||
if(furi_thread_get_signal_callback(instance->thread_id) == NULL) {
|
if(furi_thread_get_signal_callback(thread) == NULL) {
|
||||||
furi_thread_set_signal_callback(
|
furi_thread_set_signal_callback(thread, furi_event_loop_signal_callback, instance);
|
||||||
instance->thread_id, furi_event_loop_signal_callback, instance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_event_loop_init_tick(instance);
|
furi_event_loop_init_tick(instance);
|
||||||
@@ -233,8 +234,8 @@ void furi_event_loop_run(FuriEventLoop* instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Disable the default signal callback
|
// Disable the default signal callback
|
||||||
if(furi_thread_get_signal_callback(instance->thread_id) == furi_event_loop_signal_callback) {
|
if(furi_thread_get_signal_callback(thread) == furi_event_loop_signal_callback) {
|
||||||
furi_thread_set_signal_callback(instance->thread_id, NULL, NULL);
|
furi_thread_set_signal_callback(thread, NULL, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +243,10 @@ void furi_event_loop_stop(FuriEventLoop* instance) {
|
|||||||
furi_check(instance);
|
furi_check(instance);
|
||||||
|
|
||||||
xTaskNotifyIndexed(
|
xTaskNotifyIndexed(
|
||||||
instance->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, FuriEventLoopFlagStop, eSetBits);
|
(TaskHandle_t)instance->thread_id,
|
||||||
|
FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX,
|
||||||
|
FuriEventLoopFlagStop,
|
||||||
|
eSetBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -265,7 +269,10 @@ void furi_event_loop_pend_callback(
|
|||||||
PendingQueue_push_front(instance->pending_queue, item);
|
PendingQueue_push_front(instance->pending_queue, item);
|
||||||
|
|
||||||
xTaskNotifyIndexed(
|
xTaskNotifyIndexed(
|
||||||
instance->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, FuriEventLoopFlagPending, eSetBits);
|
(TaskHandle_t)instance->thread_id,
|
||||||
|
FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX,
|
||||||
|
FuriEventLoopFlagPending,
|
||||||
|
eSetBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -473,7 +480,10 @@ static void furi_event_loop_item_notify(FuriEventLoopItem* instance) {
|
|||||||
FURI_CRITICAL_EXIT();
|
FURI_CRITICAL_EXIT();
|
||||||
|
|
||||||
xTaskNotifyIndexed(
|
xTaskNotifyIndexed(
|
||||||
owner->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, FuriEventLoopFlagEvent, eSetBits);
|
(TaskHandle_t)owner->thread_id,
|
||||||
|
FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX,
|
||||||
|
FuriEventLoopFlagEvent,
|
||||||
|
eSetBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool furi_event_loop_item_is_waiting(FuriEventLoopItem* instance) {
|
static bool furi_event_loop_item_is_waiting(FuriEventLoopItem* instance) {
|
||||||
|
|||||||
@@ -65,7 +65,10 @@ static void furi_event_loop_timer_enqueue_request(
|
|||||||
TimerQueue_push_back(instance->timer_queue, timer);
|
TimerQueue_push_back(instance->timer_queue, timer);
|
||||||
|
|
||||||
xTaskNotifyIndexed(
|
xTaskNotifyIndexed(
|
||||||
instance->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, FuriEventLoopFlagTimer, eSetBits);
|
(TaskHandle_t)instance->thread_id,
|
||||||
|
FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX,
|
||||||
|
FuriEventLoopFlagTimer,
|
||||||
|
eSetBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ static void furi_thread_body(void* context) {
|
|||||||
furi_thread_set_state(thread, FuriThreadStateRunning);
|
furi_thread_set_state(thread, FuriThreadStateRunning);
|
||||||
|
|
||||||
if(thread->heap_trace_enabled == true) {
|
if(thread->heap_trace_enabled == true) {
|
||||||
memmgr_heap_enable_thread_trace(thread);
|
memmgr_heap_enable_thread_trace((FuriThreadId)thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
thread->ret = thread->callback(thread->context);
|
thread->ret = thread->callback(thread->context);
|
||||||
@@ -106,14 +106,14 @@ static void furi_thread_body(void* context) {
|
|||||||
|
|
||||||
if(thread->heap_trace_enabled == true) {
|
if(thread->heap_trace_enabled == true) {
|
||||||
furi_delay_ms(33);
|
furi_delay_ms(33);
|
||||||
thread->heap_size = memmgr_heap_get_thread_memory(thread);
|
thread->heap_size = memmgr_heap_get_thread_memory((FuriThreadId)thread);
|
||||||
furi_log_print_format(
|
furi_log_print_format(
|
||||||
thread->heap_size ? FuriLogLevelError : FuriLogLevelInfo,
|
thread->heap_size ? FuriLogLevelError : FuriLogLevelInfo,
|
||||||
TAG,
|
TAG,
|
||||||
"%s allocation balance: %zu",
|
"%s allocation balance: %zu",
|
||||||
thread->name ? thread->name : "Thread",
|
thread->name ? thread->name : "Thread",
|
||||||
thread->heap_size);
|
thread->heap_size);
|
||||||
memmgr_heap_disable_thread_trace(thread);
|
memmgr_heap_disable_thread_trace((FuriThreadId)thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_check(thread->state == FuriThreadStateRunning);
|
furi_check(thread->state == FuriThreadStateRunning);
|
||||||
@@ -275,7 +275,7 @@ void furi_thread_set_priority(FuriThread* thread, FuriThreadPriority priority) {
|
|||||||
|
|
||||||
FuriThreadPriority furi_thread_get_priority(FuriThread* thread) {
|
FuriThreadPriority furi_thread_get_priority(FuriThread* thread) {
|
||||||
furi_check(thread);
|
furi_check(thread);
|
||||||
TaskHandle_t hTask = furi_thread_get_id(thread);
|
TaskHandle_t hTask = (TaskHandle_t)thread;
|
||||||
return (FuriThreadPriority)uxTaskPriorityGet(hTask);
|
return (FuriThreadPriority)uxTaskPriorityGet(hTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,7 +390,7 @@ bool furi_thread_join(FuriThread* thread) {
|
|||||||
|
|
||||||
FuriThreadId furi_thread_get_id(FuriThread* thread) {
|
FuriThreadId furi_thread_get_id(FuriThread* thread) {
|
||||||
furi_check(thread);
|
furi_check(thread);
|
||||||
return thread;
|
return (FuriThreadId)thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_thread_enable_heap_trace(FuriThread* thread) {
|
void furi_thread_enable_heap_trace(FuriThread* thread) {
|
||||||
@@ -418,7 +418,7 @@ int32_t furi_thread_get_return_code(FuriThread* thread) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FuriThreadId furi_thread_get_current_id(void) {
|
FuriThreadId furi_thread_get_current_id(void) {
|
||||||
return xTaskGetCurrentTaskHandle();
|
return (FuriThreadId)xTaskGetCurrentTaskHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
FuriThread* furi_thread_get_current(void) {
|
FuriThread* furi_thread_get_current(void) {
|
||||||
@@ -624,15 +624,16 @@ bool furi_thread_enumerate(FuriThreadList* thread_list) {
|
|||||||
FuriThreadListItem* item =
|
FuriThreadListItem* item =
|
||||||
furi_thread_list_get_or_insert(thread_list, (FuriThread*)task[i].xHandle);
|
furi_thread_list_get_or_insert(thread_list, (FuriThread*)task[i].xHandle);
|
||||||
|
|
||||||
item->thread = (FuriThreadId)task[i].xHandle;
|
FuriThreadId thread_id = (FuriThreadId)task[i].xHandle;
|
||||||
item->app_id = furi_thread_get_appid(item->thread);
|
item->thread = (FuriThread*)thread_id;
|
||||||
|
item->app_id = furi_thread_get_appid(thread_id);
|
||||||
item->name = task[i].pcTaskName;
|
item->name = task[i].pcTaskName;
|
||||||
item->priority = task[i].uxCurrentPriority;
|
item->priority = task[i].uxCurrentPriority;
|
||||||
item->stack_address = (uint32_t)tcb->pxStack;
|
item->stack_address = (uint32_t)tcb->pxStack;
|
||||||
size_t thread_heap = memmgr_heap_get_thread_memory(item->thread);
|
size_t thread_heap = memmgr_heap_get_thread_memory(thread_id);
|
||||||
item->heap = thread_heap == MEMMGR_HEAP_UNKNOWN ? 0u : thread_heap;
|
item->heap = thread_heap == MEMMGR_HEAP_UNKNOWN ? 0u : thread_heap;
|
||||||
item->stack_size = (tcb->pxEndOfStack - tcb->pxStack + 1) * sizeof(StackType_t);
|
item->stack_size = (tcb->pxEndOfStack - tcb->pxStack + 1) * sizeof(StackType_t);
|
||||||
item->stack_min_free = furi_thread_get_stack_space(item->thread);
|
item->stack_min_free = furi_thread_get_stack_space(thread_id);
|
||||||
item->state = furi_thread_state_name(task[i].eCurrentState);
|
item->state = furi_thread_state_name(task[i].eCurrentState);
|
||||||
item->counter_previous = item->counter_current;
|
item->counter_previous = item->counter_current;
|
||||||
item->counter_current = task[i].ulRunTimeCounter;
|
item->counter_current = task[i].ulRunTimeCounter;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ struct FuriTimer {
|
|||||||
StaticTimer_t container;
|
StaticTimer_t container;
|
||||||
FuriTimerCallback cb_func;
|
FuriTimerCallback cb_func;
|
||||||
void* cb_context;
|
void* cb_context;
|
||||||
volatile bool can_be_removed;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// IMPORTANT: container MUST be the FIRST struct member
|
// IMPORTANT: container MUST be the FIRST struct member
|
||||||
@@ -42,9 +41,8 @@ static void furi_timer_epilogue(void* context, uint32_t arg) {
|
|||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
UNUSED(arg);
|
UNUSED(arg);
|
||||||
|
|
||||||
FuriTimer* instance = context;
|
volatile bool* can_be_removed = context;
|
||||||
|
*can_be_removed = true;
|
||||||
instance->can_be_removed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_timer_free(FuriTimer* instance) {
|
void furi_timer_free(FuriTimer* instance) {
|
||||||
@@ -53,9 +51,13 @@ void furi_timer_free(FuriTimer* instance) {
|
|||||||
|
|
||||||
TimerHandle_t hTimer = (TimerHandle_t)instance;
|
TimerHandle_t hTimer = (TimerHandle_t)instance;
|
||||||
furi_check(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS);
|
furi_check(xTimerDelete(hTimer, portMAX_DELAY) == pdPASS);
|
||||||
furi_check(xTimerPendFunctionCall(furi_timer_epilogue, instance, 0, portMAX_DELAY) == pdPASS);
|
|
||||||
|
|
||||||
while(!instance->can_be_removed) {
|
volatile bool can_be_removed = false;
|
||||||
|
furi_check(
|
||||||
|
xTimerPendFunctionCall(furi_timer_epilogue, (void*)&can_be_removed, 0, portMAX_DELAY) ==
|
||||||
|
pdPASS);
|
||||||
|
|
||||||
|
while(!can_be_removed) {
|
||||||
furi_delay_tick(2);
|
furi_delay_tick(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user