Skip to content

Commit

Permalink
Improved thread lifecycle (#2534)
Browse files Browse the repository at this point in the history
* Core, Thread: mark thread to join from prvDeleteTCB
* USB HAL: move vars to MEM2
* Core, Thread: cleanup sources
* Cli: add magic delays on rx pipe error, prevent cli from consuming processor time
* Furi: update thread documentation

Co-authored-by: あく <[email protected]>
  • Loading branch information
DrZlo13 and skotopes authored Mar 28, 2023
1 parent 3617ad3 commit 8b2dfea
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 17 deletions.
2 changes: 2 additions & 0 deletions applications/services/cli/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ char cli_getc(Cli* cli) {
if(cli->session != NULL) {
if(cli->session->rx((uint8_t*)&c, 1, FuriWaitForever) == 0) {
cli_reset(cli);
furi_delay_tick(10);
}
} else {
cli_reset(cli);
furi_delay_tick(10);
}
return c;
}
Expand Down
5 changes: 2 additions & 3 deletions firmware/targets/f7/furi_hal/furi_hal_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,11 @@ typedef enum {
#define USB_SRV_ALL_EVENTS (UsbEventReset | UsbEventRequest | UsbEventMessage)

PLACE_IN_SECTION("MB_MEM2") static UsbSrv usb = {0};
PLACE_IN_SECTION("MB_MEM2") static uint32_t ubuf[0x20];
PLACE_IN_SECTION("MB_MEM2") usbd_device udev;

static const struct usb_string_descriptor dev_lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US);

static uint32_t ubuf[0x20];
usbd_device udev;

static int32_t furi_hal_usb_thread(void* context);
static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_t* length);
static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep);
Expand Down
5 changes: 5 additions & 0 deletions firmware/targets/f7/inc/FreeRTOSConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ extern uint32_t SystemCoreClock;
#define configTIMER_SERVICE_TASK_NAME "TimersSrv"

#define configIDLE_TASK_NAME "(-_-)"
#define configIDLE_TASK_STACK_DEPTH 128

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
Expand Down Expand Up @@ -138,3 +139,7 @@ standard names. */
#define traceTASK_SWITCHED_IN() \
extern void furi_hal_mpu_set_stack_protection(uint32_t* stack); \
furi_hal_mpu_set_stack_protection((uint32_t*)pxCurrentTCB->pxStack)

#define portCLEAN_UP_TCB(pxTCB) \
extern void furi_thread_cleanup_tcb_event(TaskHandle_t task); \
furi_thread_cleanup_tcb_event(pxTCB)
35 changes: 23 additions & 12 deletions furi/core/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ struct FuriThreadStdout {
};

struct FuriThread {
bool is_service;
FuriThreadState state;
int32_t ret;

Expand All @@ -37,14 +36,19 @@ struct FuriThread {
char* name;
char* appid;

configSTACK_DEPTH_TYPE stack_size;
FuriThreadPriority priority;

TaskHandle_t task_handle;
bool heap_trace_enabled;
size_t heap_size;

FuriThreadStdout output;

// Keep all non-alignable byte types in one place,
// this ensures that the size of this structure is minimal
bool is_service;
bool heap_trace_enabled;

configSTACK_DEPTH_TYPE stack_size;
};

static size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, size_t size);
Expand Down Expand Up @@ -107,14 +111,8 @@ static void furi_thread_body(void* context) {
// flush stdout
__furi_thread_stdout_flush(thread);

// from here we can't use thread pointer
furi_thread_set_state(thread, FuriThreadStateStopped);

// clear thread local storage
furi_assert(pvTaskGetThreadLocalStoragePointer(NULL, 0) != NULL);
vTaskSetThreadLocalStoragePointer(NULL, 0, NULL);

thread->task_handle = NULL;
vTaskDelete(NULL);
furi_thread_catch();
}
Expand Down Expand Up @@ -249,11 +247,11 @@ void furi_thread_start(FuriThread* thread) {
furi_assert(thread);
furi_assert(thread->callback);
furi_assert(thread->state == FuriThreadStateStopped);
furi_assert(thread->stack_size > 0 && thread->stack_size < 0xFFFF * 4);
furi_assert(thread->stack_size > 0 && thread->stack_size < (UINT16_MAX * sizeof(StackType_t)));

furi_thread_set_state(thread, FuriThreadStateStarting);

uint32_t stack = thread->stack_size / 4;
uint32_t stack = thread->stack_size / sizeof(StackType_t);
UBaseType_t priority = thread->priority ? thread->priority : FuriThreadPriorityNormal;
if(thread->is_service) {
thread->task_handle = xTaskCreateStatic(
Expand All @@ -273,12 +271,25 @@ void furi_thread_start(FuriThread* thread) {
furi_check(thread->task_handle);
}

void furi_thread_cleanup_tcb_event(TaskHandle_t task) {
FuriThread* thread = pvTaskGetThreadLocalStoragePointer(task, 0);
if(thread) {
// clear thread local storage
vTaskSetThreadLocalStoragePointer(task, 0, NULL);

thread->task_handle = NULL;
}
}

bool furi_thread_join(FuriThread* thread) {
furi_assert(thread);

furi_check(furi_thread_get_current() != thread);

// Wait for thread to stop
// !!! IMPORTANT NOTICE !!!
//
// If your thread exited, but your app stuck here: some other thread uses
// all cpu time, which delays kernel from releasing task handle
while(thread->task_handle) {
furi_delay_ms(10);
}
Expand Down
5 changes: 5 additions & 0 deletions furi/core/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ FuriThread* furi_thread_alloc_ex(
void* context);

/** Release FuriThread
*
* @warning see furi_thread_join
*
* @param thread FuriThread instance
*/
Expand Down Expand Up @@ -173,6 +175,9 @@ FuriThreadState furi_thread_get_state(FuriThread* thread);
void furi_thread_start(FuriThread* thread);

/** Join FuriThread
*
* @warning Use this method only when CPU is not busy(Idle task receives
* control), otherwise it will wait forever.
*
* @param thread FuriThread instance
*
Expand Down
4 changes: 2 additions & 2 deletions furi/flipper.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ void vApplicationGetIdleTaskMemory(
StackType_t** stack_ptr,
uint32_t* stack_size) {
*tcb_ptr = memmgr_alloc_from_pool(sizeof(StaticTask_t));
*stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configMINIMAL_STACK_SIZE);
*stack_size = configMINIMAL_STACK_SIZE;
*stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configIDLE_TASK_STACK_DEPTH);
*stack_size = configIDLE_TASK_STACK_DEPTH;
}

void vApplicationGetTimerTaskMemory(
Expand Down

0 comments on commit 8b2dfea

Please sign in to comment.