Add ThisThread

pull/7872/head
Kevin Bracey 2018-04-03 10:38:53 +03:00
parent 6477b762d1
commit 1330eeecd0
10 changed files with 597 additions and 134 deletions

View File

@ -59,13 +59,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)++;
}
@ -246,118 +246,128 @@ void test_self_terminate()
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()
{
Thread t_wait(osPriorityNormal, THREAD_STACK_SIZE);
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()
{
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
@ -377,26 +387,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();
}
@ -427,9 +437,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();
}
@ -473,7 +483,7 @@ void test_delay()
t.start(callback(test_delay_thread));
Thread::yield();
ThisThread::yield();
TEST_ASSERT_EQUAL(Thread::WaitingDelay, t.get_state());
@ -481,33 +491,33 @@ 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()
{
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
@ -519,22 +529,15 @@ void test_evt_flag_thread(osEventFlagsId_t evtflg)
void test_evt_flag()
{
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)
@ -557,7 +560,7 @@ void test_mutex()
t.start(callback(test_mutex_thread, &mutex));
Thread::yield();
ThisThread::yield();
TEST_ASSERT_EQUAL(Thread::WaitingMutex, t.get_state());
@ -582,7 +585,7 @@ void test_semaphore()
t.start(callback(test_semaphore_thread, &sem));
Thread::yield();
ThisThread::yield();
TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state());
@ -607,7 +610,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());
@ -635,7 +638,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();
@ -681,7 +684,7 @@ void test_thread_ext_stack()
void test_thread_prio()
{
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());
@ -689,7 +692,7 @@ void test_thread_prio()
TEST_ASSERT_EQUAL(osPriorityHigh, t.get_priority());
t.signal_set(0x1);
t.flags_set(0x1);
t.join();
}
@ -726,12 +729,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},
@ -739,7 +742,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,6 +23,8 @@
#include "rtos/Kernel.h"
#include "mbed.h"
#include "rtos/rtos_idle.h"
#include "rtos/rtos_handlers.h"
namespace rtos {
@ -61,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,7 +31,20 @@
#endif
extern void rtos_idle_loop(void);
extern void thread_terminate_hook(osThreadId_t id);
static void (*terminate_hook)(osThreadId_t id);
static void thread_terminate_hook(osThreadId_t id)
{
if (terminate_hook) {
terminate_hook(id);
}
}
void rtos_attach_thread_terminate_hook(void (*fptr)(osThreadId_t id))
{
terminate_hook = fptr;
}
__NO_RETURN void osRtxIdleThread(void *argument)
{

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
@ -195,6 +189,13 @@ osPriority Thread::get_priority()
return ret;
}
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);
@ -338,6 +339,11 @@ const char *Thread::get_name()
return _attr.name;
}
osThreadId_t Thread::get_id() const
{
return _tid;
}
int32_t Thread::signal_clr(int32_t flags)
{
return osThreadFlagsClear(flags);
@ -379,37 +385,14 @@ osEvent Thread::signal_wait(int32_t signals, uint32_t millisec)
osStatus Thread::wait(uint32_t millisec)
{
return osDelay(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);
}
ThisThread::sleep_until(millisec);
return osOK;
}
osStatus Thread::yield()
@ -429,7 +412,7 @@ void Thread::attach_idle_hook(void (*fptr)(void))
void Thread::attach_terminate_hook(void (*fptr)(osThreadId_t id))
{
terminate_hook = fptr;
rtos_attach_thread_terminate_hook(fptr);
}
Thread::~Thread()

View File

@ -280,7 +280,6 @@ public:
/** 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.
*/
@ -308,12 +307,25 @@ public:
*/
osPriority get_priority();
/** 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 */
@ -381,12 +393,23 @@ public:
*/
const char *get_name();
/** 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.
@ -395,7 +418,12 @@ 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.
*/
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
@ -406,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
@ -422,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

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
/** @}*/