unleashed-firmware/furi/core/thread.h
Georgii Surkov 4cf98867a0
[FL-3847, FL-3513] Thread Signals (#3730)
* Add signal API
* Add signal support to loader
* Add signal support to ViewDispatcher
* Remove extra signal definitions
* Fix typos
  Co-authored-by: Silent <CookiePLMonster@users.noreply.github.com>
* scripts: runfap: close current app pre-launch
* loader: enable backlight when starting an app
* scripts: removed distfap.py
* Do not expose signal API via ViewDispatcher
* scripts: runfap: iterative retry to launch
* Add a loader signal subcommand
* Furi, Gui: move signal handling from View Dispatcher to Event Loop

Co-authored-by: Silent <CookiePLMonster@users.noreply.github.com>
Co-authored-by: hedger <hedger@nanode.su>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-06-21 21:44:36 +01:00

506 lines
15 KiB
C

/**
* @file thread.h
* @brief Furi: Furi Thread API
*/
#pragma once
#include "base.h"
#include "common_defines.h"
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Enumeration of possible FuriThread states.
*
* Many of the FuriThread functions MUST ONLY be called when the thread is STOPPED.
*/
typedef enum {
FuriThreadStateStopped, /**< Thread is stopped */
FuriThreadStateStarting, /**< Thread is starting */
FuriThreadStateRunning, /**< Thread is running */
} FuriThreadState;
/**
* @brief Enumeration of possible FuriThread priorities.
*/
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 =
(FURI_CONFIG_THREAD_MAX_PRIORITIES - 1), /**< Deferred ISR (highest possible) */
} FuriThreadPriority;
/**
* @brief FuriThread opaque type.
*/
typedef struct FuriThread FuriThread;
/** FuriThreadList type */
typedef struct FuriThreadList FuriThreadList;
/**
* @brief Unique thread identifier type (used by the OS kernel).
*/
typedef void* FuriThreadId;
/**
* @brief Thread callback function pointer type.
*
* The function to be used as a thread callback MUST follow this signature.
*
* @param[in,out] context pointer to a user-specified object
* @return value to be used as the thread return code
*/
typedef int32_t (*FuriThreadCallback)(void* context);
/**
* @brief Standard output callback function pointer type.
*
* The function to be used as a standard output callback MUST follow this signature.
*
* @warning The handler MUST process ALL of the provided data before returning.
*
* @param[in] data pointer to the data to be written to the standard out
* @param[in] size size of the data in bytes
*/
typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size);
/**
* @brief State change callback function pointer type.
*
* The function to be used as a state callback MUST follow this signature.
*
* @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)(FuriThreadState state, void* context);
/**
* @brief Signal handler callback function pointer type.
*
* The function to be used as a signal handler callback MUS follow this signature.
*
* @param[in] signal value of the signal to be handled by the recipient
* @param[in,out] arg optional argument (can be of any value, including NULL)
* @param[in,out] context pointer to a user-specified object
* @returns true if the signal was handled, false otherwise
*/
typedef bool (*FuriThreadSignalCallback)(uint32_t signal, void* arg, void* context);
/**
* @brief Create a FuriThread instance.
*
* @return pointer to the created FuriThread instance
*/
FuriThread* furi_thread_alloc(void);
/**
* @brief Create a FuriThread instance (service mode).
*
* Service threads are more memory efficient, but have
* the following limitations:
*
* - Cannot return from the callback
* - Cannot be joined or freed
* - Stack size cannot be altered
*
* @param[in] name human-readable thread name (can be NULL)
* @param[in] stack_size stack size in bytes (cannot be changed later)
* @param[in] callback pointer to a function to be executed in this thread
* @param[in] context pointer to a user-specified object (will be passed to the callback)
* @return pointer to the created FuriThread instance
*/
FuriThread* furi_thread_alloc_service(
const char* name,
uint32_t stack_size,
FuriThreadCallback callback,
void* context);
/**
* @brief Create a FuriThread instance w/ extra parameters.
*
* @param[in] name human-readable thread name (can be NULL)
* @param[in] stack_size stack size in bytes (can be changed later)
* @param[in] callback pointer to a function to be executed in this thread
* @param[in] context pointer to a user-specified object (will be passed to the callback)
* @return pointer to the created FuriThread instance
*/
FuriThread* furi_thread_alloc_ex(
const char* name,
uint32_t stack_size,
FuriThreadCallback callback,
void* context);
/**
* @brief Delete a FuriThread instance.
*
* The thread MUST be stopped when calling this function.
*
* @warning see furi_thread_join for caveats on stopping a thread.
*
* @param[in,out] thread pointer to the FuriThread instance to be deleted
*/
void furi_thread_free(FuriThread* thread);
/**
* @brief Set the name of a FuriThread instance.
*
* The thread MUST be stopped when calling this function.
*
* @param[in,out] thread pointer to the FuriThread instance to be modified
* @param[in] name human-readable thread name (can be NULL)
*/
void furi_thread_set_name(FuriThread* thread, const char* name);
/**
* @brief Set the application ID of a FuriThread instance.
*
* The thread MUST be stopped when calling this function.
*
* Technically, it is like a "process id", but it is not a system-wide unique identifier.
* All threads spawned by the same app will have the same appid.
*
* @param[in,out] thread pointer to the FuriThread instance to be modified
* @param[in] appid thread application ID (can be NULL)
*/
void furi_thread_set_appid(FuriThread* thread, const char* appid);
/**
* @brief Set the stack size of a FuriThread instance.
*
* The thread MUST be stopped when calling this function. Additionally, it is NOT possible
* to change the stack size of a service thread under any circumstances.
*
* @param[in,out] thread pointer to the FuriThread instance to be modified
* @param[in] stack_size stack size in bytes
*/
void furi_thread_set_stack_size(FuriThread* thread, size_t stack_size);
/**
* @brief Set the user callback function to be executed in a FuriThread.
*
* The thread MUST be stopped when calling this function.
*
* @param[in,out] thread pointer to the FuriThread instance to be modified
* @param[in] callback pointer to a user-specified function to be executed in this thread
*/
void furi_thread_set_callback(FuriThread* thread, FuriThreadCallback callback);
/**
* @brief Set the callback function context.
*
* The thread MUST be stopped when calling this function.
*
* @param[in,out] thread pointer to the FuriThread instance to be modified
* @param[in] context pointer to a user-specified object (will be passed to the callback, can be NULL)
*/
void furi_thread_set_context(FuriThread* thread, void* context);
/**
* @brief Set the priority of a FuriThread.
*
* The thread MUST be stopped when calling this function.
*
* @param[in,out] thread pointer to the FuriThread instance to be modified
* @param[in] priority priority level value
*/
void furi_thread_set_priority(FuriThread* thread, FuriThreadPriority priority);
/**
* @brief Get the priority of a FuriThread.
*
* @param[in] thread pointer to the FuriThread instance to be queried
* @return priority level value
*/
FuriThreadPriority furi_thread_get_priority(FuriThread* thread);
/**
* @brief Set the priority of the current FuriThread.
*
* @param priority priority level value
*/
void furi_thread_set_current_priority(FuriThreadPriority priority);
/**
* @brief Get the priority of the current FuriThread.
*
* @return priority level value
*/
FuriThreadPriority furi_thread_get_current_priority(void);
/**
* Set the callback function to be executed upon a state thransition of a FuriThread.
*
* The thread MUST be stopped when calling this function.
*
* @param[in,out] thread pointer to the FuriThread instance to be modified
* @param[in] callback pointer to a user-specified callback function
*/
void furi_thread_set_state_callback(FuriThread* thread, FuriThreadStateCallback callback);
/**
* @brief Set the state change callback context.
*
* The thread MUST be stopped when calling this function.
*
* @param[in,out] thread pointer to the FuriThread instance to be modified
* @param[in] context pointer to a user-specified object (will be passed to the callback, can be NULL)
*/
void furi_thread_set_state_context(FuriThread* thread, void* context);
/**
* @brief Get the state of a FuriThread isntance.
*
* @param[in] thread pointer to the FuriThread instance to be queried
* @return thread state value
*/
FuriThreadState furi_thread_get_state(FuriThread* thread);
/**
* @brief Set a signal handler callback for a FuriThread instance.
*
* The thread MUST be stopped when calling this function.
*
* @param[in,out] thread pointer to the FuriThread instance to be modified
* @param[in] callback pointer to a user-specified callback function
* @param[in] context pointer to a user-specified object (will be passed to the callback, can be NULL)
*/
void furi_thread_set_signal_callback(
FuriThread* thread,
FuriThreadSignalCallback callback,
void* context);
/**
* @brief Send a signal to a FuriThread instance.
*
* @param[in] thread pointer to the FuriThread instance to be signaled
* @param[in] signal signal value to be sent
* @param[in,out] arg optional argument (can be of any value, including NULL)
*/
bool furi_thread_signal(const FuriThread* thread, uint32_t signal, void* arg);
/**
* @brief Start a FuriThread instance.
*
* The thread MUST be stopped when calling this function.
*
* @param[in,out] thread pointer to the FuriThread instance to be started
*/
void furi_thread_start(FuriThread* thread);
/**
* @brief Wait for a FuriThread to exit.
*
* The thread callback function must return in order for the FuriThread instance to become joinable.
*
* @warning Use this method only when the CPU is not busy (i.e. when the
* Idle task receives control), otherwise it will wait forever.
*
* @param[in] thread pointer to the FuriThread instance to be joined
* @return always true
*/
bool furi_thread_join(FuriThread* thread);
/**
* @brief Get the unique identifier of a FuriThread instance.
*
* @param[in] thread pointer to the FuriThread instance to be queried
* @return unique identifier value or NULL if thread is not running
*/
FuriThreadId furi_thread_get_id(FuriThread* thread);
/**
* @brief Enable heap usage tracing for a FuriThread.
*
* The thread MUST be stopped when calling this function.
*
* @param[in,out] thread pointer to the FuriThread instance to be modified
*/
void furi_thread_enable_heap_trace(FuriThread* thread);
/**
* @brief Disable heap usage tracing for a FuriThread.
*
* The thread MUST be stopped when calling this function.
*
* @param[in,out] thread pointer to the FuriThread instance to be modified
*/
void furi_thread_disable_heap_trace(FuriThread* thread);
/**
* @brief Get heap usage by a FuriThread instance.
*
* The heap trace MUST be enabled before callgin this function.
*
* @param[in] thread pointer to the FuriThread instance to be queried
* @return heap usage in bytes
*/
size_t furi_thread_get_heap_size(FuriThread* thread);
/**
* @brief Get the return code of a FuriThread instance.
*
* This value is equal to the return value of the thread callback function.
*
* The thread MUST be stopped when calling this function.
*
* @param[in] thread pointer to the FuriThread instance to be queried
* @return return code value
*/
int32_t furi_thread_get_return_code(FuriThread* thread);
/**
* @brief Get the unique identifier of the current FuriThread.
*
* @return unique identifier value
*/
FuriThreadId furi_thread_get_current_id(void);
/**
* @brief Get the FuriThread instance associated with the current thread.
*
* @return pointer to a FuriThread instance or NULL if this thread does not belong to Furi
*/
FuriThread* furi_thread_get_current(void);
/**
* @brief Return control to the scheduler.
*/
void furi_thread_yield(void);
/**
* @brief Set the thread flags of a FuriThread.
*
* Can be used as a simple inter-thread communication mechanism.
*
* @param[in] thread_id unique identifier of the thread to be notified
* @param[in] flags bitmask of thread flags to set
* @return bitmask combination of previous and newly set flags
*/
uint32_t furi_thread_flags_set(FuriThreadId thread_id, uint32_t flags);
/**
* @brief Clear the thread flags of the current FuriThread.
*
* @param[in] flags bitmask of thread flags to clear
* @return bitmask of thread flags before clearing
*/
uint32_t furi_thread_flags_clear(uint32_t flags);
/**
* @brief Get the thread flags of the current FuriThread.
* @return current bitmask of thread flags
*/
uint32_t furi_thread_flags_get(void);
/**
* @brief Wait for some thread flags to be set.
*
* @see FuriFlag for option and error flags.
*
* @param[in] flags bitmask of thread flags to wait for
* @param[in] options combination of option flags determining the behavior of the function
* @param[in] timeout maximum time to wait in milliseconds (use FuriWaitForever to wait forever)
* @return bitmask combination of received thread and error flags
*/
uint32_t furi_thread_flags_wait(uint32_t flags, uint32_t options, uint32_t timeout);
/**
* @brief Enumerate all threads.
*
* @param[out] thread_list pointer to the FuriThreadList container
*
* @return true on success, false otherwise
*/
bool furi_thread_enumerate(FuriThreadList* thread_list);
/**
* @brief Get the name of a thread based on its unique identifier.
*
* @param[in] thread_id unique identifier of the thread to be queried
* @return pointer to a zero-terminated string or NULL
*/
const char* furi_thread_get_name(FuriThreadId thread_id);
/**
* @brief Get the application id of a thread based on its unique identifier.
*
* @param[in] thread_id unique identifier of the thread to be queried
* @return pointer to a zero-terminated string
*/
const char* furi_thread_get_appid(FuriThreadId thread_id);
/**
* @brief Get thread stack watermark.
*
* @param[in] thread_id unique identifier of the thread to be queried
* @return stack watermark value
*/
uint32_t furi_thread_get_stack_space(FuriThreadId thread_id);
/**
* @brief Get the standard output callback for the current thead.
*
* @return pointer to the standard out callback function
*/
FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(void);
/** Set standard output callback for the current thread.
*
* @param[in] callback pointer to the callback function or NULL to clear
*/
void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback);
/** Write data to buffered standard output.
*
* @param[in] data pointer to the data to be written
* @param[in] size data size in bytes
* @return number of bytes that was actually written
*/
size_t furi_thread_stdout_write(const char* data, size_t size);
/**
* @brief Flush buffered data to standard output.
*
* @return error code value
*/
int32_t furi_thread_stdout_flush(void);
/**
* @brief Suspend a thread.
*
* Suspended threads are no more receiving any of the processor time.
*
* @param[in] thread_id unique identifier of the thread to be suspended
*/
void furi_thread_suspend(FuriThreadId thread_id);
/**
* @brief Resume a thread.
*
* @param[in] thread_id unique identifier of the thread to be resumed
*/
void furi_thread_resume(FuriThreadId thread_id);
/**
* @brief Test if a thread is suspended.
*
* @param[in] thread_id unique identifier of the thread to be queried
* @return true if thread is suspended, false otherwise
*/
bool furi_thread_is_suspended(FuriThreadId thread_id);
#ifdef __cplusplus
}
#endif