Thread, Timer and flash.sh improvements (#165)
- Various improvements to Thread and Timer: - Remove "mark as static" option as it is unused - Implemented core pinning for ESP32 platforms - Use `TickType_t` consistently (instead of `uint32_t`) - Use `enum class` instead of `enum` - Fix for `flash.sh` not working when using `pip` to install `esptool`
This commit is contained in:
parent
5d189fe5a3
commit
43c78c69d8
@ -14,7 +14,7 @@
|
|||||||
bool tdeck_init_lvgl() {
|
bool tdeck_init_lvgl() {
|
||||||
static lv_disp_t* display = nullptr;
|
static lv_disp_t* display = nullptr;
|
||||||
const lvgl_port_cfg_t lvgl_cfg = {
|
const lvgl_port_cfg_t lvgl_cfg = {
|
||||||
.task_priority = tt::THREAD_PRIORITY_RENDER,
|
.task_priority = static_cast<UBaseType_t>(tt::THREAD_PRIORITY_RENDER),
|
||||||
.task_stack = TDECK_LVGL_TASK_STACK_DEPTH,
|
.task_stack = TDECK_LVGL_TASK_STACK_DEPTH,
|
||||||
.task_affinity = -1, // core pinning
|
.task_affinity = -1, // core pinning
|
||||||
.task_max_sleep_ms = 500,
|
.task_max_sleep_ms = 500,
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
bool initLvgl() {
|
bool initLvgl() {
|
||||||
const lvgl_port_cfg_t lvgl_cfg = {
|
const lvgl_port_cfg_t lvgl_cfg = {
|
||||||
.task_priority = tt::THREAD_PRIORITY_RENDER,
|
.task_priority = static_cast<UBaseType_t>(tt::THREAD_PRIORITY_RENDER),
|
||||||
.task_stack = CORE2_LVGL_TASK_STACK_DEPTH,
|
.task_stack = CORE2_LVGL_TASK_STACK_DEPTH,
|
||||||
.task_affinity = -1, // core pinning
|
.task_affinity = -1, // core pinning
|
||||||
.task_max_sleep_ms = 500,
|
.task_max_sleep_ms = 500,
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
bool initLvgl() {
|
bool initLvgl() {
|
||||||
const lvgl_port_cfg_t lvgl_cfg = {
|
const lvgl_port_cfg_t lvgl_cfg = {
|
||||||
.task_priority = tt::THREAD_PRIORITY_RENDER,
|
.task_priority = static_cast<UBaseType_t>(tt::THREAD_PRIORITY_RENDER),
|
||||||
.task_stack = CORE2_LVGL_TASK_STACK_DEPTH,
|
.task_stack = CORE2_LVGL_TASK_STACK_DEPTH,
|
||||||
.task_affinity = -1, // core pinning
|
.task_affinity = -1, // core pinning
|
||||||
.task_max_sleep_ms = 500,
|
.task_max_sleep_ms = 500,
|
||||||
|
|||||||
@ -65,7 +65,7 @@ void lvgl_task_start() {
|
|||||||
"lvgl",
|
"lvgl",
|
||||||
8192,
|
8192,
|
||||||
nullptr,
|
nullptr,
|
||||||
tt::Thread::PriorityHigh, // Should be higher than main app task
|
static_cast<UBaseType_t>(tt::Thread::Priority::High), // Should be higher than main app task
|
||||||
nullptr
|
nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,7 @@ void freertosMain() {
|
|||||||
"main",
|
"main",
|
||||||
8192,
|
8192,
|
||||||
nullptr,
|
nullptr,
|
||||||
tt::Thread::PriorityNormal,
|
static_cast<UBaseType_t>(tt::Thread::Priority::Normal),
|
||||||
nullptr
|
nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
bool twodotfour_lvgl_init() {
|
bool twodotfour_lvgl_init() {
|
||||||
const lvgl_port_cfg_t lvgl_cfg = {
|
const lvgl_port_cfg_t lvgl_cfg = {
|
||||||
.task_priority = tt::THREAD_PRIORITY_RENDER,
|
.task_priority = static_cast<UBaseType_t>(tt::THREAD_PRIORITY_RENDER),
|
||||||
.task_stack = 8096,
|
.task_stack = 8096,
|
||||||
.task_affinity = -1, // core pinning
|
.task_affinity = -1, // core pinning
|
||||||
.task_max_sleep_ms = 500,
|
.task_max_sleep_ms = 500,
|
||||||
|
|||||||
@ -21,22 +21,35 @@ function is_bin_in_path {
|
|||||||
|
|
||||||
function require_bin {
|
function require_bin {
|
||||||
program=$1
|
program=$1
|
||||||
tip=$2
|
|
||||||
if ! is_bin_in_path $program; then
|
if ! is_bin_in_path $program; then
|
||||||
echo -e "\e[31m⚠️ $program not found!\n\t$tip\e[0m"
|
exit 1
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
require_bin esptool.py "install esptool from your package manager or install python and run 'pip install esptool'"
|
# Find either esptool (installed via system package manager) or esptool.py (installed via pip)
|
||||||
require_bin jq "install jq from your package manager or install python and run 'pip install jq'"
|
if ! is_bin_in_path esptool; then
|
||||||
|
if ! is_bin_in_path esptool.py; then
|
||||||
|
echo "\e[31m⚠️ esptool not found! Install it from your package manager or install python and run 'pip install esptool'\e[0m"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
esptoolPath=esptool.py
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
esptoolPath=esptool
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $1 -eq 0 ]]; then
|
# Ensure the port was specified
|
||||||
|
if [ -z "$1" ]; then
|
||||||
echo -e "\e[31m⚠️ Must Specify port as argument. For example:\n\tflash.sh /dev/ttyACM0\n\tflash.sh /dev/ttyUSB0\e[0m"
|
echo -e "\e[31m⚠️ Must Specify port as argument. For example:\n\tflash.sh /dev/ttyACM0\n\tflash.sh /dev/ttyUSB0\e[0m"
|
||||||
exit -1
|
exit -1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Take the flash_arg file contents and join each line in the file into a single line
|
||||||
|
flash_args=`grep \n Binaries/flash_args | awk '{print}' ORS=' '`
|
||||||
cd Binaries
|
cd Binaries
|
||||||
# Create flash command based on partitions
|
$esptoolPath --port $1 erase_flash
|
||||||
KEY_VALUES=`jq -r '.flash_files | keys[] as $k | "\($k) \(.[$k])"' flasher_args.json | tr "\n" " "`
|
$esptoolPath --port $1 write_flash $flash_args
|
||||||
esptool.py --port $1 erase_flash
|
cd -
|
||||||
esptool.py --port $1 --connect-attempts 10 -b 460800 write_flash $KEY_VALUES
|
|
||||||
|
|||||||
@ -28,12 +28,9 @@
|
|||||||
- Attach ELF data to wrapper app (as app data) (check that app state is "running"!) so you can run more than 1 external apps at a time.
|
- Attach ELF data to wrapper app (as app data) (check that app state is "running"!) so you can run more than 1 external apps at a time.
|
||||||
We'll need to keep track of all manifest instances, so that the wrapper can look up the relevant manifest for the relevant callbacks.
|
We'll need to keep track of all manifest instances, so that the wrapper can look up the relevant manifest for the relevant callbacks.
|
||||||
- T-Deck: Clear screen before turning on blacklight
|
- T-Deck: Clear screen before turning on blacklight
|
||||||
- Audio player app
|
|
||||||
- Audio recording app
|
|
||||||
- T-Deck: Use knob for UI selection
|
- T-Deck: Use knob for UI selection
|
||||||
- Crash monitoring: Keep track of which system phase the app crashed in (e.g. which app in which state)
|
- Crash monitoring: Keep track of which system phase the app crashed in (e.g. which app in which state)
|
||||||
- AppContext's onResult should pass the app id (or launch request id!) that was started, so we can differentiate between multiple types of apps being launched
|
- AppContext's onResult should pass the app id (or launch request id!) that was started, so we can differentiate between multiple types of apps being launched
|
||||||
- Loader: Use main dispatcher instead of Thread
|
|
||||||
- Create more unit tests for `tactility-core` and `tactility` (PC-only for now)
|
- Create more unit tests for `tactility-core` and `tactility` (PC-only for now)
|
||||||
- Show a warning screen if firmware encryption or secure boot are off when saving WiFi credentials.
|
- Show a warning screen if firmware encryption or secure boot are off when saving WiFi credentials.
|
||||||
- Show a warning screen when a user plugs in the SD card on a device that only supports mounting at boot.
|
- Show a warning screen when a user plugs in the SD card on a device that only supports mounting at boot.
|
||||||
@ -45,6 +42,8 @@
|
|||||||
- Support hot-plugging SD card
|
- Support hot-plugging SD card
|
||||||
|
|
||||||
# Nice-to-haves
|
# Nice-to-haves
|
||||||
|
- Audio player app
|
||||||
|
- Audio recording app
|
||||||
- OTA updates
|
- OTA updates
|
||||||
- Web flasher
|
- Web flasher
|
||||||
- T-Deck Plus: Create separate board config?
|
- T-Deck Plus: Create separate board config?
|
||||||
|
|||||||
@ -74,8 +74,6 @@ const struct esp_elfsym elf_symbols[] {
|
|||||||
ESP_ELFSYM_EXPORT(tt_thread_alloc_ext),
|
ESP_ELFSYM_EXPORT(tt_thread_alloc_ext),
|
||||||
ESP_ELFSYM_EXPORT(tt_thread_free),
|
ESP_ELFSYM_EXPORT(tt_thread_free),
|
||||||
ESP_ELFSYM_EXPORT(tt_thread_set_name),
|
ESP_ELFSYM_EXPORT(tt_thread_set_name),
|
||||||
ESP_ELFSYM_EXPORT(tt_thread_mark_as_static),
|
|
||||||
ESP_ELFSYM_EXPORT(tt_thread_is_marked_as_static),
|
|
||||||
ESP_ELFSYM_EXPORT(tt_thread_set_stack_size),
|
ESP_ELFSYM_EXPORT(tt_thread_set_stack_size),
|
||||||
ESP_ELFSYM_EXPORT(tt_thread_set_callback),
|
ESP_ELFSYM_EXPORT(tt_thread_set_callback),
|
||||||
ESP_ELFSYM_EXPORT(tt_thread_set_priority),
|
ESP_ELFSYM_EXPORT(tt_thread_set_priority),
|
||||||
|
|||||||
@ -31,14 +31,6 @@ void tt_thread_set_name(ThreadHandle handle, const char* name) {
|
|||||||
HANDLE_AS_THREAD(handle)->setName(name);
|
HANDLE_AS_THREAD(handle)->setName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tt_thread_mark_as_static(ThreadHandle handle) {
|
|
||||||
HANDLE_AS_THREAD(handle)->markAsStatic();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tt_thread_is_marked_as_static(ThreadHandle handle) {
|
|
||||||
return HANDLE_AS_THREAD(handle)->isMarkedAsStatic();
|
|
||||||
}
|
|
||||||
|
|
||||||
void tt_thread_set_stack_size(ThreadHandle handle, size_t size) {
|
void tt_thread_set_stack_size(ThreadHandle handle, size_t size) {
|
||||||
HANDLE_AS_THREAD(handle)->setStackSize(size);
|
HANDLE_AS_THREAD(handle)->setStackSize(size);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,14 +38,14 @@ typedef int32_t (*ThreadCallback)(void* context);
|
|||||||
typedef void (*ThreadStateCallback)(ThreadState state, void* context);
|
typedef void (*ThreadStateCallback)(ThreadState state, void* context);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ThreadPriorityNone = 0, /**< Uninitialized, choose system default */
|
ThreadPriorityNone = 0U, /**< Uninitialized, choose system default */
|
||||||
ThreadPriorityIdle = 1,
|
ThreadPriorityIdle = 1U,
|
||||||
ThreadPriorityLowest = 2,
|
ThreadPriorityLowest = 2U,
|
||||||
ThreadPriorityLow = 3,
|
ThreadPriorityLow = 3U,
|
||||||
ThreadPriorityNormal = 4,
|
ThreadPriorityNormal = 4U,
|
||||||
ThreadPriorityHigh = 5,
|
ThreadPriorityHigh = 5U,
|
||||||
ThreadPriorityHigher = 6,
|
ThreadPriorityHigher = 6U,
|
||||||
ThreadPriorityHighest = 7
|
ThreadPriorityHighest = 7U
|
||||||
} ThreadPriority;
|
} ThreadPriority;
|
||||||
|
|
||||||
ThreadHandle tt_thread_alloc();
|
ThreadHandle tt_thread_alloc();
|
||||||
@ -57,8 +57,6 @@ ThreadHandle tt_thread_alloc_ext(
|
|||||||
);
|
);
|
||||||
void tt_thread_free(ThreadHandle handle);
|
void tt_thread_free(ThreadHandle handle);
|
||||||
void tt_thread_set_name(ThreadHandle handle, const char* name);
|
void tt_thread_set_name(ThreadHandle handle, const char* name);
|
||||||
void tt_thread_mark_as_static(ThreadHandle handle);
|
|
||||||
bool tt_thread_is_marked_as_static(ThreadHandle handle);
|
|
||||||
void tt_thread_set_stack_size(ThreadHandle handle, size_t size);
|
void tt_thread_set_stack_size(ThreadHandle handle, size_t size);
|
||||||
void tt_thread_set_callback(ThreadHandle handle, ThreadCallback callback, void* _Nullable callbackContext);
|
void tt_thread_set_callback(ThreadHandle handle, ThreadCallback callback, void* _Nullable callbackContext);
|
||||||
void tt_thread_set_priority(ThreadHandle handle, ThreadPriority priority);
|
void tt_thread_set_priority(ThreadHandle handle, ThreadPriority priority);
|
||||||
|
|||||||
@ -58,8 +58,8 @@ bool tt_timer_set_pending_callback(TimerHandle handle, TimerPendingCallback call
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tt_timer_set_thread_priority(TimerHandle handle, TimerThreadPriority priority) {
|
void tt_timer_set_thread_priority(TimerHandle handle, ThreadPriority priority) {
|
||||||
((TimerWrapper*)handle)->timer->setThreadPriority((tt::Timer::ThreadPriority)priority);
|
((TimerWrapper*)handle)->timer->setThreadPriority((tt::Thread::Priority)priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "tt_thread.h"
|
||||||
#include <freertos/FreeRTOS.h>
|
#include <freertos/FreeRTOS.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -16,11 +17,6 @@ typedef enum {
|
|||||||
TimerTypePeriodic = 1 ///< Repeating timer.
|
TimerTypePeriodic = 1 ///< Repeating timer.
|
||||||
} TimerType;
|
} TimerType;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
TimerThreadPriorityNormal, /**< Lower then other threads */
|
|
||||||
TimerThreadPriorityElevated, /**< Same as other threads */
|
|
||||||
} TimerThreadPriority;
|
|
||||||
|
|
||||||
typedef void (*TimerCallback)(void* context);
|
typedef void (*TimerCallback)(void* context);
|
||||||
typedef void (*TimerPendingCallback)(void* context, uint32_t arg);
|
typedef void (*TimerPendingCallback)(void* context, uint32_t arg);
|
||||||
|
|
||||||
@ -32,7 +28,7 @@ bool tt_timer_stop(TimerHandle handle);
|
|||||||
bool tt_timer_is_running(TimerHandle handle);
|
bool tt_timer_is_running(TimerHandle handle);
|
||||||
uint32_t tt_timer_get_expire_time(TimerHandle handle);
|
uint32_t tt_timer_get_expire_time(TimerHandle handle);
|
||||||
bool tt_timer_set_pending_callback(TimerHandle handle, TimerPendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeoutTicks);
|
bool tt_timer_set_pending_callback(TimerHandle handle, TimerPendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeoutTicks);
|
||||||
void tt_timer_set_thread_priority(TimerHandle handle, TimerThreadPriority priority);
|
void tt_timer_set_thread_priority(TimerHandle handle, ThreadPriority priority);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ DispatcherThread::DispatcherThread(const std::string& threadName, size_t threadS
|
|||||||
}
|
}
|
||||||
|
|
||||||
DispatcherThread::~DispatcherThread() {
|
DispatcherThread::~DispatcherThread() {
|
||||||
if (thread->getState() != Thread::StateStopped) {
|
if (thread->getState() != Thread::State::Stopped) {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,7 @@ namespace tt {
|
|||||||
#define THREAD_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_TASK_NOTIFY) - 1U))
|
#define THREAD_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_TASK_NOTIFY) - 1U))
|
||||||
#define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U))
|
#define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U))
|
||||||
|
|
||||||
static_assert(Thread::PriorityHighest <= TT_CONFIG_THREAD_MAX_PRIORITIES, "highest thread priority is higher than max priority");
|
static_assert(static_cast<UBaseType_t>(Thread::Priority::Critical) <= TT_CONFIG_THREAD_MAX_PRIORITIES, "highest thread priority is higher than max priority");
|
||||||
static_assert(TT_CONFIG_THREAD_MAX_PRIORITIES <= configMAX_PRIORITIES, "highest tactility priority is higher than max FreeRTOS priority");
|
static_assert(TT_CONFIG_THREAD_MAX_PRIORITIES <= configMAX_PRIORITIES, "highest tactility priority is higher than max FreeRTOS priority");
|
||||||
|
|
||||||
void setState(Thread::Data* data, Thread::State state) {
|
void setState(Thread::Data* data, Thread::State state) {
|
||||||
@ -29,6 +29,8 @@ void setState(Thread::Data* data, Thread::State state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static_assert(configSUPPORT_DYNAMIC_ALLOCATION == 1);
|
||||||
|
|
||||||
/** Catch threads that are trying to exit wrong way */
|
/** Catch threads that are trying to exit wrong way */
|
||||||
__attribute__((__noreturn__)) void thread_catch() { //-V1082
|
__attribute__((__noreturn__)) void thread_catch() { //-V1082
|
||||||
// If you're here it means you're probably doing something wrong
|
// If you're here it means you're probably doing something wrong
|
||||||
@ -47,20 +49,12 @@ static void thread_body(void* context) {
|
|||||||
tt_assert(pvTaskGetThreadLocalStoragePointer(nullptr, 0) == nullptr);
|
tt_assert(pvTaskGetThreadLocalStoragePointer(nullptr, 0) == nullptr);
|
||||||
vTaskSetThreadLocalStoragePointer(nullptr, 0, data->thread);
|
vTaskSetThreadLocalStoragePointer(nullptr, 0, data->thread);
|
||||||
|
|
||||||
tt_assert(data->state == Thread::StateStarting);
|
tt_assert(data->state == Thread::State::Starting);
|
||||||
setState(data, Thread::StateRunning);
|
setState(data, Thread::State::Running);
|
||||||
data->callbackResult = data->callback(data->callbackContext);
|
data->callbackResult = data->callback(data->callbackContext);
|
||||||
tt_assert(data->state == Thread::StateRunning);
|
tt_assert(data->state == Thread::State::Running);
|
||||||
|
|
||||||
if (data->isStatic) {
|
setState(data, Thread::State::Stopped);
|
||||||
TT_LOG_I(
|
|
||||||
TAG,
|
|
||||||
"%s static task memory will not be reclaimed",
|
|
||||||
data->name.empty() ? "<unnamed service>" : data->name.c_str()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
setState(data, Thread::StateStopped);
|
|
||||||
|
|
||||||
vTaskSetThreadLocalStoragePointer(nullptr, 0, nullptr);
|
vTaskSetThreadLocalStoragePointer(nullptr, 0, nullptr);
|
||||||
data->taskHandle = nullptr;
|
data->taskHandle = nullptr;
|
||||||
@ -73,15 +67,14 @@ Thread::Thread() :
|
|||||||
data({
|
data({
|
||||||
.thread = nullptr,
|
.thread = nullptr,
|
||||||
.taskHandle = nullptr,
|
.taskHandle = nullptr,
|
||||||
.state = StateStopped,
|
.state = State::Stopped,
|
||||||
.callback = nullptr,
|
.callback = nullptr,
|
||||||
.callbackContext = nullptr,
|
.callbackContext = nullptr,
|
||||||
.callbackResult = 0,
|
.callbackResult = 0,
|
||||||
.stateCallback = nullptr,
|
.stateCallback = nullptr,
|
||||||
.stateCallbackContext = nullptr,
|
.stateCallbackContext = nullptr,
|
||||||
.name = std::string(),
|
.name = std::string(),
|
||||||
.priority = PriorityNormal,
|
.priority = Priority::Normal,
|
||||||
.isStatic = false,
|
|
||||||
.stackSize = 0,
|
.stackSize = 0,
|
||||||
}) { }
|
}) { }
|
||||||
|
|
||||||
@ -89,64 +82,56 @@ Thread::Thread(
|
|||||||
const std::string& name,
|
const std::string& name,
|
||||||
configSTACK_DEPTH_TYPE stackSize,
|
configSTACK_DEPTH_TYPE stackSize,
|
||||||
Callback callback,
|
Callback callback,
|
||||||
_Nullable void* callbackContext) :
|
_Nullable void* callbackContext,
|
||||||
|
portBASE_TYPE affinity
|
||||||
|
) :
|
||||||
data({
|
data({
|
||||||
.thread = nullptr,
|
.thread = nullptr,
|
||||||
.taskHandle = nullptr,
|
.taskHandle = nullptr,
|
||||||
.state = StateStopped,
|
.state = State::Stopped,
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.callbackContext = callbackContext,
|
.callbackContext = callbackContext,
|
||||||
.callbackResult = 0,
|
.callbackResult = 0,
|
||||||
.stateCallback = nullptr,
|
.stateCallback = nullptr,
|
||||||
.stateCallbackContext = nullptr,
|
.stateCallbackContext = nullptr,
|
||||||
.name = name,
|
.name = name,
|
||||||
.priority = PriorityNormal,
|
.priority = Priority::Normal,
|
||||||
.isStatic = false,
|
|
||||||
.stackSize = stackSize,
|
.stackSize = stackSize,
|
||||||
|
.affinity = affinity
|
||||||
}) { }
|
}) { }
|
||||||
|
|
||||||
Thread::~Thread() {
|
Thread::~Thread() {
|
||||||
// Ensure that use join before free
|
// Ensure that use join before free
|
||||||
tt_assert(data.state == StateStopped);
|
tt_assert(data.state == State::Stopped);
|
||||||
tt_assert(data.taskHandle == nullptr);
|
tt_assert(data.taskHandle == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::setName(const std::string& newName) {
|
void Thread::setName(const std::string& newName) {
|
||||||
tt_assert(data.state == StateStopped);
|
tt_assert(data.state == State::Stopped);
|
||||||
data.name = newName;
|
data.name = newName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::markAsStatic() {
|
|
||||||
data.isStatic = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Thread::isMarkedAsStatic() const {
|
|
||||||
return data.isStatic;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::setStackSize(size_t stackSize) {
|
void Thread::setStackSize(size_t stackSize) {
|
||||||
tt_assert(data.state == StateStopped);
|
tt_assert(data.state == State::Stopped);
|
||||||
tt_assert(stackSize % 4 == 0);
|
tt_assert(stackSize % 4 == 0);
|
||||||
data.stackSize = stackSize;
|
data.stackSize = stackSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::setCallback(Callback callback, _Nullable void* callbackContext) {
|
void Thread::setCallback(Callback callback, _Nullable void* callbackContext) {
|
||||||
tt_assert(data.state == StateStopped);
|
tt_assert(data.state == State::Stopped);
|
||||||
data.callback = callback;
|
data.callback = callback;
|
||||||
data.callbackContext = callbackContext;
|
data.callbackContext = callbackContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::setPriority(Priority priority) {
|
void Thread::setPriority(Priority priority) {
|
||||||
tt_assert(data.state == StateStopped);
|
tt_assert(data.state == State::Stopped);
|
||||||
tt_assert(priority >= 0 && priority <= TT_CONFIG_THREAD_MAX_PRIORITIES);
|
|
||||||
data.priority = priority;
|
data.priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::setStateCallback(StateCallback callback, _Nullable void* callbackContext) {
|
void Thread::setStateCallback(StateCallback callback, _Nullable void* callbackContext) {
|
||||||
tt_assert(data.state == StateStopped);
|
tt_assert(data.state == State::Stopped);
|
||||||
data.stateCallback = callback;
|
data.stateCallback = callback;
|
||||||
data.stateCallbackContext = callbackContext;
|
data.stateCallbackContext = callbackContext;
|
||||||
}
|
}
|
||||||
@ -157,38 +142,49 @@ Thread::State Thread::getState() const {
|
|||||||
|
|
||||||
void Thread::start() {
|
void Thread::start() {
|
||||||
tt_assert(data.callback);
|
tt_assert(data.callback);
|
||||||
tt_assert(data.state == StateStopped);
|
tt_assert(data.state == State::Stopped);
|
||||||
tt_assert(data.stackSize > 0 && data.stackSize < (UINT16_MAX * sizeof(StackType_t)));
|
tt_assert(data.stackSize > 0U && data.stackSize < (UINT16_MAX * sizeof(StackType_t)));
|
||||||
|
|
||||||
setState(&data, StateStarting);
|
setState(&data, State::Starting);
|
||||||
|
|
||||||
uint32_t stack_depth = data.stackSize / sizeof(StackType_t);
|
uint32_t stack_depth = data.stackSize / sizeof(StackType_t);
|
||||||
if (data.isStatic) {
|
|
||||||
#if configSUPPORT_STATIC_ALLOCATION == 1
|
BaseType_t result;
|
||||||
data.taskHandle = xTaskCreateStatic(
|
if (data.affinity != -1) {
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
result = xTaskCreatePinnedToCore(
|
||||||
thread_body,
|
thread_body,
|
||||||
data.name.c_str(),
|
data.name.c_str(),
|
||||||
stack_depth,
|
stack_depth,
|
||||||
&data,
|
this,
|
||||||
data.priority,
|
static_cast<UBaseType_t>(data.priority),
|
||||||
static_cast<StackType_t*>(malloc(sizeof(StackType_t) * stack_depth)),
|
&(data.taskHandle),
|
||||||
static_cast<StaticTask_t*>(malloc(sizeof(StaticTask_t)))
|
data.affinity
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
TT_LOG_E(TAG, "static tasks are not supported by current FreeRTOS config/platform - creating regular one");
|
TT_LOG_W(TAG, "Pinned tasks are not supported by current FreeRTOS platform - creating regular one");
|
||||||
BaseType_t result = xTaskCreate(
|
result = xTaskCreate(
|
||||||
thread_body, data.name.c_str(), stack_depth, this, data.priority, &(data.taskHandle)
|
thread_body,
|
||||||
|
data.name.c_str(),
|
||||||
|
stack_depth,
|
||||||
|
this,
|
||||||
|
static_cast<UBaseType_t>(data.priority),
|
||||||
|
&(data.taskHandle)
|
||||||
);
|
);
|
||||||
tt_check(result == pdPASS);
|
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
BaseType_t result = xTaskCreate(
|
result = xTaskCreate(
|
||||||
thread_body, data.name.c_str(), stack_depth, this, data.priority, &(data.taskHandle)
|
thread_body,
|
||||||
|
data.name.c_str(),
|
||||||
|
stack_depth,
|
||||||
|
this,
|
||||||
|
static_cast<UBaseType_t>(data.priority),
|
||||||
|
&(data.taskHandle)
|
||||||
);
|
);
|
||||||
tt_check(result == pdPASS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tt_check(data.state == StateStopped || data.taskHandle);
|
tt_check(result == pdPASS);
|
||||||
|
tt_check(data.state == State::Stopped || data.taskHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::join() {
|
bool Thread::join() {
|
||||||
@ -205,12 +201,12 @@ bool Thread::join() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadId Thread::getId() {
|
ThreadId Thread::getId() const {
|
||||||
return data.taskHandle;
|
return data.taskHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t Thread::getReturnCode() {
|
int32_t Thread::getReturnCode() const {
|
||||||
tt_assert(data.state == StateStopped);
|
tt_assert(data.state == State::Stopped);
|
||||||
return data.callbackResult;
|
return data.callbackResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,8 +220,7 @@ Thread* thread_get_current() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void thread_set_current_priority(Thread::Priority priority) {
|
void thread_set_current_priority(Thread::Priority priority) {
|
||||||
UBaseType_t new_priority = priority ? priority : Thread::PriorityNormal;
|
vTaskPrioritySet(nullptr, static_cast<UBaseType_t>(priority));
|
||||||
vTaskPrioritySet(nullptr, new_priority);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread::Priority thread_get_current_priority() {
|
Thread::Priority thread_get_current_priority() {
|
||||||
@ -237,14 +232,6 @@ void thread_yield() {
|
|||||||
taskYIELD();
|
taskYIELD();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool thread_mark_is_static(ThreadId thread_id) {
|
|
||||||
auto hTask = (TaskHandle_t)thread_id;
|
|
||||||
assert(!TT_IS_IRQ_MODE() && (hTask != nullptr));
|
|
||||||
auto* thread = (Thread*)pvTaskGetThreadLocalStoragePointer(hTask, 0);
|
|
||||||
assert(thread != nullptr);
|
|
||||||
return thread->isMarkedAsStatic();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t thread_flags_set(ThreadId thread_id, uint32_t flags) {
|
uint32_t thread_flags_set(ThreadId thread_id, uint32_t flags) {
|
||||||
auto hTask = (TaskHandle_t)thread_id;
|
auto hTask = (TaskHandle_t)thread_id;
|
||||||
uint32_t rflags;
|
uint32_t rflags;
|
||||||
|
|||||||
@ -16,24 +16,23 @@ typedef TaskHandle_t ThreadId;
|
|||||||
class Thread {
|
class Thread {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef enum {
|
enum class State{
|
||||||
StateStopped,
|
Stopped,
|
||||||
StateStarting,
|
Starting,
|
||||||
StateRunning,
|
Running,
|
||||||
} State;
|
};
|
||||||
|
|
||||||
/** ThreadPriority */
|
/** ThreadPriority */
|
||||||
typedef enum {
|
enum class Priority : UBaseType_t {
|
||||||
PriorityNone = 0, /**< Uninitialized, choose system default */
|
None = 0U, /**< Uninitialized, choose system default */
|
||||||
PriorityIdle = 1,
|
Idle = 1U,
|
||||||
PriorityLowest = 2,
|
Lower = 2U,
|
||||||
PriorityLow = 3,
|
Low = 3U,
|
||||||
PriorityNormal = 4,
|
Normal = 4U,
|
||||||
PriorityHigh = 5,
|
High = 5U,
|
||||||
PriorityHigher = 6,
|
Higher = 6U,
|
||||||
PriorityHighest = 7
|
Critical = 7U
|
||||||
} Priority;
|
};
|
||||||
|
|
||||||
|
|
||||||
/** ThreadCallback Your callback to run in new thread
|
/** ThreadCallback Your callback to run in new thread
|
||||||
* @warning never use osThreadExit in Thread
|
* @warning never use osThreadExit in Thread
|
||||||
@ -55,41 +54,33 @@ public:
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
Thread* thread;
|
Thread* thread;
|
||||||
TaskHandle_t taskHandle;
|
TaskHandle_t taskHandle;
|
||||||
|
|
||||||
State state;
|
State state;
|
||||||
|
|
||||||
Callback callback;
|
Callback callback;
|
||||||
void* callbackContext;
|
void* callbackContext;
|
||||||
int32_t callbackResult;
|
int32_t callbackResult;
|
||||||
|
|
||||||
StateCallback stateCallback;
|
StateCallback stateCallback;
|
||||||
void* stateCallbackContext;
|
void* stateCallbackContext;
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
Priority priority;
|
Priority priority;
|
||||||
|
|
||||||
// Keep all non-alignable byte types in one place,
|
|
||||||
// this ensures that the size of this structure is minimal
|
|
||||||
bool isStatic;
|
|
||||||
|
|
||||||
configSTACK_DEPTH_TYPE stackSize;
|
configSTACK_DEPTH_TYPE stackSize;
|
||||||
|
portBASE_TYPE affinity;
|
||||||
} Data;
|
} Data;
|
||||||
|
|
||||||
Thread();
|
Thread();
|
||||||
|
|
||||||
/** Allocate Thread, shortcut version
|
/** Allocate Thread, shortcut version
|
||||||
* @param[in] name
|
* @param[in] name the name of the thread
|
||||||
* @param[in] stack_size
|
* @param[in] stackSize in bytes
|
||||||
* @param[in] callback
|
* @param[in] callback
|
||||||
* @param[in] callbackContext
|
* @param[in] callbackContext
|
||||||
* @return Thread*
|
* @param[in] affinity Which CPU core to pin this task to, -1 means unpinned (only works on ESP32)
|
||||||
*/
|
*/
|
||||||
Thread(
|
Thread(
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
configSTACK_DEPTH_TYPE stackSize,
|
configSTACK_DEPTH_TYPE stackSize,
|
||||||
Callback callback,
|
Callback callback,
|
||||||
_Nullable void* callbackContext
|
_Nullable void* callbackContext,
|
||||||
|
portBASE_TYPE affinity = -1
|
||||||
);
|
);
|
||||||
|
|
||||||
~Thread();
|
~Thread();
|
||||||
@ -99,16 +90,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setName(const std::string& name);
|
void setName(const std::string& name);
|
||||||
|
|
||||||
/** Mark thread as service
|
|
||||||
* The service cannot be stopped or removed, and cannot exit from the thread body
|
|
||||||
*/
|
|
||||||
void markAsStatic();
|
|
||||||
|
|
||||||
/** Check if thread is as service
|
|
||||||
* If true, the service cannot be stopped or removed, and cannot exit from the thread body
|
|
||||||
*/
|
|
||||||
bool isMarkedAsStatic() const;
|
|
||||||
|
|
||||||
/** Set Thread stack size
|
/** Set Thread stack size
|
||||||
* @param[in] stackSize stack size in bytes
|
* @param[in] stackSize stack size in bytes
|
||||||
*/
|
*/
|
||||||
@ -137,8 +118,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
State getState() const;
|
State getState() const;
|
||||||
|
|
||||||
/** Start Thread
|
/** Start Thread */
|
||||||
*/
|
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
/** Join Thread
|
/** Join Thread
|
||||||
@ -150,10 +130,10 @@ public:
|
|||||||
/** Get FreeRTOS ThreadId for Thread instance
|
/** Get FreeRTOS ThreadId for Thread instance
|
||||||
* @return ThreadId or nullptr
|
* @return ThreadId or nullptr
|
||||||
*/
|
*/
|
||||||
ThreadId getId();
|
ThreadId getId() const;
|
||||||
|
|
||||||
/** @return thread return code */
|
/** @return thread return code */
|
||||||
int32_t getReturnCode();
|
int32_t getReturnCode() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -161,9 +141,9 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define THREAD_PRIORITY_APP Thread::PriorityNormal
|
#define THREAD_PRIORITY_APP Thread::PriorityNormal
|
||||||
#define THREAD_PRIORITY_SERVICE Thread::PriorityHigh
|
#define THREAD_PRIORITY_SERVICE Thread::Priority::High
|
||||||
#define THREAD_PRIORITY_RENDER Thread::PriorityHigher
|
#define THREAD_PRIORITY_RENDER Thread::Priority::Higher
|
||||||
#define THREAD_PRIORITY_ISR (TT_CONFIG_THREAD_MAX_PRIORITIES - 1)
|
#define THREAD_PRIORITY_ISR Thread::Priority::Critical
|
||||||
|
|
||||||
/** Set current thread priority
|
/** Set current thread priority
|
||||||
* @param[in] priority ThreadPriority value
|
* @param[in] priority ThreadPriority value
|
||||||
@ -220,10 +200,4 @@ void thread_resume(ThreadId threadId);
|
|||||||
*/
|
*/
|
||||||
bool thread_is_suspended(ThreadId threadId);
|
bool thread_is_suspended(ThreadId threadId);
|
||||||
|
|
||||||
/** Check if the thread was created with static memory
|
|
||||||
* @param[in] threadId thread id
|
|
||||||
* @return true if thread memory is static
|
|
||||||
*/
|
|
||||||
bool thread_mark_is_static(ThreadId threadId);
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -36,16 +36,16 @@ Timer::~Timer() {
|
|||||||
tt_check(xTimerDelete(timerHandle, portMAX_DELAY) == pdPASS);
|
tt_check(xTimerDelete(timerHandle, portMAX_DELAY) == pdPASS);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Timer::start(uint32_t intervalTicks) {
|
bool Timer::start(TickType_t interval) {
|
||||||
tt_assert(!TT_IS_ISR());
|
tt_assert(!TT_IS_ISR());
|
||||||
tt_assert(intervalTicks < portMAX_DELAY);
|
tt_assert(interval < portMAX_DELAY);
|
||||||
return xTimerChangePeriod(timerHandle, intervalTicks, portMAX_DELAY) == pdPASS;
|
return xTimerChangePeriod(timerHandle, interval, portMAX_DELAY) == pdPASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Timer::restart(uint32_t intervalTicks) {
|
bool Timer::restart(TickType_t interval) {
|
||||||
tt_assert(!TT_IS_ISR());
|
tt_assert(!TT_IS_ISR());
|
||||||
tt_assert(intervalTicks < portMAX_DELAY);
|
tt_assert(interval < portMAX_DELAY);
|
||||||
return xTimerChangePeriod(timerHandle, intervalTicks, portMAX_DELAY) == pdPASS &&
|
return xTimerChangePeriod(timerHandle, interval, portMAX_DELAY) == pdPASS &&
|
||||||
xTimerReset(timerHandle, portMAX_DELAY) == pdPASS;
|
xTimerReset(timerHandle, portMAX_DELAY) == pdPASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,9 +59,9 @@ bool Timer::isRunning() {
|
|||||||
return xTimerIsTimerActive(timerHandle) == pdTRUE;
|
return xTimerIsTimerActive(timerHandle) == pdTRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Timer::getExpireTime() {
|
TickType_t Timer::getExpireTime() {
|
||||||
tt_assert(!TT_IS_ISR());
|
tt_assert(!TT_IS_ISR());
|
||||||
return (uint32_t)xTimerGetExpiryTime(timerHandle);
|
return xTimerGetExpiryTime(timerHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Timer::setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeout) {
|
bool Timer::setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeout) {
|
||||||
@ -73,19 +73,13 @@ bool Timer::setPendingCallback(PendingCallback callback, void* callbackContext,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::setThreadPriority(ThreadPriority priority) {
|
void Timer::setThreadPriority(Thread::Priority priority) {
|
||||||
tt_assert(!TT_IS_ISR());
|
tt_assert(!TT_IS_ISR());
|
||||||
|
|
||||||
TaskHandle_t task_handle = xTimerGetTimerDaemonTaskHandle();
|
TaskHandle_t task_handle = xTimerGetTimerDaemonTaskHandle();
|
||||||
tt_assert(task_handle); // Don't call this method before timer task start
|
tt_assert(task_handle); // Don't call this method before timer task start
|
||||||
|
|
||||||
if (priority == TimerThreadPriorityNormal) {
|
vTaskPrioritySet(task_handle, static_cast<UBaseType_t>(priority));
|
||||||
vTaskPrioritySet(task_handle, configTIMER_TASK_PRIORITY);
|
|
||||||
} else if (priority == TimerThreadPriorityElevated) {
|
|
||||||
vTaskPrioritySet(task_handle, configMAX_PRIORITIES - 1);
|
|
||||||
} else {
|
|
||||||
tt_crash("Unsupported timer priority");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include "CoreTypes.h"
|
#include "CoreTypes.h"
|
||||||
|
|
||||||
#include "RtosCompatTimers.h"
|
#include "RtosCompatTimers.h"
|
||||||
|
#include "Thread.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
@ -34,17 +35,17 @@ public:
|
|||||||
|
|
||||||
/** Start timer
|
/** Start timer
|
||||||
* @warning This is asynchronous call, real operation will happen as soon as timer service process this request.
|
* @warning This is asynchronous call, real operation will happen as soon as timer service process this request.
|
||||||
* @param[in] ticks The interval in ticks
|
* @param[in] interval The interval in ticks
|
||||||
* @return success result
|
* @return success result
|
||||||
*/
|
*/
|
||||||
bool start(uint32_t intervalTicks);
|
bool start(TickType_t interval);
|
||||||
|
|
||||||
/** Restart timer with previous timeout value
|
/** Restart timer with previous timeout value
|
||||||
* @warning This is asynchronous call, real operation will happen as soon as timer service process this request.
|
* @warning This is asynchronous call, real operation will happen as soon as timer service process this request.
|
||||||
* @param[in] ticks The interval in ticks
|
* @param[in] interval The interval in ticks
|
||||||
* @return success result
|
* @return success result
|
||||||
*/
|
*/
|
||||||
bool restart(uint32_t intervalTicks);
|
bool restart(TickType_t interval);
|
||||||
|
|
||||||
/** Stop timer
|
/** Stop timer
|
||||||
* @warning This is asynchronous call, real operation will happen as soon as timer service process this request.
|
* @warning This is asynchronous call, real operation will happen as soon as timer service process this request.
|
||||||
@ -61,7 +62,7 @@ public:
|
|||||||
/** Get timer expire time
|
/** Get timer expire time
|
||||||
* @return expire tick
|
* @return expire tick
|
||||||
*/
|
*/
|
||||||
uint32_t getExpireTime();
|
TickType_t getExpireTime();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls xTimerPendFunctionCall internally.
|
* Calls xTimerPendFunctionCall internally.
|
||||||
@ -69,18 +70,19 @@ public:
|
|||||||
* @param[in] callbackContext the first function argument
|
* @param[in] callbackContext the first function argument
|
||||||
* @param[in] callbackArg the second function argument
|
* @param[in] callbackArg the second function argument
|
||||||
* @param[in] timeout the function timeout (must set to 0 in ISR mode)
|
* @param[in] timeout the function timeout (must set to 0 in ISR mode)
|
||||||
|
* @return true on success
|
||||||
*/
|
*/
|
||||||
bool setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeout);
|
bool setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeout);
|
||||||
|
|
||||||
typedef enum {
|
enum class Priority{
|
||||||
TimerThreadPriorityNormal, /**< Lower then other threads */
|
Normal, /**< Lower then other threads */
|
||||||
TimerThreadPriorityElevated, /**< Same as other threads */
|
Elevated, /**< Same as other threads */
|
||||||
} ThreadPriority;
|
};
|
||||||
|
|
||||||
/** Set Timer thread priority
|
/** Set Timer thread priority
|
||||||
* @param[in] priority The priority
|
* @param[in] priority The priority
|
||||||
*/
|
*/
|
||||||
void setThreadPriority(ThreadPriority priority);
|
void setThreadPriority(Thread::Priority priority);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -23,12 +23,12 @@ TEST_CASE("a mutex can block a thread") {
|
|||||||
thread.start();
|
thread.start();
|
||||||
|
|
||||||
kernel::delayMillis(5);
|
kernel::delayMillis(5);
|
||||||
CHECK_EQ(thread.getState(), Thread::StateRunning);
|
CHECK_EQ(thread.getState(), Thread::State::Running);
|
||||||
|
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
|
|
||||||
kernel::delayMillis(5);
|
kernel::delayMillis(5);
|
||||||
CHECK_EQ(thread.getState(), Thread::StateStopped);
|
CHECK_EQ(thread.getState(), Thread::State::Stopped);
|
||||||
|
|
||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,13 +78,13 @@ TEST_CASE("thread state should be correct") {
|
|||||||
&interruptable_thread,
|
&interruptable_thread,
|
||||||
&interrupted
|
&interrupted
|
||||||
);
|
);
|
||||||
CHECK_EQ(thread->getState(), Thread::StateStopped);
|
CHECK_EQ(thread->getState(), Thread::State::Stopped);
|
||||||
thread->start();
|
thread->start();
|
||||||
Thread::State state = thread->getState();
|
Thread::State state = thread->getState();
|
||||||
CHECK((state == Thread::StateStarting || state == Thread::StateRunning));
|
CHECK((state == Thread::State::Starting || state == Thread::State::Running));
|
||||||
interrupted = true;
|
interrupted = true;
|
||||||
thread->join();
|
thread->join();
|
||||||
CHECK_EQ(thread->getState(), Thread::StateStopped);
|
CHECK_EQ(thread->getState(), Thread::State::Stopped);
|
||||||
delete thread;
|
delete thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user