[FL-2591] Furi: remove CMSIS thread api, migrate to FuriThread, remove unused CMSIS APIs (#1333)

* Furi: remove CMSIS thread api, migrate to FuriThread, remove unused CMSIS APIs
* Furi: magic thread catcher validating thread completion; backtrace improver
* Furi: allow furi_thread_get_current_id outside of thread context
* Furi: use IRQ instead of ISR for core primitives
This commit is contained in:
あく
2022-06-20 17:54:48 +03:00
committed by GitHub
parent 7618c8ba6f
commit 839e52ac32
61 changed files with 1467 additions and 2784 deletions

View File

@@ -6,16 +6,19 @@
#include <cmsis_os2.h>
#include <furi/common_defines.h>
#include <furi/check.h>
#include <furi/common_defines.h>
#include <furi/log.h>
#include <furi/event_flags.h>
#include <furi/memmgr.h>
#include <furi/memmgr_heap.h>
#include <furi/mutex.h>
#include <furi/pubsub.h>
#include <furi/record.h>
#include <furi/semaphore.h>
#include <furi/stdglue.h>
#include <furi/thread.h>
#include <furi/valuemutex.h>
#include <furi/log.h>
#include <furi_hal_gpio.h>

45
core/furi/base.h Normal file
View File

@@ -0,0 +1,45 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
// FreeRTOS part
#include <FreeRTOS.h>
#ifdef __cplusplus
extern "C" {
#endif
// Timeout value.
#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value.
// Flags options (\ref furi_thread_flags_wait and \ref osEventFlagsWait).
#define osFlagsWaitAny 0x00000000U ///< Wait for any flag (default).
#define osFlagsWaitAll 0x00000001U ///< Wait for all flags.
#define osFlagsNoClear 0x00000002U ///< Do not clear flags which have been specified to wait for.
// Flags errors (returned by osThreadFlagsXxxx and osEventFlagsXxxx).
#define osFlagsError 0x80000000U ///< Error indicator.
#define osFlagsErrorUnknown 0xFFFFFFFFU ///< osError (-1).
#define osFlagsErrorTimeout 0xFFFFFFFEU ///< osErrorTimeout (-2).
#define osFlagsErrorResource 0xFFFFFFFDU ///< osErrorResource (-3).
#define osFlagsErrorParameter 0xFFFFFFFCU ///< osErrorParameter (-4).
#define osFlagsErrorISR 0xFFFFFFFAU ///< osErrorISR (-6).
/// Status code values returned by CMSIS-RTOS functions.
typedef enum {
osOK = 0, ///< Operation completed successfully.
osError = -1, ///< Unspecified RTOS error: run-time error but no other error message fits.
osErrorTimeout = -2, ///< Operation not completed within the timeout period.
osErrorResource = -3, ///< Resource not available.
osErrorParameter = -4, ///< Parameter error.
osErrorNoMemory =
-5, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation.
osErrorISR =
-6, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines.
osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
} osStatus_t;
#ifdef __cplusplus
}
#endif

View File

@@ -6,11 +6,14 @@
#include <furi_hal_rtc.h>
#include <stdio.h>
#include <FreeRTOS.h>
#include <task.h>
void __furi_print_name() {
if(FURI_IS_ISR()) {
furi_hal_console_puts("[ISR] ");
} else {
const char* name = osThreadGetName(osThreadGetId());
const char* name = pcTaskGetName(xTaskGetCurrentTaskHandle());
if(name == NULL) {
furi_hal_console_puts("[main] ");
} else {

View File

@@ -1,4 +1,5 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#define FURI_NORETURN [[noreturn]]

222
core/furi/event_flags.c Normal file
View File

@@ -0,0 +1,222 @@
#include "event_flags.h"
#include "common_defines.h"
#include <event_groups.h>
#define MAX_BITS_EVENT_GROUPS 24U
#define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U))
osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t* attr) {
EventGroupHandle_t hEventGroup;
int32_t mem;
hEventGroup = NULL;
if(FURI_IS_IRQ_MODE() == 0U) {
mem = -1;
if(attr != NULL) {
if((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticEventGroup_t))) {
/* The memory for control block is provided, use static object */
mem = 1;
} else {
if((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
/* Control block will be allocated from the dynamic pool */
mem = 0;
}
}
} else {
mem = 0;
}
if(mem == 1) {
#if(configSUPPORT_STATIC_ALLOCATION == 1)
hEventGroup = xEventGroupCreateStatic(attr->cb_mem);
#endif
} else {
if(mem == 0) {
#if(configSUPPORT_DYNAMIC_ALLOCATION == 1)
hEventGroup = xEventGroupCreate();
#endif
}
}
}
/* Return event flags ID */
return ((osEventFlagsId_t)hEventGroup);
}
/*
Set the specified Event Flags.
Limitations:
- Event flags are limited to 24 bits.
*/
uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) {
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
uint32_t rflags;
BaseType_t yield;
if((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
rflags = (uint32_t)osErrorParameter;
} else if(FURI_IS_IRQ_MODE() != 0U) {
#if(configUSE_OS2_EVENTFLAGS_FROM_ISR == 0)
(void)yield;
/* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */
rflags = (uint32_t)osErrorResource;
#else
yield = pdFALSE;
if(xEventGroupSetBitsFromISR(hEventGroup, (EventBits_t)flags, &yield) == pdFAIL) {
rflags = (uint32_t)osErrorResource;
} else {
rflags = flags;
portYIELD_FROM_ISR(yield);
}
#endif
} else {
rflags = xEventGroupSetBits(hEventGroup, (EventBits_t)flags);
}
/* Return event flags after setting */
return (rflags);
}
/*
Clear the specified Event Flags.
Limitations:
- Event flags are limited to 24 bits.
*/
uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags) {
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
uint32_t rflags;
if((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
rflags = (uint32_t)osErrorParameter;
} else if(FURI_IS_IRQ_MODE() != 0U) {
#if(configUSE_OS2_EVENTFLAGS_FROM_ISR == 0)
/* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */
rflags = (uint32_t)osErrorResource;
#else
rflags = xEventGroupGetBitsFromISR(hEventGroup);
if(xEventGroupClearBitsFromISR(hEventGroup, (EventBits_t)flags) == pdFAIL) {
rflags = (uint32_t)osErrorResource;
} else {
/* xEventGroupClearBitsFromISR only registers clear operation in the timer command queue. */
/* Yield is required here otherwise clear operation might not execute in the right order. */
/* See https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/93 for more info. */
portYIELD_FROM_ISR(pdTRUE);
}
#endif
} else {
rflags = xEventGroupClearBits(hEventGroup, (EventBits_t)flags);
}
/* Return event flags before clearing */
return (rflags);
}
/*
Get the current Event Flags.
Limitations:
- Event flags are limited to 24 bits.
*/
uint32_t osEventFlagsGet(osEventFlagsId_t ef_id) {
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
uint32_t rflags;
if(ef_id == NULL) {
rflags = 0U;
} else if(FURI_IS_IRQ_MODE() != 0U) {
rflags = xEventGroupGetBitsFromISR(hEventGroup);
} else {
rflags = xEventGroupGetBits(hEventGroup);
}
/* Return current event flags */
return (rflags);
}
/*
Wait for one or more Event Flags to become signaled.
Limitations:
- Event flags are limited to 24 bits.
- osEventFlagsWait cannot be called from an ISR.
*/
uint32_t
osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) {
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
BaseType_t wait_all;
BaseType_t exit_clr;
uint32_t rflags;
if((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
rflags = (uint32_t)osErrorParameter;
} else if(FURI_IS_IRQ_MODE() != 0U) {
rflags = (uint32_t)osErrorISR;
} else {
if(options & osFlagsWaitAll) {
wait_all = pdTRUE;
} else {
wait_all = pdFAIL;
}
if(options & osFlagsNoClear) {
exit_clr = pdFAIL;
} else {
exit_clr = pdTRUE;
}
rflags = xEventGroupWaitBits(
hEventGroup, (EventBits_t)flags, exit_clr, wait_all, (TickType_t)timeout);
if(options & osFlagsWaitAll) {
if((flags & rflags) != flags) {
if(timeout > 0U) {
rflags = (uint32_t)osErrorTimeout;
} else {
rflags = (uint32_t)osErrorResource;
}
}
} else {
if((flags & rflags) == 0U) {
if(timeout > 0U) {
rflags = (uint32_t)osErrorTimeout;
} else {
rflags = (uint32_t)osErrorResource;
}
}
}
}
/* Return event flags before clearing */
return (rflags);
}
/*
Delete an Event Flags object.
*/
osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id) {
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
osStatus_t stat;
#ifndef USE_FreeRTOS_HEAP_1
if(FURI_IS_IRQ_MODE() != 0U) {
stat = osErrorISR;
} else if(hEventGroup == NULL) {
stat = osErrorParameter;
} else {
stat = osOK;
vEventGroupDelete(hEventGroup);
}
#else
stat = osError;
#endif
/* Return execution status */
return (stat);
}

63
core/furi/event_flags.h Normal file
View File

@@ -0,0 +1,63 @@
#pragma once
#include "base.h"
#ifdef __cplusplus
extern "C" {
#endif
/// Attributes structure for event flags.
typedef struct {
const char* name; ///< name of the event flags
uint32_t attr_bits; ///< attribute bits
void* cb_mem; ///< memory for control block
uint32_t cb_size; ///< size of provided memory for control block
} osEventFlagsAttr_t;
/// \details Event Flags ID identifies the event flags.
typedef void* osEventFlagsId_t;
/// Create and Initialize an Event Flags object.
/// \param[in] attr event flags attributes; NULL: default values.
/// \return event flags ID for reference by other functions or NULL in case of error.
osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t* attr);
/// Get name of an Event Flags object.
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
/// \return name as null-terminated string.
const char* osEventFlagsGetName(osEventFlagsId_t ef_id);
/// Set the specified Event Flags.
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
/// \param[in] flags specifies the flags that shall be set.
/// \return event flags after setting or error code if highest bit set.
uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags);
/// Clear the specified Event Flags.
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
/// \param[in] flags specifies the flags that shall be cleared.
/// \return event flags before clearing or error code if highest bit set.
uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags);
/// Get the current Event Flags.
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
/// \return current event flags.
uint32_t osEventFlagsGet(osEventFlagsId_t ef_id);
/// Wait for one or more Event Flags to become signaled.
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
/// \param[in] flags specifies the flags to wait for.
/// \param[in] options specifies flags options (osFlagsXxxx).
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
/// \return event flags before clearing or error code if highest bit set.
uint32_t
osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout);
/// Delete an Event Flags object.
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
/// \return status code that indicates the execution status of the function.
osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id);
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,6 @@
#include "log.h"
#include "check.h"
#include "mutex.h"
#include <cmsis_os2.h>
#include <furi_hal.h>

