Merge pull request #7872 from kjbracey-arm/thisthread

Add ThisThread namespace and deprecate static Thread methods
pull/7960/head
Cruz Monrreal 2018-09-02 15:10:18 -05:00 committed by GitHub
commit 48232be98e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 776 additions and 280 deletions

View File

@ -61,13 +61,13 @@ void increment(counter_t *counter)
void increment_with_yield(counter_t *counter)
{
Thread::yield();
ThisThread::yield();
(*counter)++;
}
void increment_with_wait(counter_t *counter)
{
Thread::wait(100);
ThisThread::sleep_for(100);
(*counter)++;
}
@ -286,59 +286,69 @@ end:
delete thread;
}
void signal_wait()
void flags_wait()
{
osEvent evt = Thread::signal_wait(0x1);
TEST_ASSERT_EQUAL(osEventSignal, evt.status);
TEST_ASSERT_EQUAL(0x1, evt.value.signals);
uint32_t flags = ThisThread::flags_wait_all(0x1);
TEST_ASSERT_EQUAL(0x1, flags);
}
void signal_wait_tout()
void flags_wait_tout()
{
osEvent evt = Thread::signal_wait(0x2, 50);
TEST_ASSERT_EQUAL(osEventTimeout, evt.status);
uint32_t flags = ThisThread::flags_wait_all_for(0x2, 50);
TEST_ASSERT_EQUAL(0x1, flags);
}
void signal_wait_multibit()
void flags_wait_multibit()
{
osEvent evt = Thread::signal_wait(0x1 | 0x2, 50);
TEST_ASSERT_EQUAL(osEventSignal, evt.status);
TEST_ASSERT_EQUAL(0x3, evt.value.signals);
uint32_t flags = ThisThread::flags_wait_all(0x1 | 0x2);
TEST_ASSERT_EQUAL(0x3, flags);
}
void signal_wait_multibit_tout()
void flags_wait_multibit_any()
{
osEvent evt = Thread::signal_wait(0x1 | 0x2, 50);
TEST_ASSERT_EQUAL(osEventTimeout, evt.status);
uint32_t flags = ThisThread::flags_wait_any(0x1 | 0x2);
TEST_ASSERT_NOT_EQUAL(0x0, flags);
}
void flags_wait_multibit_tout()
{
uint32_t flags = ThisThread::flags_wait_all_for(0x1 | 0x2, 50);
TEST_ASSERT_NOT_EQUAL(0x3, flags);
}
/**
Testing thread signal: wait
Testing thread flags: wait
Given two threads (A & B) are started
when thread A executes @a signal_wait(0x1)
and thread B execute @a signal_set(0x1)
when thread A executes @a flags_wait_all(0x1)
and thread B execute @a flags_set(0x1)
then thread A exits the wait and continues execution
Testing thread signal: timeout
Testing thread flags: timeout
Given two threads (A & B) are started
when thread A executes @a signal_wait(0x1 | 0x2, 50) with a timeout of 50ms
and thread B execute @a signal_set(0x2)
then thread A keeps waiting for correct signal until it timeouts
when thread A executes @a flags_wait_all_for(0x1 | 0x2, 50) with a timeout of 50ms
and thread B execute @a flags_set(0x2)
then thread A keeps waiting for correct flags until it timeouts
Testing thread signal: multi-bit
Testing thread flags: multi-bit
Given two threads (A & B) are started
when thread A executes @a signal_wait(0x1 | 0x2)
and thread B execute @a signal_set(0x1 | 0x2)
when thread A executes @a flags_wait_all(0x1 | 0x2)
and thread B execute @a flags_set(0x1 | 0x2)
then thread A exits the wait and continues execution
Testing thread signal: multi-bit timeout
Testing thread flags: multi-bit any
Given two threads (A & B) are started
when thread A executes @a signal_wait(0x1, 50) with a timeout of 50ms
and thread B execute @a signal_set(0x2)
then thread A keeps waiting for correct signal until it timeouts
when thread A executes @a flags_wait_any(0x1 | 0x2)
and thread B execute @a flags_set(0x1)
then thread A exits the wait and continues execution
Testing thread flags: multi-bit timeout
Given two threads (A & B) are started
when thread A executes @a flags_wait_all_for(0x1, 50) with a timeout of 50ms
and thread B execute @a flags_set(0x2)
then thread A keeps waiting for correct flags until it timeouts
*/
template <int S, void (*F)()>
void test_thread_signal()
void test_thread_flags_set()
{
char *dummy = new (std::nothrow) char[THREAD_STACK_SIZE];
delete[] dummy;
@ -348,37 +358,37 @@ void test_thread_signal()
t_wait.start(callback(F));
Thread::yield();
ThisThread::yield();
Thread::State state = t_wait.get_state();
TEST_ASSERT_EQUAL(Thread::WaitingThreadFlag, state);
int32_t res = t_wait.signal_set(S);
int32_t res = t_wait.flags_set(S);
t_wait.join();
}
void signal_clr()
void flags_clear()
{
Thread::yield();
ThisThread::yield();
int32_t sig = Thread::signal_clr(0x1);
int32_t sig = ThisThread::flags_clear(0x1);
TEST_ASSERT_EQUAL(0x1, sig);
/* Signal cleared we should get timeout */
osEvent evt = Thread::signal_wait(0x1, 0);
TEST_ASSERT_EQUAL(osOK, evt.status);
/* Flags cleared we should get timeout */
uint32_t flags = ThisThread::flags_wait_all_for(0x1, 0);
TEST_ASSERT_EQUAL(0, flags);
}
/** Testing thread signals: signal clear
/** Testing thread flags: flags clear
Given two threads (A & B) are started
when thread A executes @a signal_set(0x1)
and thread B execute @a signal_clr(0x1)
and thread B execute @a signal_wait(0x1, 0)
then thread B @a signal_wait status should be osOK indicating a timeout
when thread A executes @a flags_set(0x1)
and thread B execute @a flags_clear(0x1)
and thread B execute @a flags_wait_all_for(0x1, 0)
then thread B @a flags_wait_all_for return should be 0 indicating no flags set
*/
void test_thread_signal_clr()
void test_thread_flags_clear()
{
char *dummy = new (std::nothrow) char[THREAD_STACK_SIZE];
delete[] dummy;
@ -386,26 +396,26 @@ void test_thread_signal_clr()
Thread t_wait(osPriorityNormal, THREAD_STACK_SIZE);
t_wait.start(callback(signal_clr));
t_wait.start(callback(flags_clear));
int32_t res = t_wait.signal_set(0x1);
int32_t res = t_wait.flags_set(0x1);
TEST_ASSERT_EQUAL(0x1, res);
t_wait.join();
}
void thread_wait_signal()
void thread_wait_flags()
{
Thread::signal_wait(0x1);
ThisThread::flags_wait_all(0x1);
}
void stack_info()
{
Thread::signal_wait(0x1);
ThisThread::flags_wait_all(0x1);
thread_wait_signal();
thread_wait_flags();
Thread::signal_wait(0x1);
ThisThread::flags_wait_all(0x1);
}
/** Testing thread stack info
@ -429,26 +439,26 @@ void test_thread_stack_info()
Thread t(osPriorityNormal, THREAD_STACK_SIZE);
t.start(callback(stack_info));
Thread::yield();
ThisThread::yield();
TEST_ASSERT_EQUAL(THREAD_STACK_SIZE, t.stack_size());
TEST_ASSERT_EQUAL(THREAD_STACK_SIZE, t.free_stack() + t.used_stack());
uint32_t last_stack = t.used_stack();
t.signal_set(0x1);
Thread::yield();
t.flags_set(0x1);
ThisThread::yield();
TEST_ASSERT_EQUAL(THREAD_STACK_SIZE, t.free_stack() + t.used_stack());
TEST_ASSERT(last_stack <= t.used_stack());
last_stack = t.used_stack();
t.signal_set(0x1);
Thread::yield();
t.flags_set(0x1);
ThisThread::yield();
TEST_ASSERT_EQUAL(THREAD_STACK_SIZE, t.free_stack() + t.used_stack());
TEST_ASSERT(last_stack >= t.used_stack());
t.signal_set(0x1);
t.flags_set(0x1);
t.join();
}
@ -483,9 +493,9 @@ void test_thread_name()
const char tname[] = "Amazing thread";
Thread t(osPriorityNormal, THREAD_STACK_SIZE, NULL, tname);
t.start(callback(thread_wait_signal));
t.start(callback(thread_wait_flags));
TEST_ASSERT_EQUAL(strcmp(tname, t.get_name()), 0);
t.signal_set(0x1);
t.flags_set(0x1);
t.join();
}
@ -537,7 +547,7 @@ void test_delay()
t.start(callback(test_delay_thread));
Thread::yield();
ThisThread::yield();
TEST_ASSERT_EQUAL(Thread::WaitingDelay, t.get_state());
@ -545,18 +555,18 @@ void test_delay()
TEST_ASSERT_EQUAL(Thread::Deleted, t.get_state());
}
void test_signal_thread()
void test_thread_flags_thread()
{
Thread::signal_wait(0x1);
ThisThread::flags_wait_all(0x1);
}
/** Testing thread states: wait signal
/** Testing thread states: wait flags
Given the thread is running
when thread waits for a signal
then its state, as reported by @a get_state, is @a WaitingSignal
when thread waits for flags
then its state, as reported by @a get_state, is @a WaitingThreadFlag
*/
void test_signal()
void test_thread_flags()
{
char *dummy = new (std::nothrow) char[THREAD_STACK_SIZE];
delete[] dummy;
@ -564,18 +574,18 @@ void test_signal()
Thread t(osPriorityNormal, THREAD_STACK_SIZE);
t.start(callback(test_signal_thread));
t.start(callback(test_thread_flags_thread));
Thread::yield();
ThisThread::yield();
TEST_ASSERT_EQUAL(Thread::WaitingThreadFlag, t.get_state());
t.signal_set(0x1);
t.flags_set(0x1);
}
void test_evt_flag_thread(osEventFlagsId_t evtflg)
void test_evt_flag_thread(EventFlags *evtflg)
{
osEventFlagsWait(evtflg, 0x1, osFlagsWaitAny, osWaitForever);
evtflg->wait_any(0x1);
}
/** Testing thread states: wait evt flag
@ -591,22 +601,15 @@ void test_evt_flag()
TEST_SKIP_UNLESS_MESSAGE(dummy, "Not enough memory to run test");
Thread t(osPriorityNormal, THREAD_STACK_SIZE);
mbed_rtos_storage_event_flags_t evtflg_mem;
osEventFlagsAttr_t evtflg_attr;
osEventFlagsId_t evtflg;
EventFlags evtflg;
evtflg_attr.cb_mem = &evtflg_mem;
evtflg_attr.cb_size = sizeof(evtflg_mem);
evtflg = osEventFlagsNew(&evtflg_attr);
TEST_ASSERT_NOT_EQUAL(NULL, evtflg);
t.start(callback(test_evt_flag_thread, &evtflg));
t.start(callback(test_evt_flag_thread, evtflg));
Thread::yield();
ThisThread::yield();
TEST_ASSERT_EQUAL(Thread::WaitingEventFlag, t.get_state());
osEventFlagsSet(evtflg, 0x1);
evtflg.set(0x1);
}
void test_mutex_thread(Mutex *mutex)
@ -633,7 +636,7 @@ void test_mutex()
t.start(callback(test_mutex_thread, &mutex));
Thread::yield();
ThisThread::yield();
TEST_ASSERT_EQUAL(Thread::WaitingMutex, t.get_state());
@ -662,7 +665,7 @@ void test_semaphore()
t.start(callback(test_semaphore_thread, &sem));
Thread::yield();
ThisThread::yield();
TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state());
@ -691,7 +694,7 @@ void test_msg_get()
t.start(callback(test_msg_get_thread, &queue));
Thread::yield();
ThisThread::yield();
TEST_ASSERT_EQUAL(Thread::WaitingMessageGet, t.get_state());
@ -723,7 +726,7 @@ void test_msg_put()
t.start(callback(test_msg_put_thread, &queue));
Thread::yield();
ThisThread::yield();
TEST_ASSERT_EQUAL(Thread::WaitingMessagePut, t.get_state());
queue.get();
@ -773,7 +776,7 @@ void test_thread_prio()
TEST_SKIP_UNLESS_MESSAGE(dummy, "Not enough memory to run test");
Thread t(osPriorityNormal, THREAD_STACK_SIZE);
t.start(callback(thread_wait_signal));
t.start(callback(thread_wait_flags));
TEST_ASSERT_EQUAL(osPriorityNormal, t.get_priority());
@ -781,7 +784,7 @@ void test_thread_prio()
TEST_ASSERT_EQUAL(osPriorityHigh, t.get_priority());
t.signal_set(0x1);
t.flags_set(0x1);
t.join();
}
@ -818,12 +821,12 @@ static const case_t cases[] = {
{"Testing thread self terminate", test_self_terminate, DEFAULT_HANDLERS},
{"Testing thread signals: wait", test_thread_signal<0x1, signal_wait>, DEFAULT_HANDLERS},
{"Testing thread signals: timeout", test_thread_signal<0x1, signal_wait_tout>, DEFAULT_HANDLERS},
{"Testing thread signals: multi-bit", test_thread_signal<0x3, signal_wait_multibit>, DEFAULT_HANDLERS},
{"Testing thread signals: multi-bit timeout", test_thread_signal<0x1, signal_wait_multibit_tout>, DEFAULT_HANDLERS},
{"Testing thread signals: signal clear", test_thread_signal_clr, DEFAULT_HANDLERS},
{"Testing thread flags: wait", test_thread_flags_set<0x1, flags_wait>, DEFAULT_HANDLERS},
{"Testing thread flags: timeout", test_thread_flags_set<0x1, flags_wait_tout>, DEFAULT_HANDLERS},
{"Testing thread flags: multi-bit all", test_thread_flags_set<0x3, flags_wait_multibit>, DEFAULT_HANDLERS},
{"Testing thread flags: multi-bit all timeout", test_thread_flags_set<0x1, flags_wait_multibit_tout>, DEFAULT_HANDLERS},
{"Testing thread flags: multi-bit any", test_thread_flags_set<0x1, flags_wait_multibit_any>, DEFAULT_HANDLERS},
{"Testing thread flags: flags clear", test_thread_flags_clear, DEFAULT_HANDLERS},
{"Testing thread stack info", test_thread_stack_info, DEFAULT_HANDLERS},
{"Testing thread wait", test_thread_wait, DEFAULT_HANDLERS},
@ -831,7 +834,7 @@ static const case_t cases[] = {
{"Testing thread states: deleted", test_deleted, DEFAULT_HANDLERS},
{"Testing thread states: wait delay", test_delay, DEFAULT_HANDLERS},
{"Testing thread states: wait signal", test_signal, DEFAULT_HANDLERS},
{"Testing thread states: wait thread flags", test_thread_flags, DEFAULT_HANDLERS},
{"Testing thread states: wait event flag", test_evt_flag, DEFAULT_HANDLERS},
{"Testing thread states: wait mutex", test_mutex, DEFAULT_HANDLERS},
{"Testing thread states: wait semaphore", test_semaphore, DEFAULT_HANDLERS},

View File

@ -23,10 +23,13 @@
#include "rtos/Kernel.h"
#include "mbed.h"
#include "rtos/rtos_idle.h"
#include "rtos/rtos_handlers.h"
namespace rtos {
uint64_t Kernel::get_ms_count() {
uint64_t Kernel::get_ms_count()
{
// CMSIS-RTOS 2.1.0 and 2.1.1 differ in the time type. We assume
// our header at least matches the implementation, so we don't try looking
// at the run-time version report. (There's no compile-time version report)
@ -36,7 +39,7 @@ uint64_t Kernel::get_ms_count() {
// 2.1.x who knows? We assume could go back to uint64_t
if (sizeof osKernelGetTickCount() == sizeof(uint64_t)) {
return osKernelGetTickCount();
} else /* assume 32-bit */ {
} else { /* assume 32-bit */
// Based on suggestion in CMSIS-RTOS 2.1.1 docs, but with reentrancy
// protection for the tick memory. We use critical section rather than a
// mutex, as hopefully this method can be callable from interrupt later -
@ -60,4 +63,14 @@ uint64_t Kernel::get_ms_count() {
}
}
void Kernel::attach_idle_hook(void (*fptr)(void))
{
rtos_attach_idle_hook(fptr);
}
void Kernel::attach_thread_terminate_hook(void (*fptr)(osThreadId_t id))
{
rtos_attach_thread_terminate_hook(fptr);
}
}