View File

@@ -133,7 +133,7 @@ void memmgr_heap_init() {
MemmgrHeapThreadDict_init(memmgr_heap_thread_dict);
}
void memmgr_heap_enable_thread_trace(osThreadId_t thread_id) {
void memmgr_heap_enable_thread_trace(FuriThreadId thread_id) {
vTaskSuspendAll();
{
memmgr_heap_thread_trace_depth++;
@@ -147,7 +147,7 @@ void memmgr_heap_enable_thread_trace(osThreadId_t thread_id) {
(void)xTaskResumeAll();
}
void memmgr_heap_disable_thread_trace(osThreadId_t thread_id) {
void memmgr_heap_disable_thread_trace(FuriThreadId thread_id) {
vTaskSuspendAll();
{
memmgr_heap_thread_trace_depth++;
@@ -158,7 +158,7 @@ void memmgr_heap_disable_thread_trace(osThreadId_t thread_id) {
(void)xTaskResumeAll();
}
size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id) {
size_t memmgr_heap_get_thread_memory(FuriThreadId thread_id) {
size_t leftovers = MEMMGR_HEAP_UNKNOWN;
vTaskSuspendAll();
{
@@ -192,7 +192,7 @@ size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id) {
#undef traceMALLOC
static inline void traceMALLOC(void* pointer, size_t size) {
osThreadId_t thread_id = osThreadGetId();
FuriThreadId thread_id = furi_thread_get_current_id();
if(thread_id && memmgr_heap_thread_trace_depth == 0) {
memmgr_heap_thread_trace_depth++;
MemmgrHeapAllocDict_t* alloc_dict =
@@ -207,7 +207,7 @@ static inline void traceMALLOC(void* pointer, size_t size) {
#undef traceFREE
static inline void traceFREE(void* pointer, size_t size) {
UNUSED(size);
osThreadId_t thread_id = osThreadGetId();
FuriThreadId thread_id = furi_thread_get_current_id();
if(thread_id && memmgr_heap_thread_trace_depth == 0) {
memmgr_heap_thread_trace_depth++;
MemmgrHeapAllocDict_t* alloc_dict =
@@ -297,7 +297,7 @@ static void print_heap_init() {
static void print_heap_malloc(void* ptr, size_t size) {
char tmp_str[33];
const char* name = osThreadGetName(osThreadGetId());
const char* name = furi_thread_get_name(furi_thread_get_current_id());
if(!name) {
name = "";
}
@@ -318,7 +318,7 @@ static void print_heap_malloc(void* ptr, size_t size) {
static void print_heap_free(void* ptr) {
char tmp_str[33];
const char* name = osThreadGetName(osThreadGetId());
const char* name = furi_thread_get_name(furi_thread_get_current_id());
if(!name) {
name = "";
}

View File

@@ -6,7 +6,7 @@
#pragma once
#include <stdint.h>
#include <cmsis_os2.h>
#include "furi/thread.h"
#ifdef __cplusplus
extern "C" {
@@ -18,13 +18,13 @@ extern "C" {
*
* @param thread_id - thread id to track
*/
void memmgr_heap_enable_thread_trace(osThreadId_t thread_id);
void memmgr_heap_enable_thread_trace(FuriThreadId taks_handle);
/** Memmgr heap disable thread allocation tracking
*
* @param thread_id - thread id to track
*/
void memmgr_heap_disable_thread_trace(osThreadId_t thread_id);
void memmgr_heap_disable_thread_trace(FuriThreadId taks_handle);
/** Memmgr heap get allocatred thread memory
*
@@ -32,7 +32,7 @@ void memmgr_heap_disable_thread_trace(osThreadId_t thread_id);
*
* @return bytes allocated right now
*/
size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id);
size_t memmgr_heap_get_thread_memory(FuriThreadId taks_handle);
/** Memmgr heap get the max contiguous block size on the heap
*

217
core/furi/mutex.c Normal file
View File

@@ -0,0 +1,217 @@
#include "mutex.h"
#include "check.h"
#include "common_defines.h"
#include <semphr.h>
osMutexId_t osMutexNew(const osMutexAttr_t* attr) {
SemaphoreHandle_t hMutex;
uint32_t type;
uint32_t rmtx;
int32_t mem;
hMutex = NULL;
if(FURI_IS_IRQ_MODE() == 0U) {
if(attr != NULL) {
type = attr->attr_bits;
} else {
type = 0U;
}
if((type & osMutexRecursive) == osMutexRecursive) {
rmtx = 1U;
} else {
rmtx = 0U;
}
if((type & osMutexRobust) != osMutexRobust) {
mem = -1;
if(attr != NULL) {
if((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) {
/* The memory for control block is provided, use static object */
mem = 1;
} else {
if((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
/* Control block will be allocated from the dynamic pool */
mem = 0;
}
}
} else {
mem = 0;
}
if(mem == 1) {
#if(configSUPPORT_STATIC_ALLOCATION == 1)
if(rmtx != 0U) {
#if(configUSE_RECURSIVE_MUTEXES == 1)
hMutex = xSemaphoreCreateRecursiveMutexStatic(attr->cb_mem);
#endif
} else {
hMutex = xSemaphoreCreateMutexStatic(attr->cb_mem);
}
#endif
} else {
if(mem == 0) {
#if(configSUPPORT_DYNAMIC_ALLOCATION == 1)
if(rmtx != 0U) {
#if(configUSE_RECURSIVE_MUTEXES == 1)
hMutex = xSemaphoreCreateRecursiveMutex();
#endif
} else {
hMutex = xSemaphoreCreateMutex();
}
#endif
}
}
#if(configQUEUE_REGISTRY_SIZE > 0)
if(hMutex != NULL) {
if((attr != NULL) && (attr->name != NULL)) {
/* Only non-NULL name objects are added to the Queue Registry */
vQueueAddToRegistry(hMutex, attr->name);
}
}
#endif
if((hMutex != NULL) && (rmtx != 0U)) {
/* Set LSB as 'recursive mutex flag' */
hMutex = (SemaphoreHandle_t)((uint32_t)hMutex | 1U);
}
}
}
/* Return mutex ID */
return ((osMutexId_t)hMutex);
}
/*
Acquire a Mutex or timeout if it is locked.
*/
osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout) {
SemaphoreHandle_t hMutex;
osStatus_t stat;
uint32_t rmtx;
hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
/* Extract recursive mutex flag */
rmtx = (uint32_t)mutex_id & 1U;
stat = osOK;
if(FURI_IS_IRQ_MODE() != 0U) {
stat = osErrorISR;
} else if(hMutex == NULL) {
stat = osErrorParameter;
} else {
if(rmtx != 0U) {
#if(configUSE_RECURSIVE_MUTEXES == 1)
if(xSemaphoreTakeRecursive(hMutex, timeout) != pdPASS) {
if(timeout != 0U) {
stat = osErrorTimeout;
} else {
stat = osErrorResource;
}
}
#endif
} else {
if(xSemaphoreTake(hMutex, timeout) != pdPASS) {
if(timeout != 0U) {
stat = osErrorTimeout;
} else {
stat = osErrorResource;
}
}
}
}
/* Return execution status */
return (stat);
}
/*
Release a Mutex that was acquired by osMutexAcquire.
*/
osStatus_t osMutexRelease(osMutexId_t mutex_id) {
SemaphoreHandle_t hMutex;
osStatus_t stat;
uint32_t rmtx;
hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
/* Extract recursive mutex flag */
rmtx = (uint32_t)mutex_id & 1U;
stat = osOK;
if(FURI_IS_IRQ_MODE() != 0U) {
stat = osErrorISR;
} else if(hMutex == NULL) {
stat = osErrorParameter;
} else {
if(rmtx != 0U) {
#if(configUSE_RECURSIVE_MUTEXES == 1)
if(xSemaphoreGiveRecursive(hMutex) != pdPASS) {
stat = osErrorResource;
}
#endif
} else {
if(xSemaphoreGive(hMutex) != pdPASS) {
stat = osErrorResource;
}
}
}
/* Return execution status */
return (stat);
}
/*
Get Thread which owns a Mutex object.
*/
FuriThreadId osMutexGetOwner(osMutexId_t mutex_id) {
SemaphoreHandle_t hMutex;
FuriThreadId owner;
hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
if((FURI_IS_IRQ_MODE() != 0U) || (hMutex == NULL)) {
owner = 0;
} else {
owner = (FuriThreadId)xSemaphoreGetMutexHolder(hMutex);
}
/* Return owner thread ID */
return (owner);
}
/*
Delete a Mutex object.
*/
osStatus_t osMutexDelete(osMutexId_t mutex_id) {
osStatus_t stat;
#ifndef USE_FreeRTOS_HEAP_1
SemaphoreHandle_t hMutex;
hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
if(FURI_IS_IRQ_MODE() != 0U) {
stat = osErrorISR;
} else if(hMutex == NULL) {
stat = osErrorParameter;
} else {
#if(configQUEUE_REGISTRY_SIZE > 0)
vQueueUnregisterQueue(hMutex);
#endif
stat = osOK;
vSemaphoreDelete(hMutex);
}
#else
stat = osError;
#endif
/* Return execution status */
return (stat);
}

56
core/furi/mutex.h Normal file
View File

@@ -0,0 +1,56 @@
#pragma once
#include "base.h"
#include "thread.h"
#ifdef __cplusplus
extern "C" {
#endif
// Mutex attributes (attr_bits in \ref osMutexAttr_t).
#define osMutexRecursive 0x00000001U ///< Recursive mutex.
#define osMutexPrioInherit 0x00000002U ///< Priority inherit protocol.
#define osMutexRobust 0x00000008U ///< Robust mutex.
/// Attributes structure for mutex.
typedef struct {
const char* name; ///< name of the mutex
uint32_t attr_bits; ///< attribute bits
void* cb_mem; ///< memory for control block
uint32_t cb_size; ///< size of provided memory for control block
} osMutexAttr_t;
/// \details Mutex ID identifies the mutex.
typedef void* osMutexId_t;
/// Create and Initialize a Mutex object.
/// \param[in] attr mutex attributes; NULL: default values.
/// \return mutex ID for reference by other functions or NULL in case of error.
osMutexId_t osMutexNew(const osMutexAttr_t* attr);
/// Get name of a Mutex object.
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
/// \return name as null-terminated string.
const char* osMutexGetName(osMutexId_t mutex_id);
/// Acquire a Mutex or timeout if it is locked.
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
/// \return status code that indicates the execution status of the function.
osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout);
/// Release a Mutex that was acquired by \ref osMutexAcquire.
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
/// \return status code that indicates the execution status of the function.
osStatus_t osMutexRelease(osMutexId_t mutex_id);
/// Delete a Mutex object.
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
/// \return status code that indicates the execution status of the function.
osStatus_t osMutexDelete(osMutexId_t mutex_id);
FuriThreadId osMutexGetOwner(osMutexId_t mutex_id);
#ifdef __cplusplus
}
#endif

View File

@@ -1,9 +1,9 @@
#include "pubsub.h"
#include "memmgr.h"
#include "check.h"
#include "mutex.h"
#include <m-list.h>
#include <cmsis_os2.h>
struct FuriPubSubSubscription {
FuriPubSubCallback callback;

View File

@@ -1,8 +1,9 @@
#include "record.h"
#include "check.h"
#include "memmgr.h"
#include "mutex.h"
#include "event_flags.h"
#include <cmsis_os2.h>
#include <m-string.h>
#include <m-dict.h>

190
core/furi/semaphore.c Normal file
View File

@@ -0,0 +1,190 @@
#include "semaphore.h"
#include "check.h"
#include "common_defines.h"
#include <semphr.h>
osSemaphoreId_t
osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t* attr) {
SemaphoreHandle_t hSemaphore;
int32_t mem;
hSemaphore = NULL;
if((FURI_IS_IRQ_MODE() == 0U) && (max_count > 0U) && (initial_count <= max_count)) {
mem = -1;
if(attr != NULL) {
if((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) {
/* The memory for control block is provided, use static object */
mem = 1;
} else {
if((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
/* Control block will be allocated from the dynamic pool */
mem = 0;
}
}
} else {
mem = 0;
}
if(mem != -1) {
if(max_count == 1U) {
if(mem == 1) {
#if(configSUPPORT_STATIC_ALLOCATION == 1)
hSemaphore = xSemaphoreCreateBinaryStatic((StaticSemaphore_t*)attr->cb_mem);
#endif
} else {
#if(configSUPPORT_DYNAMIC_ALLOCATION == 1)
hSemaphore = xSemaphoreCreateBinary();
#endif
}
if((hSemaphore != NULL) && (initial_count != 0U)) {
if(xSemaphoreGive(hSemaphore) != pdPASS) {
vSemaphoreDelete(hSemaphore);
hSemaphore = NULL;
}
}
} else {
if(mem == 1) {
#if(configSUPPORT_STATIC_ALLOCATION == 1)
hSemaphore = xSemaphoreCreateCountingStatic(
max_count, initial_count, (StaticSemaphore_t*)attr->cb_mem);
#endif
} else {
#if(configSUPPORT_DYNAMIC_ALLOCATION == 1)
hSemaphore = xSemaphoreCreateCounting(max_count, initial_count);
#endif
}
}
#if(configQUEUE_REGISTRY_SIZE > 0)
if(hSemaphore != NULL) {
if((attr != NULL) && (attr->name != NULL)) {
/* Only non-NULL name objects are added to the Queue Registry */
vQueueAddToRegistry(hSemaphore, attr->name);
}
}
#endif
}
}
/* Return semaphore ID */
return ((osSemaphoreId_t)hSemaphore);
}
/*
Acquire a Semaphore token or timeout if no tokens are available.
*/
osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout) {
SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
osStatus_t stat;
BaseType_t yield;
stat = osOK;
if(hSemaphore == NULL) {
stat = osErrorParameter;
} else if(FURI_IS_IRQ_MODE() != 0U) {
if(timeout != 0U) {
stat = osErrorParameter;
} else {
yield = pdFALSE;
if(xSemaphoreTakeFromISR(hSemaphore, &yield) != pdPASS) {
stat = osErrorResource;
} else {
portYIELD_FROM_ISR(yield);
}
}
} else {
if(xSemaphoreTake(hSemaphore, (TickType_t)timeout) != pdPASS) {
if(timeout != 0U) {
stat = osErrorTimeout;
} else {
stat = osErrorResource;
}
}
}
/* Return execution status */
return (stat);
}
/*
Release a Semaphore token up to the initial maximum count.
*/
osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id) {
SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
osStatus_t stat;
BaseType_t yield;
stat = osOK;
if(hSemaphore == NULL) {
stat = osErrorParameter;
} else if(FURI_IS_IRQ_MODE() != 0U) {
yield = pdFALSE;
if(xSemaphoreGiveFromISR(hSemaphore, &yield) != pdTRUE) {
stat = osErrorResource;
} else {
portYIELD_FROM_ISR(yield);
}
} else {
if(xSemaphoreGive(hSemaphore) != pdPASS) {
stat = osErrorResource;
}
}
/* Return execution status */
return (stat);
}
/*
Get current Semaphore token count.
*/
uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id) {
SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
uint32_t count;
if(hSemaphore == NULL) {
count = 0U;
} else if(FURI_IS_IRQ_MODE() != 0U) {
count = (uint32_t)uxSemaphoreGetCountFromISR(hSemaphore);
} else {
count = (uint32_t)uxSemaphoreGetCount(hSemaphore);
}
/* Return number of tokens */
return (count);
}
/*
Delete a Semaphore object.
*/
osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id) {
SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
osStatus_t stat;
#ifndef USE_FreeRTOS_HEAP_1
if(FURI_IS_IRQ_MODE() != 0U) {
stat = osErrorISR;
} else if(hSemaphore == NULL) {
stat = osErrorParameter;
} else {
#if(configQUEUE_REGISTRY_SIZE > 0)
vQueueUnregisterQueue(hSemaphore);
#endif
stat = osOK;
vSemaphoreDelete(hSemaphore);
}
#else
stat = osError;
#endif
/* Return execution status */
return (stat);
}

57
core/furi/semaphore.h Normal file
View File

@@ -0,0 +1,57 @@
#pragma once
#include "base.h"
#include "thread.h"
#ifdef __cplusplus
extern "C" {
#endif
/// Attributes structure for semaphore.
typedef struct {
const char* name; ///< name of the semaphore
uint32_t attr_bits; ///< attribute bits
void* cb_mem; ///< memory for control block
uint32_t cb_size; ///< size of provided memory for control block
} osSemaphoreAttr_t;
/// \details Semaphore ID identifies the semaphore.
typedef void* osSemaphoreId_t;
/// Create and Initialize a Semaphore object.
/// \param[in] max_count maximum number of available tokens.
/// \param[in] initial_count initial number of available tokens.
/// \param[in] attr semaphore attributes; NULL: default values.
/// \return semaphore ID for reference by other functions or NULL in case of error.
osSemaphoreId_t
osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t* attr);
/// Get name of a Semaphore object.
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
/// \return name as null-terminated string.
const char* osSemaphoreGetName(osSemaphoreId_t semaphore_id);
/// Acquire a Semaphore token or timeout if no tokens are available.
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
/// \return status code that indicates the execution status of the function.
osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout);
/// Release a Semaphore token up to the initial maximum count.
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
/// \return status code that indicates the execution status of the function.
osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id);
/// Get current Semaphore token count.
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
/// \return number of tokens available.
uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id);
/// Delete a Semaphore object.
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
/// \return status code that indicates the execution status of the function.
osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id);
#ifdef __cplusplus
}
#endif

View File

@@ -26,13 +26,13 @@ static ssize_t stdout_write(void* _cookie, const char* data, size_t size) {
furi_assert(furi_stdglue);
bool consumed = false;
osKernelState_t state = osKernelGetState();
osThreadId_t thread_id = osThreadGetId();
if(state == osKernelRunning && thread_id &&
FuriThreadId task_id = furi_thread_get_current_id();
if(state == osKernelRunning && task_id &&
osMutexAcquire(furi_stdglue->mutex, osWaitForever) == osOK) {
// We are in the thread context
// Handle thread callbacks
FuriStdglueWriteCallback* callback_ptr =
FuriStdglueCallbackDict_get(furi_stdglue->thread_outputs, (uint32_t)thread_id);
FuriStdglueCallbackDict_get(furi_stdglue->thread_outputs, (uint32_t)task_id);
if(callback_ptr) {
(*callback_ptr)(_cookie, data, size);
consumed = true;
@@ -76,14 +76,14 @@ void furi_stdglue_init() {
bool furi_stdglue_set_thread_stdout_callback(FuriStdglueWriteCallback callback) {
furi_assert(furi_stdglue);
osThreadId_t thread_id = osThreadGetId();
if(thread_id) {
FuriThreadId task_id = furi_thread_get_current_id();
if(task_id) {
furi_check(osMutexAcquire(furi_stdglue->mutex, osWaitForever) == osOK);
if(callback) {
FuriStdglueCallbackDict_set_at(
furi_stdglue->thread_outputs, (uint32_t)thread_id, callback);
furi_stdglue->thread_outputs, (uint32_t)task_id, callback);
} else {
FuriStdglueCallbackDict_erase(furi_stdglue->thread_outputs, (uint32_t)thread_id);
FuriStdglueCallbackDict_erase(furi_stdglue->thread_outputs, (uint32_t)task_id);
}
furi_check(osMutexRelease(furi_stdglue->mutex) == osOK);
return true;

View File

@@ -2,7 +2,9 @@
#include "memmgr.h"
#include "memmgr_heap.h"
#include "check.h"
#include "common_defines.h"
#include <task.h>
#include <m-string.h>
struct FuriThread {
@@ -15,14 +17,22 @@ struct FuriThread {
FuriThreadStateCallback state_callback;
void* state_context;
osThreadAttr_t attr;
volatile osThreadId_t id;
char* name;
configSTACK_DEPTH_TYPE stack_size;
FuriThreadPriority priority;
TaskHandle_t task_handle;
bool heap_trace_enabled;
size_t heap_size;
};
void furi_thread_set_state(FuriThread* thread, FuriThreadState state) {
/** Catch threads that are trying to exit wrong way */
__attribute__((__noreturn__)) void furi_thread_catch() {
asm volatile("nop"); // extra magic
furi_crash("You are doing it wrong");
}
static void furi_thread_set_state(FuriThread* thread, FuriThreadState state) {
furi_assert(thread);
thread->state = state;
if(thread->state_callback) {
@@ -37,23 +47,24 @@ static void furi_thread_body(void* context) {
furi_assert(thread->state == FuriThreadStateStarting);
furi_thread_set_state(thread, FuriThreadStateRunning);
osThreadId_t thread_id = osThreadGetId();
TaskHandle_t task_handle = xTaskGetCurrentTaskHandle();
if(thread->heap_trace_enabled == true) {
memmgr_heap_enable_thread_trace(thread_id);
memmgr_heap_enable_thread_trace((FuriThreadId)task_handle);
}
thread->ret = thread->callback(thread->context);
if(thread->heap_trace_enabled == true) {
osDelay(33);
thread->heap_size = memmgr_heap_get_thread_memory(thread_id);
memmgr_heap_disable_thread_trace(thread_id);
thread->heap_size = memmgr_heap_get_thread_memory((FuriThreadId)task_handle);
memmgr_heap_disable_thread_trace((FuriThreadId)task_handle);
}
furi_assert(thread->state == FuriThreadStateRunning);
furi_thread_set_state(thread, FuriThreadStateStopped);
osThreadExit();
vTaskDelete(thread->task_handle);
furi_thread_catch();
}
FuriThread* furi_thread_alloc() {
@@ -66,21 +77,22 @@ void furi_thread_free(FuriThread* thread) {
furi_assert(thread);
furi_assert(thread->state == FuriThreadStateStopped);
if(thread->attr.name) free((void*)thread->attr.name);
if(thread->name) free((void*)thread->name);
free(thread);
}
void furi_thread_set_name(FuriThread* thread, const char* name) {
furi_assert(thread);
furi_assert(thread->state == FuriThreadStateStopped);
if(thread->attr.name) free((void*)thread->attr.name);
thread->attr.name = strdup(name);
if(thread->name) free((void*)thread->name);
thread->name = strdup(name);
}
void furi_thread_set_stack_size(FuriThread* thread, size_t stack_size) {
furi_assert(thread);
furi_assert(thread->state == FuriThreadStateStopped);
thread->attr.stack_size = stack_size;
furi_assert(stack_size % 4 == 0);
thread->stack_size = stack_size;
}
void furi_thread_set_callback(FuriThread* thread, FuriThreadCallback callback) {
@@ -95,6 +107,13 @@ void furi_thread_set_context(FuriThread* thread, void* context) {
thread->context = context;
}
void furi_thread_set_priority(FuriThread* thread, FuriThreadPriority priority) {
furi_assert(thread);
furi_assert(thread->state == FuriThreadStateStopped);
furi_assert(priority >= FuriThreadPriorityIdle && priority <= FuriThreadPriorityIsr);
thread->priority = priority;
}
void furi_thread_set_state_callback(FuriThread* thread, FuriThreadStateCallback callback) {
furi_assert(thread);
furi_assert(thread->state == FuriThreadStateStopped);
@@ -112,41 +131,39 @@ FuriThreadState furi_thread_get_state(FuriThread* thread) {
return thread->state;
}
bool furi_thread_start(FuriThread* thread) {
void furi_thread_start(FuriThread* thread) {
furi_assert(thread);
furi_assert(thread->callback);
furi_assert(thread->state == FuriThreadStateStopped);
furi_assert(thread->attr.stack_size > 0);
furi_assert(thread->stack_size > 0 && thread->stack_size < 0xFFFF * 4);
furi_thread_set_state(thread, FuriThreadStateStarting);
thread->id = osThreadNew(furi_thread_body, thread, &thread->attr);
if(thread->id) {
return true;
} else {
furi_assert(thread->state == FuriThreadStateStarting);
furi_thread_set_state(thread, FuriThreadStateStopped);
return false;
}
BaseType_t ret = xTaskCreate(
furi_thread_body,
thread->name,
thread->stack_size / 4,
thread,
thread->priority ? thread->priority : FuriThreadPriorityNormal,
&thread->task_handle);
furi_check(ret == pdPASS);
furi_check(thread->task_handle);
}
osStatus_t furi_thread_terminate(FuriThread* thread) {
bool furi_thread_join(FuriThread* thread) {
furi_assert(thread);
osStatus_t ret = osThreadTerminate(thread->id);
if(ret == osOK) {
furi_thread_set_state(thread, FuriThreadStateStopped);
}
return ret;
}
osStatus_t furi_thread_join(FuriThread* thread) {
furi_assert(thread);
while(thread->state != FuriThreadStateStopped) {
osDelay(10);
}
return osOK;
}
osThreadId_t furi_thread_get_thread_id(FuriThread* thread) {
return thread->id;
FuriThreadId furi_thread_get_id(FuriThread* thread) {
furi_assert(thread);
return thread->task_handle;
}
void furi_thread_enable_heap_trace(FuriThread* thread) {
@@ -174,3 +191,213 @@ int32_t furi_thread_get_return_code(FuriThread* thread) {
furi_assert(thread->state == FuriThreadStateStopped);
return thread->ret;
}
FuriThreadId furi_thread_get_current_id() {
return xTaskGetCurrentTaskHandle();
}
void furi_thread_yield() {
furi_assert(!FURI_IS_IRQ_MODE());
taskYIELD();
}
/* Limits */
#define MAX_BITS_TASK_NOTIFY 31U
#define MAX_BITS_EVENT_GROUPS 24U
#define THREAD_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_TASK_NOTIFY) - 1U))
#define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U))
uint32_t furi_thread_flags_set(FuriThreadId thread_id, uint32_t flags) {
TaskHandle_t hTask = (TaskHandle_t)thread_id;
uint32_t rflags;
BaseType_t yield;
if((hTask == NULL) || ((flags & THREAD_FLAGS_INVALID_BITS) != 0U)) {
rflags = (uint32_t)osErrorParameter;
} else {
rflags = (uint32_t)osError;
if(FURI_IS_IRQ_MODE()) {
yield = pdFALSE;
(void)xTaskNotifyFromISR(hTask, flags, eSetBits, &yield);
(void)xTaskNotifyAndQueryFromISR(hTask, 0, eNoAction, &rflags, NULL);
portYIELD_FROM_ISR(yield);
} else {
(void)xTaskNotify(hTask, flags, eSetBits);
(void)xTaskNotifyAndQuery(hTask, 0, eNoAction, &rflags);
}
}
/* Return flags after setting */
return (rflags);
}
uint32_t furi_thread_flags_clear(uint32_t flags) {
TaskHandle_t hTask;
uint32_t rflags, cflags;
if(FURI_IS_IRQ_MODE()) {
rflags = (uint32_t)osErrorISR;
} else if((flags & THREAD_FLAGS_INVALID_BITS) != 0U) {
rflags = (uint32_t)osErrorParameter;
} else {
hTask = xTaskGetCurrentTaskHandle();
if(xTaskNotifyAndQuery(hTask, 0, eNoAction, &cflags) == pdPASS) {
rflags = cflags;
cflags &= ~flags;
if(xTaskNotify(hTask, cflags, eSetValueWithOverwrite) != pdPASS) {
rflags = (uint32_t)osError;
}
} else {
rflags = (uint32_t)osError;
}
}
/* Return flags before clearing */
return (rflags);
}
uint32_t furi_thread_flags_get(void) {
TaskHandle_t hTask;
uint32_t rflags;
if(FURI_IS_IRQ_MODE()) {
rflags = (uint32_t)osErrorISR;
} else {
hTask = xTaskGetCurrentTaskHandle();
if(xTaskNotifyAndQuery(hTask, 0, eNoAction, &rflags) != pdPASS) {
rflags = (uint32_t)osError;
}
}
return (rflags);
}
uint32_t furi_thread_flags_wait(uint32_t flags, uint32_t options, uint32_t timeout) {
uint32_t rflags, nval;
uint32_t clear;
TickType_t t0, td, tout;
BaseType_t rval;
if(FURI_IS_IRQ_MODE()) {
rflags = (uint32_t)osErrorISR;
} else if((flags & THREAD_FLAGS_INVALID_BITS) != 0U) {
rflags = (uint32_t)osErrorParameter;
} else {
if((options & osFlagsNoClear) == osFlagsNoClear) {
clear = 0U;
} else {
clear = flags;
}
rflags = 0U;
tout = timeout;
t0 = xTaskGetTickCount();
do {
rval = xTaskNotifyWait(0, clear, &nval, tout);
if(rval == pdPASS) {
rflags &= flags;
rflags |= nval;
if((options & osFlagsWaitAll) == osFlagsWaitAll) {
if((flags & rflags) == flags) {
break;
} else {
if(timeout == 0U) {
rflags = (uint32_t)osErrorResource;
break;
}
}
} else {
if((flags & rflags) != 0) {
break;
} else {
if(timeout == 0U) {
rflags = (uint32_t)osErrorResource;
break;
}
}
}
/* Update timeout */
td = xTaskGetTickCount() - t0;
if(td > tout) {
tout = 0;
} else {
tout -= td;
}
} else {
if(timeout == 0) {
rflags = (uint32_t)osErrorResource;
} else {
rflags = (uint32_t)osErrorTimeout;
}
}
} while(rval != pdFAIL);
}
/* Return flags before clearing */
return (rflags);
}
uint32_t furi_thread_enumerate(FuriThreadId* thread_array, uint32_t array_items) {
uint32_t i, count;
TaskStatus_t* task;
if(FURI_IS_IRQ_MODE() || (thread_array == NULL) || (array_items == 0U)) {
count = 0U;
} else {
vTaskSuspendAll();
count = uxTaskGetNumberOfTasks();
task = pvPortMalloc(count * sizeof(TaskStatus_t));
if(task != NULL) {
count = uxTaskGetSystemState(task, count, NULL);
for(i = 0U; (i < count) && (i < array_items); i++) {
thread_array[i] = (FuriThreadId)task[i].xHandle;
}
count = i;
}
(void)xTaskResumeAll();
vPortFree(task);
}
return (count);
}
const char* furi_thread_get_name(FuriThreadId thread_id) {
TaskHandle_t hTask = (TaskHandle_t)thread_id;
const char* name;
if(FURI_IS_IRQ_MODE() || (hTask == NULL)) {
name = NULL;
} else {
name = pcTaskGetName(hTask);
}
return (name);
}
uint32_t furi_thread_get_stack_space(FuriThreadId thread_id) {
TaskHandle_t hTask = (TaskHandle_t)thread_id;
uint32_t sz;
if(FURI_IS_IRQ_MODE() || (hTask == NULL)) {
sz = 0U;
} else {
sz = (uint32_t)(uxTaskGetStackHighWaterMark(hTask) * sizeof(StackType_t));
}
return (sz);
}

View File

@@ -5,9 +5,7 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <cmsis_os2.h>
#include "base.h"
#ifdef __cplusplus
extern "C" {
@@ -20,9 +18,24 @@ typedef enum {
FuriThreadStateRunning,
} FuriThreadState;
/** FuriThreadPriority */
typedef enum {
FuriThreadPriorityNone = 0, /**< Uninitialized, choose system default */
FuriThreadPriorityIdle = 1, /**< Idle priority */
FuriThreadPriorityLowest = 14, /**< Lowest */
FuriThreadPriorityLow = 15, /**< Low */
FuriThreadPriorityNormal = 16, /**< Normal */
FuriThreadPriorityHigh = 17, /**< High */
FuriThreadPriorityHighest = 18, /**< Highest */
FuriThreadPriorityIsr = 32, /**< Deffered Isr (highest possible) */
} FuriThreadPriority;
/** FuriThread anonymous structure */
typedef struct FuriThread FuriThread;
/** FuriThreadId proxy type to OS low level functions */
typedef void* FuriThreadId;
/** FuriThreadCallback Your callback to run in new thread
* @warning never use osThreadExit in FuriThread
*/
@@ -74,6 +87,13 @@ void furi_thread_set_callback(FuriThread* thread, FuriThreadCallback callback);
*/
void furi_thread_set_context(FuriThread* thread, void* context);
/** Set FuriThread priority
*
* @param thread FuriThread instance
* @param priority FuriThreadPriority value
*/
void furi_thread_set_priority(FuriThread* thread, FuriThreadPriority priority);
/** Set FuriThread state change callback
*
* @param thread FuriThread instance
@@ -99,36 +119,24 @@ FuriThreadState furi_thread_get_state(FuriThread* thread);
/** Start FuriThread
*
* @param thread FuriThread instance
*
* @return true on success
*/
bool furi_thread_start(FuriThread* thread);
/** Treminate FuriThread
*
* @param thread FuriThread instance
*
* @return osStatus_t
* @warning terminating statefull thread is dangerous use only if you know
* what you doing
*/
osStatus_t furi_thread_terminate(FuriThread* thread);
void furi_thread_start(FuriThread* thread);
/** Join FuriThread
*
* @param thread FuriThread instance
*
* @return osStatus_t
* @return bool
*/
osStatus_t furi_thread_join(FuriThread* thread);
bool furi_thread_join(FuriThread* thread);
/** Get CMSIS Thread ID
/** Get FreeRTOS FuriThreadId for FuriThread instance
*
* @param thread FuriThread instance
*
* @return osThreadId_t or NULL
* @return FuriThreadId or NULL
*/
osThreadId_t furi_thread_get_thread_id(FuriThread* thread);
FuriThreadId furi_thread_get_id(FuriThread* thread);
/** Enable heap tracing
*
@@ -158,6 +166,33 @@ size_t furi_thread_get_heap_size(FuriThread* thread);
*/
int32_t furi_thread_get_return_code(FuriThread* thread);
/** Thread releated methods that doesn't involve FuriThread directly */
/** Get FreeRTOS FuriThreadId for current thread
*
* @param thread FuriThread instance
*
* @return FuriThreadId or NULL
*/
FuriThreadId furi_thread_get_current_id();
/** Return control to scheduler */
void furi_thread_yield();
uint32_t furi_thread_flags_set(FuriThreadId thread_id, uint32_t flags);
uint32_t furi_thread_flags_clear(uint32_t flags);
uint32_t furi_thread_flags_get(void);
uint32_t furi_thread_flags_wait(uint32_t flags, uint32_t options, uint32_t timeout);
uint32_t furi_thread_enumerate(FuriThreadId* thread_array, uint32_t array_items);
const char* furi_thread_get_name(FuriThreadId thread_id);
uint32_t furi_thread_get_stack_space(FuriThreadId thread_id);
#ifdef __cplusplus
}
#endif

View File

@@ -2,6 +2,7 @@
#include <cmsis_os2.h>
#include <stdbool.h>
#include "mutex.h"
#ifdef __cplusplus
extern "C" {