View File

@ -23,6 +23,7 @@
#define KERNEL_H
#include <stdint.h>
#include "cmsis_os2.h"
namespace rtos {
/** \addtogroup rtos */
@ -43,6 +44,20 @@ namespace Kernel {
*/
uint64_t get_ms_count();
/** Attach a function to be called by the RTOS idle task
@param fptr pointer to the function to be called
@note You may call this function from ISR context.
*/
void attach_idle_hook(void (*fptr)(void));
/** Attach a function to be called when a task is killed
@param fptr pointer to the function to be called
@note You may call this function from ISR context.
*/
void attach_thread_terminate_hook(void (*fptr)(osThreadId_t id));
} // namespace Kernel
} // namespace rtos

View File

@ -21,6 +21,7 @@
#include "mbed_error.h"
#include "mbed_interface.h"
#include "RTX_Config.h"
#include "rtos/rtos_handlers.h"
#ifdef RTE_Compiler_EventRecorder
#include "EventRecorder.h" // Keil::Compiler:Event Recorder
@ -30,45 +31,58 @@
#endif
extern void rtos_idle_loop(void);
extern void thread_terminate_hook(osThreadId_t id);
__NO_RETURN void osRtxIdleThread (void *argument)
static void (*terminate_hook)(osThreadId_t id);
static void thread_terminate_hook(osThreadId_t id)
{
for (;;) {
rtos_idle_loop();
if (terminate_hook) {
terminate_hook(id);
}
}
__NO_RETURN uint32_t osRtxErrorNotify (uint32_t code, void *object_id)
void rtos_attach_thread_terminate_hook(void (*fptr)(osThreadId_t id))
{
terminate_hook = fptr;
}
__NO_RETURN void osRtxIdleThread(void *argument)
{
for (;;) {
rtos_idle_loop();
}
}
__NO_RETURN uint32_t osRtxErrorNotify(uint32_t code, void *object_id)
{
osThreadId_t tid = osThreadGetId();
switch (code) {
case osRtxErrorStackUnderflow:
// Stack underflow detected for thread (thread_id=object_id)
// Note: "overflow" is printed instead of "underflow" due to end user familiarity with overflow errors
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_STACK_OVERFLOW), "CMSIS-RTOS error: Stack overflow", code);
break;
case osRtxErrorISRQueueOverflow:
// ISR Queue overflow detected when inserting object (object_id)
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_ISR_QUEUE_OVERFLOW), "CMSIS-RTOS error: ISR Queue overflow", code);
break;
case osRtxErrorTimerQueueOverflow:
// User Timer Callback Queue overflow detected for timer (timer_id=object_id)
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_TIMER_QUEUE_OVERFLOW), "CMSIS-RTOS error: User Timer Callback Queue overflow", code);
break;
case osRtxErrorClibSpace:
// Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_CLIB_SPACE_UNAVAILABLE), "CMSIS-RTOS error: STD C/C++ library libspace not available", code);
break;
case osRtxErrorClibMutex:
// Standard C/C++ library mutex initialization failed
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_CLIB_MUTEX_INIT_FAILURE), "CMSIS-RTOS error: STD C/C++ library mutex initialization failed", code);
break;
default:
//Unknown error flagged from kernel
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_UNKNOWN), "CMSIS-RTOS error: Unknown", code);
break;
case osRtxErrorStackUnderflow:
// Stack underflow detected for thread (thread_id=object_id)
// Note: "overflow" is printed instead of "underflow" due to end user familiarity with overflow errors
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_STACK_OVERFLOW), "CMSIS-RTOS error: Stack overflow", code);
break;
case osRtxErrorISRQueueOverflow:
// ISR Queue overflow detected when inserting object (object_id)
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_ISR_QUEUE_OVERFLOW), "CMSIS-RTOS error: ISR Queue overflow", code);
break;
case osRtxErrorTimerQueueOverflow:
// User Timer Callback Queue overflow detected for timer (timer_id=object_id)
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_TIMER_QUEUE_OVERFLOW), "CMSIS-RTOS error: User Timer Callback Queue overflow", code);
break;
case osRtxErrorClibSpace:
// Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_CLIB_SPACE_UNAVAILABLE), "CMSIS-RTOS error: STD C/C++ library libspace not available", code);
break;
case osRtxErrorClibMutex:
// Standard C/C++ library mutex initialization failed
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_CLIB_MUTEX_INIT_FAILURE), "CMSIS-RTOS error: STD C/C++ library mutex initialization failed", code);
break;
default:
//Unknown error flagged from kernel
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_ERROR_CODE_UNKNOWN), "CMSIS-RTOS error: Unknown", code);
break;
}
/* That shouldn't be reached */
@ -77,52 +91,52 @@ __NO_RETURN uint32_t osRtxErrorNotify (uint32_t code, void *object_id)
#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED
static const char* error_msg(int32_t status)
static const char *error_msg(int32_t status)
{
switch (status) {
case osError:
return "Unspecified RTOS error";
case osErrorTimeout:
return "Operation not completed within the timeout period";
case osErrorResource:
return "Resource not available";
case osErrorParameter:
return "Parameter error";
case osErrorNoMemory:
return "System is out of memory";
case osErrorISR:
return "Not allowed in ISR context";
default:
return "Unknown";
case osError:
return "Unspecified RTOS error";
case osErrorTimeout:
return "Operation not completed within the timeout period";
case osErrorResource:
return "Resource not available";
case osErrorParameter:
return "Parameter error";
case osErrorNoMemory:
return "System is out of memory";
case osErrorISR:
return "Not allowed in ISR context";
default:
return "Unknown";
}
}
void EvrRtxKernelError (int32_t status)
void EvrRtxKernelError(int32_t status)
{
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_EVENT), error_msg(status), status);
}
void EvrRtxThreadError (osThreadId_t thread_id, int32_t status)
void EvrRtxThreadError(osThreadId_t thread_id, int32_t status)
{
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_THREAD_EVENT), error_msg(status), thread_id);
}
void EvrRtxTimerError (osTimerId_t timer_id, int32_t status)
void EvrRtxTimerError(osTimerId_t timer_id, int32_t status)
{
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_TIMER_EVENT), error_msg(status), timer_id);
}
void EvrRtxEventFlagsError (osEventFlagsId_t ef_id, int32_t status)
void EvrRtxEventFlagsError(osEventFlagsId_t ef_id, int32_t status)
{
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT), error_msg(status), ef_id);
}
void EvrRtxMutexError (osMutexId_t mutex_id, int32_t status)
void EvrRtxMutexError(osMutexId_t mutex_id, int32_t status)
{
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MUTEX_EVENT), error_msg(status), mutex_id);
}
void EvrRtxSemaphoreError (osSemaphoreId_t semaphore_id, int32_t status)
void EvrRtxSemaphoreError(osSemaphoreId_t semaphore_id, int32_t status)
{
// Ignore semaphore overflow, the count will saturate with a returned error
if (status == osRtxErrorSemaphoreCountLimit) {
@ -132,12 +146,12 @@ void EvrRtxSemaphoreError (osSemaphoreId_t semaphore_id, int32_t status)
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT), error_msg(status), semaphore_id);
}
void EvrRtxMemoryPoolError (osMemoryPoolId_t mp_id, int32_t status)
void EvrRtxMemoryPoolError(osMemoryPoolId_t mp_id, int32_t status)
{
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT), error_msg(status), mp_id);
}
void EvrRtxMessageQueueError (osMessageQueueId_t mq_id, int32_t status)
void EvrRtxMessageQueueError(osMessageQueueId_t mq_id, int32_t status)
{
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT), error_msg(status), mq_id);
}
@ -145,7 +159,7 @@ void EvrRtxMessageQueueError (osMessageQueueId_t mq_id, int32_t status)
#endif
// RTX hook which gets called when a thread terminates, using the event function to call hook
void EvrRtxThreadExit (void)
void EvrRtxThreadExit(void)
{
osThreadId_t thread_id = osThreadGetId();
thread_terminate_hook(thread_id);
@ -154,7 +168,7 @@ void EvrRtxThreadExit (void)
#endif
}
void EvrRtxThreadTerminate (osThreadId_t thread_id)
void EvrRtxThreadTerminate(osThreadId_t thread_id)
{
thread_terminate_hook(thread_id);
#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_TERMINATE_DISABLE) && defined(RTE_Compiler_EventRecorder))

141
rtos/ThisThread.cpp Normal file
View File

@ -0,0 +1,141 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2012 ARM Limited
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#define __STDC_LIMIT_MACROS
#include "rtos/ThisThread.h"
#include "mbed.h"
#include "rtos/rtos_idle.h"
#include "mbed_assert.h"
namespace rtos {
uint32_t ThisThread::flags_clear(uint32_t flags)
{
flags = osThreadFlagsClear(flags);
MBED_ASSERT(!(flags & osFlagsError));
return flags;
}
uint32_t ThisThread::flags_get()
{
return osThreadFlagsGet();
}
static uint32_t flags_wait_for(uint32_t flags, uint32_t millisec, bool clear, uint32_t options)
{
if (!clear) {
options |= osFlagsNoClear;
}
flags = osThreadFlagsWait(flags, options, millisec);
if (flags & osFlagsError) {
MBED_ASSERT((flags == osFlagsErrorTimeout && millisec != osWaitForever) ||
(flags == osFlagsErrorResource && millisec == 0));
flags = ThisThread::flags_get();
}
return flags;
}
static uint32_t flags_wait_until(uint32_t flags, uint64_t millisec, bool clear, uint32_t options)
{
uint64_t now = Kernel::get_ms_count();
uint32_t delay;
if (now >= millisec) {
delay = 0;
} else if (millisec - now >= osWaitForever) {
// Documentation permits early return for big offsets
delay = osWaitForever - 1;
} else {
delay = millisec - now;
}
return flags_wait_for(flags, delay, clear, options);
}
uint32_t ThisThread::flags_wait_all(uint32_t flags, bool clear)
{
return flags_wait_for(flags, osWaitForever, clear, osFlagsWaitAll);
}
uint32_t ThisThread::flags_wait_all_for(uint32_t flags, uint32_t millisec, bool clear)
{
return flags_wait_for(flags, millisec, clear, osFlagsWaitAll);
}
uint32_t ThisThread::flags_wait_all_until(uint32_t flags, uint64_t millisec, bool clear)
{
return flags_wait_until(flags, millisec, clear, osFlagsWaitAll);
}
uint32_t ThisThread::flags_wait_any(uint32_t flags, bool clear)
{
return flags_wait_for(flags, osWaitForever, clear, osFlagsWaitAny);
}
uint32_t ThisThread::flags_wait_any_for(uint32_t flags, uint32_t millisec, bool clear)
{
return flags_wait_for(flags, millisec, clear, osFlagsWaitAny);
}
uint32_t ThisThread::flags_wait_any_until(uint32_t flags, uint64_t millisec, bool clear)
{
return flags_wait_until(flags, millisec, clear, osFlagsWaitAny);
}
void ThisThread::sleep_for(uint32_t millisec)
{
osStatus_t status = osDelay(millisec);
MBED_ASSERT(status == osOK);
}
void ThisThread::sleep_until(uint64_t millisec)
{
// CMSIS-RTOS 2.1.0 had 64-bit time and osDelayUntil, but that's been revoked.
// Limit ourselves to manual implementation assuming a >=32-bit osDelay.
// 64-bit time doesn't wrap (for half a billion years, at last)
// make the effort to loop for unlimited sleep, as it doesn't cost much
uint64_t now;
while ((now = Kernel::get_ms_count()) < millisec) {
if (millisec - now > UINT32_MAX) {
sleep_for(UINT32_MAX);
continue;
} else {
sleep_for(millisec - now);
break;
}
}
}
void ThisThread::yield()
{
osThreadYield();
}
osThreadId_t ThisThread::get_id()
{
return osThreadGetId();
}
}

188
rtos/ThisThread.h Normal file
View File

@ -0,0 +1,188 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2018 ARM Limited
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef THIS_THREAD_H
#define THIS_THREAD_H
#include <stdint.h>
#include "cmsis_os2.h"
#include "mbed_rtos1_types.h"
#include "mbed_rtos_storage.h"
#include "platform/Callback.h"
#include "platform/mbed_toolchain.h"
#include "platform/NonCopyable.h"
#include "rtos/Semaphore.h"
#include "rtos/Mutex.h"
namespace rtos {
/** \addtogroup rtos */
/** @{*/
/**
* \defgroup rtos_ThisThread ThisThread namespace
* @{
*/
/** The ThisThread namespace allows controlling the current thread.
*
* Example:
* @code
* #include "mbed.h"
* #include "rtos.h"
*
* Thread thread;
* DigitalOut led1(LED1);
*
* #define STOP_FLAG 1
*
* // Blink function toggles the led in a long running loop
* void blink(DigitalOut *led) {
* while (!ThisThread::flags_wait_any_for(STOP_FLAG, 1000)) {
* *led = !*led;
* }
* }
*
* // Spawns a thread to run blink for 5 seconds
* int main() {
* thread.start(callback(blink, &led1));
* ThisThread::sleep_for(5000);
* thread.signal_set(STOP_FLAG);
* thread.join();
* }
* @endcode
*
*/
namespace ThisThread {
/** Clears the specified Thread Flags of the currently running thread.
@param flags specifies the flags of the thread that should be cleared.
@return thread flags before clearing.
@note You cannot call this function from ISR context.
@see Thread::flags_set
*/
uint32_t flags_clear(uint32_t flags);
/** Returns the Thread Flags currently set for the currently running thread.
@return current thread flags or 0 if not in a valid thread.
@note You cannot call this function from ISR context.
@see Thread::flags_set
*/
uint32_t flags_get();
/** Wait for all of the specified Thread Flags to become signaled for the current thread.
@param flags specifies the flags to wait for
@param clear whether to clear the specified flags after waiting for them. (default: true)
@return actual thread flags before clearing, which will satisfy the wait
@note You cannot call this function from ISR context.
@see Thread::flags_set
*/
uint32_t flags_wait_all(uint32_t flags, bool clear = true);
/** Wait for any of the specified Thread Flags to become signaled for the current thread.
@param flags specifies the flags to wait for
@param clear whether to clear the specified flags after waiting for them. (default: true)
@return actual thread flags before clearing, which will satisfy the wait
@note You cannot call this function from ISR context.
@see Thread::flags_set
*/
uint32_t flags_wait_any(uint32_t flags, bool clear = true);
/** Wait for all of the specified Thread Flags to become signaled for the current thread.
@param flags specifies the flags to wait for
@param millisec timeout value or 0 in case of no time-out.
@param clear whether to clear the specified flags after waiting for them. (default: true)
@return actual thread flags before clearing, which may not satisfy the wait
@note You cannot call this function from ISR context.
@see Thread::flags_set
*/
uint32_t flags_wait_all_for(uint32_t flags, uint32_t millisec, bool clear = true);
/** Wait for all of the specified Thread Flags to become signaled for the current thread.
@param flags specifies the flags to wait for
@param millisec absolute timeout time, referenced to Kernel::get_ms_count()
@param clear whether to clear the specified flags after waiting for them. (default: true)
@return actual thread flags before clearing, which may not satisfy the wait
@note You cannot call this function from ISR context.
@note the underlying RTOS may have a limit to the maximum wait time
due to internal 32-bit computations, but this is guaranteed to work if the
wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
the wait will time out earlier than specified.
@see Thread::flags_set
*/
uint32_t flags_wait_all_until(uint32_t flags, uint64_t millisec, bool clear = true);
/** Wait for any of the specified Thread Flags to become signaled for the current thread.
@param flags specifies the flags to wait for
@param millisec timeout value or 0 in case of no time-out.
@param clear whether to clear the specified flags after waiting for them. (default: true)
@return actual thread flags before clearing, which may not satisfy the wait
@note You cannot call this function from ISR context.
@see Thread::flags_set
*/
uint32_t flags_wait_any_for(uint32_t flags, uint32_t millisec, bool clear = true);
/** Wait for any of the specified Thread Flags to become signaled for the current thread.
@param flags specifies the flags to wait for
@param millisec absolute timeout time, referenced to Kernel::get_ms_count()
@param clear whether to clear the specified flags after waiting for them. (default: true)
@return actual thread flags before clearing, which may not satisfy the wait
@note You cannot call this function from ISR context.
@note the underlying RTOS may have a limit to the maximum wait time
due to internal 32-bit computations, but this is guaranteed to work if the
wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded,
the wait will time out earlier than specified.
@see Thread::flags_set
*/
uint32_t flags_wait_any_until(uint32_t flags, uint64_t millisec, bool clear = true);
/** Sleep for a specified time period in millisec:
@param millisec time delay value
@note You cannot call this function from ISR context.
*/
void sleep_for(uint32_t millisec);
/** Sleep until a specified time in millisec
The specified time is according to Kernel::get_ms_count().
@param millisec absolute time in millisec
@note You cannot call this function from ISR context.
@note if millisec is equal to or lower than the current tick count, this
returns immediately.
*/
void sleep_until(uint64_t millisec);
/** Pass control to next equal-priority thread that is in state READY.
(Higher-priority READY threads would prevent us from running; this
will not enable lower-priority threads to run, as we remain READY).
@note You cannot call this function from ISR context.
*/
void yield();
/** Get the thread id of the current running thread.
@return thread ID for reference by other functions or NULL in case of error or in ISR context.
@note You may call this function from ISR context.
*/
osThreadId_t get_id();
};
/** @}*/
/** @}*/
}
#endif

View File

@ -20,9 +20,11 @@
* SOFTWARE.
*/
#include "rtos/Thread.h"
#include "rtos/ThisThread.h"
#include "mbed.h"
#include "rtos/rtos_idle.h"
#include "rtos/rtos_handlers.h"
#include "mbed_assert.h"
#define ALIGN_UP(pos, align) ((pos) % (align) ? (pos) + ((align) - (pos) % (align)) : (pos))
@ -33,14 +35,6 @@ MBED_STATIC_ASSERT(ALIGN_UP(1, 8) == 8, "ALIGN_UP macro error");
MBED_STATIC_ASSERT(ALIGN_DOWN(7, 8) == 0, "ALIGN_DOWN macro error");
MBED_STATIC_ASSERT(ALIGN_DOWN(8, 8) == 8, "ALIGN_DOWN macro error");
static void (*terminate_hook)(osThreadId_t id) = 0;
extern "C" void thread_terminate_hook(osThreadId_t id)
{
if (terminate_hook != (void (*)(osThreadId_t))NULL) {
terminate_hook(id);
}
}
namespace rtos {
#ifndef MBED_TZ_DEFAULT_ACCESS
@ -48,7 +42,8 @@ namespace rtos {
#endif
void Thread::constructor(uint32_t tz_module, osPriority priority,
uint32_t stack_size, unsigned char *stack_mem, const char *name) {
uint32_t stack_size, unsigned char *stack_mem, const char *name)
{
const uintptr_t unaligned_mem = reinterpret_cast<uintptr_t>(stack_mem);
const uintptr_t aligned_mem = ALIGN_UP(unaligned_mem, 8);
@ -63,17 +58,19 @@ void Thread::constructor(uint32_t tz_module, osPriority priority,
_attr.priority = priority;
_attr.stack_size = aligned_size;
_attr.name = name ? name : "application_unnamed_thread";
_attr.stack_mem = reinterpret_cast<uint32_t*>(aligned_mem);
_attr.stack_mem = reinterpret_cast<uint32_t *>(aligned_mem);
_attr.tz_module = tz_module;
}
void Thread::constructor(osPriority priority,
uint32_t stack_size, unsigned char *stack_mem, const char *name) {
uint32_t stack_size, unsigned char *stack_mem, const char *name)
{
constructor(MBED_TZ_DEFAULT_ACCESS, priority, stack_size, stack_mem, name);
}
void Thread::constructor(Callback<void()> task,
osPriority priority, uint32_t stack_size, unsigned char *stack_mem, const char *name) {
osPriority priority, uint32_t stack_size, unsigned char *stack_mem, const char *name)
{
constructor(MBED_TZ_DEFAULT_ACCESS, priority, stack_size, stack_mem, name);
switch (start(task)) {
@ -90,7 +87,8 @@ void Thread::constructor(Callback<void()> task,
}
}
osStatus Thread::start(Callback<void()> task) {
osStatus Thread::start(Callback<void()> task)
{
_mutex.lock();
if ((_tid != 0) || _finished) {
@ -99,7 +97,7 @@ osStatus Thread::start(Callback<void()> task) {
}
if (_attr.stack_mem == NULL) {
_attr.stack_mem = new uint32_t[_attr.stack_size/sizeof(uint32_t)];
_attr.stack_mem = new uint32_t[_attr.stack_size / sizeof(uint32_t)];
MBED_ASSERT(_attr.stack_mem != NULL);
}
@ -115,8 +113,8 @@ osStatus Thread::start(Callback<void()> task) {
_tid = osThreadNew(Thread::_thunk, this, &_attr);
if (_tid == NULL) {
if (_dynamic_stack) {
delete[] (uint32_t *)(_attr.stack_mem);
_attr.stack_mem = (uint32_t*)NULL;
delete[](uint32_t *)(_attr.stack_mem);
_attr.stack_mem = (uint32_t *)NULL;
}
_mutex.unlock();
_join_sem.release();
@ -127,7 +125,8 @@ osStatus Thread::start(Callback<void()> task) {
return osOK;
}
osStatus Thread::terminate() {
osStatus Thread::terminate()
{
osStatus_t ret = osOK;
_mutex.lock();
@ -149,7 +148,8 @@ osStatus Thread::terminate() {
return ret;
}
osStatus Thread::join() {
osStatus Thread::join()
{
int32_t ret = _join_sem.wait();
if (ret < 0) {
return osError;
@ -167,7 +167,8 @@ osStatus Thread::join() {
return osOK;
}
osStatus Thread::set_priority(osPriority priority) {
osStatus Thread::set_priority(osPriority priority)
{
osStatus_t ret;
_mutex.lock();
@ -177,7 +178,8 @@ osStatus Thread::set_priority(osPriority priority) {
return ret;
}
osPriority Thread::get_priority() {
osPriority Thread::get_priority() const
{
osPriority_t ret;
_mutex.lock();
@ -187,11 +189,20 @@ osPriority Thread::get_priority() {
return ret;
}
int32_t Thread::signal_set(int32_t flags) {
uint32_t Thread::flags_set(uint32_t flags)
{
flags = osThreadFlagsSet(_tid, flags);
MBED_ASSERT(!(flags & osFlagsError));
return flags;
}
int32_t Thread::signal_set(int32_t flags)
{
return osThreadFlagsSet(_tid, flags);
}
Thread::State Thread::get_state() {
Thread::State Thread::get_state() const
{
uint8_t state = osThreadTerminated;
_mutex.lock();
@ -208,7 +219,7 @@ Thread::State Thread::get_state() {
State user_state;
switch(state) {
switch (state) {
case osThreadInactive:
user_state = Inactive;
break;
@ -256,7 +267,8 @@ Thread::State Thread::get_state() {
return user_state;
}
uint32_t Thread::stack_size() {
uint32_t Thread::stack_size() const
{
uint32_t size = 0;
_mutex.lock();
@ -268,7 +280,8 @@ uint32_t Thread::stack_size() {
return size;
}
uint32_t Thread::free_stack() {
uint32_t Thread::free_stack() const
{
uint32_t size = 0;
_mutex.lock();
@ -283,7 +296,8 @@ uint32_t Thread::free_stack() {
return size;
}
uint32_t Thread::used_stack() {
uint32_t Thread::used_stack() const
{
uint32_t size = 0;
_mutex.lock();
@ -298,7 +312,8 @@ uint32_t Thread::used_stack() {
return size;
}
uint32_t Thread::max_stack() {
uint32_t Thread::max_stack() const
{
uint32_t size = 0;
_mutex.lock();
@ -306,8 +321,9 @@ uint32_t Thread::max_stack() {
#if defined(MBED_OS_BACKEND_RTX5)
mbed_rtos_storage_thread_t *thread = (mbed_rtos_storage_thread_t *)_tid;
uint32_t high_mark = 0;
while ((((uint32_t *)(thread->stack_mem))[high_mark] == osRtxStackMagicWord) || (((uint32_t *)(thread->stack_mem))[high_mark] == osRtxStackFillPattern))
while ((((uint32_t *)(thread->stack_mem))[high_mark] == osRtxStackMagicWord) || (((uint32_t *)(thread->stack_mem))[high_mark] == osRtxStackFillPattern)) {
high_mark++;
}
size = thread->stack_size - (high_mark * sizeof(uint32_t));
#else
size = osThreadGetStackSize(_tid) - osThreadGetStackSpace(_tid);
@ -318,15 +334,23 @@ uint32_t Thread::max_stack() {
return size;
}
const char *Thread::get_name() {
const char *Thread::get_name() const
{
return _attr.name;
}
int32_t Thread::signal_clr(int32_t flags) {
osThreadId_t Thread::get_id() const
{
return _tid;
}
int32_t Thread::signal_clr(int32_t flags)
{
return osThreadFlagsClear(flags);
}
osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) {
osEvent Thread::signal_wait(int32_t signals, uint32_t millisec)
{
uint32_t res;
osEvent evt;
uint32_t options = osFlagsWaitAll;
@ -359,67 +383,51 @@ osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) {
return evt;
}
osStatus Thread::wait(uint32_t millisec) {
return osDelay(millisec);
osStatus Thread::wait(uint32_t millisec)
{
ThisThread::sleep_for(millisec);
return osOK;
}
osStatus Thread::wait_until(uint64_t millisec) {
// CMSIS-RTOS 2.1.0 and 2.1.1 differ in the time type, which we determine
// by looking at the return type of osKernelGetTickCount. We assume
// our header at least matches the implementation, so we don't try looking
// at the run-time version report. (There's no compile-time version report)
if (sizeof osKernelGetTickCount() == sizeof(uint64_t)) {
// CMSIS-RTOS 2.1.0 has a 64-bit API. The corresponding RTX 5.2.0 can't
// delay more than 0xfffffffe ticks, but there's no limit stated for
// the generic API.
return osDelayUntil(millisec);
} else {
// 64-bit time doesn't wrap (for half a billion years, at last)
uint64_t now = Kernel::get_ms_count();
// Report being late on entry
if (now >= millisec) {
return osErrorParameter;
}
// We're about to make a 32-bit delay call, so have at least this limit
if (millisec - now > 0xFFFFFFFF) {
return osErrorParameter;
}
// And this may have its own internal limit - we'll find out.
// We hope/assume there's no problem with passing
// osWaitForever = 0xFFFFFFFF - that value is only specified to have
// special meaning for osSomethingWait calls.
return osDelay(millisec - now);
}
osStatus Thread::wait_until(uint64_t millisec)
{
ThisThread::sleep_until(millisec);
return osOK;
}
osStatus Thread::yield() {
osStatus Thread::yield()
{
return osThreadYield();
}
osThreadId Thread::gettid() {
osThreadId Thread::gettid()
{
return osThreadGetId();
}
void Thread::attach_idle_hook(void (*fptr)(void)) {
void Thread::attach_idle_hook(void (*fptr)(void))
{
rtos_attach_idle_hook(fptr);
}
void Thread::attach_terminate_hook(void (*fptr)(osThreadId_t id)) {
terminate_hook = fptr;
void Thread::attach_terminate_hook(void (*fptr)(osThreadId_t id))
{
rtos_attach_thread_terminate_hook(fptr);
}
Thread::~Thread() {
Thread::~Thread()
{
// terminate is thread safe
terminate();
if (_dynamic_stack) {
delete[] (uint32_t*)(_attr.stack_mem);
_attr.stack_mem = (uint32_t*)NULL;
delete[](uint32_t *)(_attr.stack_mem);
_attr.stack_mem = (uint32_t *)NULL;
}
}
void Thread::_thunk(void * thread_ptr)
void Thread::_thunk(void *thread_ptr)
{
Thread *t = (Thread*)thread_ptr;
Thread *t = (Thread *)thread_ptr;
t->_task();
t->_mutex.lock();
t->_tid = (osThreadId)NULL;

View File

@ -94,9 +94,10 @@ public:
@note You cannot call this function from ISR context.
*/
Thread(osPriority priority=osPriorityNormal,
uint32_t stack_size=OS_STACK_SIZE,
unsigned char *stack_mem=NULL, const char *name=NULL) {
Thread(osPriority priority = osPriorityNormal,
uint32_t stack_size = OS_STACK_SIZE,
unsigned char *stack_mem = NULL, const char *name = NULL)
{
constructor(priority, stack_size, stack_mem, name);
}
@ -113,9 +114,10 @@ public:
@note You cannot call this function from ISR context.
*/
Thread(uint32_t tz_module, osPriority priority=osPriorityNormal,
uint32_t stack_size=OS_STACK_SIZE,
unsigned char *stack_mem=NULL, const char *name=NULL) {
Thread(uint32_t tz_module, osPriority priority = osPriorityNormal,
uint32_t stack_size = OS_STACK_SIZE,
unsigned char *stack_mem = NULL, const char *name = NULL)
{
constructor(tz_module, priority, stack_size, stack_mem, name);
}
@ -140,12 +142,13 @@ public:
@note You cannot call this function from ISR context.
*/
MBED_DEPRECATED_SINCE("mbed-os-5.1",
"Thread-spawning constructors hide errors. "
"Replaced by thread.start(task).")
"Thread-spawning constructors hide errors. "
"Replaced by thread.start(task).")
Thread(mbed::Callback<void()> task,
osPriority priority=osPriorityNormal,
uint32_t stack_size=OS_STACK_SIZE,
unsigned char *stack_mem=NULL) {
osPriority priority = osPriorityNormal,
uint32_t stack_size = OS_STACK_SIZE,
unsigned char *stack_mem = NULL)
{
constructor(task, priority, stack_size, stack_mem);
}
@ -171,12 +174,13 @@ public:
*/
template <typename T>
MBED_DEPRECATED_SINCE("mbed-os-5.1",
"Thread-spawning constructors hide errors. "
"Replaced by thread.start(callback(task, argument)).")
"Thread-spawning constructors hide errors. "
"Replaced by thread.start(callback(task, argument)).")
Thread(T *argument, void (T::*task)(),
osPriority priority=osPriorityNormal,
uint32_t stack_size=OS_STACK_SIZE,
unsigned char *stack_mem=NULL) {
osPriority priority = osPriorityNormal,
uint32_t stack_size = OS_STACK_SIZE,
unsigned char *stack_mem = NULL)
{
constructor(mbed::callback(task, argument),
priority, stack_size, stack_mem);
}
@ -203,12 +207,13 @@ public:
*/
template <typename T>
MBED_DEPRECATED_SINCE("mbed-os-5.1",
"Thread-spawning constructors hide errors. "
"Replaced by thread.start(callback(task, argument)).")
"Thread-spawning constructors hide errors. "
"Replaced by thread.start(callback(task, argument)).")
Thread(T *argument, void (*task)(T *),
osPriority priority=osPriorityNormal,
uint32_t stack_size=OS_STACK_SIZE,
unsigned char *stack_mem=NULL) {
osPriority priority = osPriorityNormal,
uint32_t stack_size = OS_STACK_SIZE,
unsigned char *stack_mem = NULL)
{
constructor(mbed::callback(task, argument),
priority, stack_size, stack_mem);
}
@ -235,12 +240,13 @@ public:
@note You cannot call this function from ISR context.
*/
MBED_DEPRECATED_SINCE("mbed-os-5.1",
"Thread-spawning constructors hide errors. "
"Replaced by thread.start(callback(task, argument)).")
Thread(void (*task)(void const *argument), void *argument=NULL,
osPriority priority=osPriorityNormal,
uint32_t stack_size=OS_STACK_SIZE,
unsigned char *stack_mem=NULL) {
"Thread-spawning constructors hide errors. "
"Replaced by thread.start(callback(task, argument)).")
Thread(void (*task)(void const *argument), void *argument = NULL,
osPriority priority = osPriorityNormal,
uint32_t stack_size = OS_STACK_SIZE,
unsigned char *stack_mem = NULL)
{
constructor(mbed::callback((void (*)(void *))task, argument),
priority, stack_size, stack_mem);
}
@ -265,15 +271,15 @@ public:
*/
template <typename T, typename M>
MBED_DEPRECATED_SINCE("mbed-os-5.1",
"The start function does not support cv-qualifiers. "
"Replaced by thread.start(callback(obj, method)).")
osStatus start(T *obj, M method) {
"The start function does not support cv-qualifiers. "
"Replaced by thread.start(callback(obj, method)).")
osStatus start(T *obj, M method)
{
return start(mbed::callback(obj, method));
}
/** Wait for thread to terminate
@return status code that indicates the execution status of the function.
@note not callable from interrupt
@note You cannot call this function from ISR context.
*/
@ -299,14 +305,27 @@ public:
@note You cannot call this function from ISR context.
*/
osPriority get_priority();
osPriority get_priority() const;
/** Set the specified Thread Flags for the thread.
@param flags specifies the flags of the thread that should be set.
@return thread flags after setting or osFlagsError in case of incorrect parameters.
@note You may call this function from ISR context.
*/
uint32_t flags_set(uint32_t flags);
/** Set the specified Thread Flags for the thread.
@param signals specifies the signal flags of the thread that should be set.
@return signal flags after setting or osFlagsError in case of incorrect parameters.
@note You may call this function from ISR context.
@deprecated Other signal_xxx methods have been deprecated in favour of ThisThread::flags functions.
To match this naming scheme, derived from CMSIS-RTOS2, Thread::flags_set is now provided.
*/
MBED_DEPRECATED_SINCE("mbed-os-5.10",
"Other signal_xxx methods have been deprecated in favour of ThisThread::flags functions. "
"To match this naming scheme, derived from CMSIS-RTOS2, Thread::flags_set is now provided.")
int32_t signal_set(int32_t signals);
/** State of the Thread */
@ -337,49 +356,60 @@ public:
@note You cannot call this function from ISR context.
*/
State get_state();
State get_state() const;
/** Get the total stack memory size for this Thread
@return the total stack memory size in bytes
@note You cannot call this function from ISR context.
*/
uint32_t stack_size();
uint32_t stack_size() const;
/** Get the currently unused stack memory for this Thread
@return the currently unused stack memory in bytes
@note You cannot call this function from ISR context.
*/
uint32_t free_stack();
uint32_t free_stack() const;
/** Get the currently used stack memory for this Thread
@return the currently used stack memory in bytes
@note You cannot call this function from ISR context.
*/
uint32_t used_stack();
uint32_t used_stack() const;
/** Get the maximum stack memory usage to date for this Thread
@return the maximum stack memory usage to date in bytes
@note You cannot call this function from ISR context.
*/
uint32_t max_stack();
uint32_t max_stack() const;
/** Get thread name
@return thread name or NULL if the name was not set.
@note You may call this function from ISR context.
*/
const char *get_name();
const char *get_name() const;
/** Get thread id
@return thread ID for reference by other functions.
@note You may call this function from ISR context.
*/
osThreadId_t get_id() const;
/** Clears the specified Thread Flags of the currently running thread.
@param signals specifies the signal flags of the thread that should be cleared.
@return signal flags before clearing or osFlagsError in case of incorrect parameters.
@note You cannot call this function from ISR context.
@deprecated Static methods only affecting current thread cause confusion. Replaced by ThisThread::flags_clear.
*/
MBED_DEPRECATED_SINCE("mbed-os-5.10",
"Static methods only affecting current thread cause confusion. "
"Replaced by ThisThread::flags_clear.")
static int32_t signal_clr(int32_t signals);
/** Wait for one or more Thread Flags to become signaled for the current RUNNING thread.
@ -388,8 +418,13 @@ public:
@return event flag information or error code. @note if @a millisec is set to 0 and flag is no set the event carries osOK value.
@note You cannot call this function from ISR context.
@deprecated Static methods only affecting current thread cause confusion.
Replaced by ThisThread::flags_wait_all, ThisThread::flags_wait_all_for, ThisThread::flags_wait_any and ThisThread:wait_any_for.
*/
static osEvent signal_wait(int32_t signals, uint32_t millisec=osWaitForever);
MBED_DEPRECATED_SINCE("mbed-os-5.10",
"Static methods only affecting current thread cause confusion. "
"Replaced by ThisThread::flags_wait_all, ThisThread::flags_wait_all_for, ThisThread::flags_wait_any and ThisThread:wait_any_for.")
static osEvent signal_wait(int32_t signals, uint32_t millisec = osWaitForever);
/** Wait for a specified time period in milliseconds
Being tick-based, the delay will be up to the specified time - eg for
@ -399,7 +434,11 @@ public:
@return status code that indicates the execution status of the function.
@note You cannot call this function from ISR context.
@deprecated Static methods only affecting current thread cause confusion. Replaced by ThisThread::sleep_for.
*/
MBED_DEPRECATED_SINCE("mbed-os-5.10",
"Static methods only affecting current thread cause confusion. "
"Replaced by ThisThread::sleep_for.")
static osStatus wait(uint32_t millisec);
/** Wait until a specified time in millisec
@ -415,35 +454,56 @@ public:
it may return with an immediate error, or wait for the maximum delay.
@note You cannot call this function from ISR context.
@deprecated Static methods only affecting current thread cause confusion. Replaced by ThisThread::sleep_until.
*/
MBED_DEPRECATED_SINCE("mbed-os-5.10",
"Static methods only affecting current thread cause confusion. "
"Replaced by ThisThread::sleep_until.")
static osStatus wait_until(uint64_t millisec);
/** Pass control to next thread that is in state READY.
@return status code that indicates the execution status of the function.
@note You cannot call this function from ISR context.
@deprecated Static methods only affecting current thread cause confusion. Replaced by ThisThread::sleep_until.
*/
MBED_DEPRECATED_SINCE("mbed-os-5.10",
"Static methods only affecting current thread cause confusion. "
"Replaced by ThisThread::yield.")
static osStatus yield();
/** Get the thread id of the current running thread.
@return thread ID for reference by other functions or NULL in case of error.
@note You may call this function from ISR context.
@deprecated Static methods only affecting current thread cause confusion. Replaced by ThisThread::get_id.
Use Thread::get_id for the ID of a specific Thread.
*/
MBED_DEPRECATED_SINCE("mbed-os-5.10",
"Static methods only affecting current thread cause confusion. "
"Replaced by ThisThread::get_id. Use Thread::get_id for the ID of a specific Thread.")
static osThreadId gettid();
/** Attach a function to be called by the RTOS idle task
@param fptr pointer to the function to be called
@note You may call this function from ISR context.
@deprecated Static methods affecting system cause confusion. Replaced by Kernel::attach_idle_hook.
*/
MBED_DEPRECATED_SINCE("mbed-os-5.10",
"Static methods affecting system cause confusion. "
"Replaced by Kernel::attach_idle_hook.")
static void attach_idle_hook(void (*fptr)(void));
/** Attach a function to be called when a task is killed
@param fptr pointer to the function to be called
@note You may call this function from ISR context.
@deprecated Static methods affecting system cause confusion. Replaced by Kernel::attach_thread_terminate_hook.
*/
MBED_DEPRECATED_SINCE("mbed-os-5.10",
"Static methods affecting system cause confusion. "
"Replaced by Kernel::attach_thread_terminate_hook.")
static void attach_terminate_hook(void (*fptr)(osThreadId id));
/** Thread destructor
@ -455,28 +515,28 @@ public:
private:
// Required to share definitions without
// delegated constructors
void constructor(osPriority priority=osPriorityNormal,
uint32_t stack_size=OS_STACK_SIZE,
unsigned char *stack_mem=NULL,
const char *name=NULL);
void constructor(osPriority priority = osPriorityNormal,
uint32_t stack_size = OS_STACK_SIZE,
unsigned char *stack_mem = NULL,
const char *name = NULL);
void constructor(mbed::Callback<void()> task,
osPriority priority=osPriorityNormal,
uint32_t stack_size=OS_STACK_SIZE,
unsigned char *stack_mem=NULL,
const char *name=NULL);
osPriority priority = osPriorityNormal,
uint32_t stack_size = OS_STACK_SIZE,
unsigned char *stack_mem = NULL,
const char *name = NULL);
void constructor(uint32_t tz_module,
osPriority priority=osPriorityNormal,
uint32_t stack_size=OS_STACK_SIZE,
unsigned char *stack_mem=NULL,
const char *name=NULL);
static void _thunk(void * thread_ptr);
osPriority priority = osPriorityNormal,
uint32_t stack_size = OS_STACK_SIZE,
unsigned char *stack_mem = NULL,
const char *name = NULL);
static void _thunk(void *thread_ptr);
mbed::Callback<void()> _task;
osThreadId_t _tid;
osThreadAttr_t _attr;
bool _dynamic_stack;
Semaphore _join_sem;
Mutex _mutex;
mutable Mutex _mutex;
mbed_rtos_storage_thread_t _obj_mem;
bool _finished;
};

View File

@ -28,6 +28,7 @@
#include "mbed_rtos_storage.h"
#include "rtos/Kernel.h"
#include "rtos/Thread.h"
#include "rtos/ThisThread.h"
#include "rtos/Mutex.h"
#include "rtos/RtosTimer.h"
#include "rtos/Semaphore.h"

53
rtos/rtos_handlers.h Normal file
View File

@ -0,0 +1,53 @@
/** \addtogroup rtos */
/** @{*/
/* mbed Microcontroller Library
* Copyright (c) 2006-2012 ARM Limited
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef RTOS_HANDLERS_H
#define RTOS_HANDLERS_H
#include "cmsis_os2.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* \defgroup rtos_handlers RTOS hook functions
* @{
*/
/**
@note
Sets the hook function called by thread termination
@param fptr Hook function pointer.
*/
void rtos_attach_thread_terminate_hook(void (*fptr)(osThreadId_t id));
/** @}*/
#ifdef __cplusplus
}
#endif
#endif
/** @}*/