From 5c453e5d463d89afef120682f89e583b7e6880b4 Mon Sep 17 00:00:00 2001 From: Hugues Kamba Date: Mon, 20 Jul 2020 17:59:56 +0100 Subject: [PATCH] CMake: Add support for rtos dir --- rtos/CMakeLists.txt | 22 + rtos/ConditionVariable.h | 550 ++++++++++++++++++ rtos/EventFlags.h | 175 ++++++ rtos/Kernel.h | 143 +++++ rtos/Mail.h | 385 ++++++++++++ rtos/MemoryPool.h | 288 +++++++++ rtos/Mutex.h | 234 ++++++++ rtos/Queue.h | 348 +++++++++++ rtos/Semaphore.h | 159 +++++ rtos/ThisThread.h | 290 +++++++++ rtos/Thread.h | 284 +++++++++ rtos/mbed_rtos1_types.h | 30 + rtos/mbed_rtos_storage.h | 26 + rtos/mbed_rtos_types.h | 80 +++ rtos/rtos.h | 48 ++ rtos/source/TARGET_CORTEX/CMakeLists.txt | 34 ++ rtos/source/TARGET_CORTEX/rtx5/CMakeLists.txt | 76 +++ .../RTX/Source/TOOLCHAIN_ARM/CMakeLists.txt | 4 + .../RTX/Source/TOOLCHAIN_GCC/CMakeLists.txt | 4 + .../RTX/Source/TOOLCHAIN_IAR/CMakeLists.txt | 4 + 20 files changed, 3184 insertions(+) create mode 100644 rtos/CMakeLists.txt create mode 100644 rtos/ConditionVariable.h create mode 100644 rtos/EventFlags.h create mode 100644 rtos/Kernel.h create mode 100644 rtos/Mail.h create mode 100644 rtos/MemoryPool.h create mode 100644 rtos/Mutex.h create mode 100644 rtos/Queue.h create mode 100644 rtos/Semaphore.h create mode 100644 rtos/ThisThread.h create mode 100644 rtos/Thread.h create mode 100644 rtos/mbed_rtos1_types.h create mode 100644 rtos/mbed_rtos_storage.h create mode 100644 rtos/mbed_rtos_types.h create mode 100644 rtos/rtos.h create mode 100644 rtos/source/TARGET_CORTEX/CMakeLists.txt create mode 100644 rtos/source/TARGET_CORTEX/rtx5/CMakeLists.txt create mode 100644 rtos/source/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_ARM/CMakeLists.txt create mode 100644 rtos/source/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_GCC/CMakeLists.txt create mode 100644 rtos/source/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_IAR/CMakeLists.txt diff --git a/rtos/CMakeLists.txt b/rtos/CMakeLists.txt new file mode 100644 index 0000000000..dee5f05a40 --- /dev/null +++ b/rtos/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright (c) 2020 ARM Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +target_sources(mbed-os + PRIVATE + source/ConditionVariable.cpp + source/EventFlags.cpp + source/Kernel.cpp + source/Mutex.cpp + source/Semaphore.cpp + source/ThisThread.cpp + source/Thread.cpp +) + + +add_subdirectory(source/TARGET_CORTEX) + +target_include_directories(mbed-os + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + source +) diff --git a/rtos/ConditionVariable.h b/rtos/ConditionVariable.h new file mode 100644 index 0000000000..d602d7c309 --- /dev/null +++ b/rtos/ConditionVariable.h @@ -0,0 +1,550 @@ +/* Mbed Microcontroller Library + * Copyright (c) 2017-2019 ARM Limited + * SPDX-License-Identifier: MIT + * + * 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 CONDITIONVARIABLE_H +#define CONDITIONVARIABLE_H + +#include +#include +#include "rtos/mbed_rtos_types.h" +#include "rtos/Mutex.h" +#include "rtos/Semaphore.h" +#include "rtos/Kernel.h" + +#include "platform/NonCopyable.h" + +#if MBED_CONF_RTOS_PRESENT || defined(DOXYGEN_ONLY) + +namespace rtos { +/** \addtogroup rtos-public-api */ +/** @{*/ + +enum class cv_status { + no_timeout, + timeout +}; + +struct Waiter; +/** + * \defgroup rtos_ConditionVariable ConditionVariable class + * @{ + */ + +/** The ConditionVariable class is a synchronization primitive that allows + * threads to wait until a particular condition occurs. + * + * Use the condition variable in conjunction with a mutex to safely wait for + * or notify waiters of condition changes to a resource accessible by multiple + * threads. + * + * The thread that intends to wait on a ConditionVariable must: + * - Acquire a lock on a mutex. + * - Execute `wait`, `wait_for` or `wait_until`. While the thread is waiting, + * the mutex is unlocked. + * - When the condition variable has been notified, or in the case of `wait_for` + * and `wait_until` the timeout expires, the thread is awakened. + * + * The thread that intends to notify a ConditionVariable must: + * - Acquire a lock on the mutex used to construct the condition variable. + * - Execute `notify_one` or `notify_all` on the condition variable. + * + * All threads waiting on the condition variable wake when + * `ConditionVariable::notify_all` is called. + * At least one thread waiting on the condition variable wakes + * when `ConditionVariable::notify_one` is called. + * + * While a thread is waiting for notification of a + * ConditionVariable, it releases the lock held on the mutex. + * The ConditionVariable reacquires the mutex lock before exiting the wait + * function. + * + * #### Unspecified behavior + * - The thread that is unblocked on `ConditionVariable::notify_one` is + * unspecified if there are multiple waiters. + * - When `ConditionVariable::notify_one` or `ConditionVariable::notify_all` is + * called and there are one or more waiters, and one or more threads + * attempting to acquire the condition variable's mutex, the order in which the mutex is + * acquired is unspecified. + * - Spurious notifications (not triggered by the application) can occur. + * + * #### Undefined behavior + * - Calling wait if the mutex is not locked by the current thread is undefined + * behavior. + * - The order in which waiting threads acquire the condition variable's + * mutex after `ConditionVariable::notify_all` is called is undefined. + * - The behavior of `ConditionVariable::wait` and `ConditionVariable::wait_for` + * is undefined if the condition variable's mutex is locked more than once by + * the calling thread. + * + * @note Synchronization level: Thread safe + * + * @note Bare metal profile: This class is not supported. + * + * Example: + * + * @code + * #include "mbed.h" + * + * Mutex mutex; + * ConditionVariable cv(mutex); + * + * // These variables are protected by locking the mutex. + * uint32_t work_count = 0; + * bool done = false; + * + * void worker_thread() + * { + * // Acquire lock on mutex before accessing protected variables and waiting. + * mutex.lock(); + * + * while (done == false) { + * printf("Worker thread: Count: %lu\r\n", work_count); + * + * // Wait for main thread to notify the condition variable. + * printf("Worker thread: Waiting\r\n"); + * cv.wait(); + * } + * + * printf("Worker: Exiting\r\n"); + * + * // The condition variable acquires the lock when exiting the `wait` function. + * // Unlock mutex when exiting the thread. + * mutex.unlock(); + * } + * + * int main() + * { + * Thread thread; + * thread.start(worker_thread); + * + * for (int i = 0; i < 5; i++) { + * // Acquire lock on mutex before modifying variables and notifying. + * mutex.lock(); + * + * // Change count and notify waiters. + * work_count++; + * printf("Main thread: Set count to: %lu\r\n", work_count); + * printf("Main thread: Notifying worker thread\r\n"); + * cv.notify_all(); + * + * // Mutex must be unlocked before the worker thread can acquire it. + * mutex.unlock(); + * + * ThisThread::sleep_for(1000); + * } + * + * // Change done and notify waiters of this. + * mutex.lock(); + * done = true; + * cv.notify_all(); + * mutex.unlock(); + * + * thread.join(); + * + * printf("Main: Exiting\r\n"); + * } + * @endcode + */ + +class ConditionVariable : private mbed::NonCopyable { +public: + /** Create and initialize a ConditionVariable object. + * + * @note You cannot call this function from ISR context. + */ + ConditionVariable(Mutex &mutex); + + /** Wait for a notification. + * + * Wait causes the current thread to block until the condition variable + * receives a notification from another thread. + * + * @note - The thread calling this function must be the owner of the + * ConditionVariable's mutex, and it must be locked exactly once. + * + * @note - Spurious notifications can occur, so the caller of this API + * should check to make sure the condition the caller is waiting on has + * been met. + * + * @note - The current thread releases the mutex while inside the wait + * function and reacquires it upon exiting the function. + * + * Example: + * @code + * mutex.lock(); + * + * while (!condition_met) { + * cond.wait(); + * } + * + * function_to_handle_condition(); + * + * mutex.unlock(); + * @endcode + * + * @note You cannot call this function from ISR context. + */ + void wait(); + + /** Wait for a predicate. + * + * Wait causes the current thread to block until the predicate is + * true. + * + * @param pred A function-like object such that `pred()` is convertible to bool + * + * @note - The thread calling this function must be the owner of the + * ConditionVariable's mutex, and it must be locked exactly once. + * + * @note - The current thread releases the mutex while inside the wait + * function and reacquires it upon exiting the function. + * + * Example: + * @code + * extern bool data_available(); + * + * mutex.lock(); + * + * cond.wait(data_available); + * + * function_to_handle_data(); + * + * mutex.unlock(); + * @endcode + * + * @note You cannot call this function from ISR context. + */ + template + void wait(Predicate pred) + { + while (!pred()) { + wait(); + } + } + + + /** Wait for a notification until the specified time. + * + * Wait until causes the current thread to block until the condition + * variable is notified, or a specific time given by millisec parameter is + * reached. + * + * @param millisec Absolute end time referenced to `Kernel::get_ms_count()` + * @return `true` if a timeout occurred, `false` otherwise. + * + * @note - The thread calling this function must be the owner of the + * ConditionVariable's mutex, and it must be locked exactly once. + * + * @note - Spurious notifications can occur, so the caller of this API + * should check to make sure the condition the caller is waiting on has + * been met. + * + * @note - The current thread releases the lock while inside the wait + * function and reacquires it upon exiting the function. + * + * Example: + * @code + * mutex.lock(); + * uint64_t end_time = Kernel::get_ms_count() + COND_WAIT_TIMEOUT; + * + * while (!condition_met) { + * if (cond.wait_until(end_time)) { + * break; + * } + * } + * + * if (condition_met) { + * function_to_handle_condition(); + * } + * + * mutex.unlock(); + * @endcode + * + * @note You cannot call this function from ISR context. + * @deprecated Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` + * rather than `Kernel::get_ms_count() + 5000`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.") + bool wait_until(uint64_t millisec); + + /** Wait for a notification until the specified time. + * + * Wait until causes the current thread to block until the condition + * variable is notified, or a specific time given by millisec parameter is + * reached. + * + * @param abs_time Absolute end time referenced to `Kernel::Clock` + * @return `cv_status::timeout` if a timeout occurred, `cv_status::no_timeout` otherwise. + * + * @note - The thread calling this function must be the owner of the + * ConditionVariable's mutex, and it must be locked exactly once. + * + * @note - Spurious notifications can occur, so the caller of this API + * should check to make sure the condition the caller is waiting on has + * been met. + * + * @note - The current thread releases the lock while inside the wait + * function and reacquires it upon exiting the function. + * + * Example: + * @code + * mutex.lock(); + * Kernel::Clock::time_point end_time = Kernel::Clock::now() + 2s; + * + * while (!condition_met) { + * if (cond.wait_until(end_time) == cv_status::timeout) { + * break; + * } + * } + * + * if (condition_met) { + * function_to_handle_condition(); + * } + * + * mutex.unlock(); + * @endcode + * + * @note You cannot call this function from ISR context. + */ + cv_status wait_until(Kernel::Clock::time_point abs_time); + + /** Wait for a predicate until the specified time. + * + * Wait until causes the current thread to block until the predicate is true, + * or a specific time given by abs_time parameter is reached. + * + * @param abs_time Absolute end time referenced to `Kernel::Clock` + * @param pred A function-like object such that `pred()` is convertible to bool + * @return The state of the predicate + * + * @note - The thread calling this function must be the owner of the + * ConditionVariable's mutex, and it must be locked exactly once. + * + * @note - The current thread releases the mutex while inside the wait + * function and reacquires it upon exiting the function. + * + * Example: + * @code + * extern bool data_available(); + * + * mutex.lock(); + * + * if (cond.wait_until(Kernel::Clock::now() + 2s, data_available)) { + * function_to_handle_data(); + * } + * + * mutex.unlock(); + * @endcode + * + * @note You cannot call this function from ISR context. + */ + template + bool wait_until(Kernel::Clock::time_point abs_time, Predicate pred) + { + while (!pred()) { + if (wait_until(abs_time) == cv_status::timeout) { + return pred(); + } + } + return true; + } + + /** Wait for a notification or timeout. + * + * `Wait for` causes the current thread to block until the condition + * variable receives a notification from another thread, or the timeout + * specified by the millisec parameter is reached. + * + * @param millisec Timeout value or osWaitForever in case of no timeout. + * @return `true` if a timeout occurred, `false` otherwise. + * + * @note - The thread calling this function must be the owner of the + * ConditionVariable's mutex, and it must be locked exactly once. + * + * @note - Spurious notifications can occur, so the caller of this API + * should check to make sure the condition the caller is waiting on has + * been met. + * + * @note - The current thread releases the lock while inside the wait + * function and reacquire it upon exiting the function. + * + * Example: + * @code + * mutex.lock(); + * + * while (!condition_met) { + * cond.wait_for(MAX_SLEEP_TIME); + * if (!condition_met) { + * do_other_work_while_condition_false(); + * } + * } + * + * if (condition_met) { + * function_to_handle_condition(); + * } + * + * mutex.unlock(); + * @endcode + * + * @note You cannot call this function from ISR context. + * @deprecated Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.") + bool wait_for(uint32_t millisec); + + /** Wait for a notification or timeout. + * + * `Wait for` causes the current thread to block until the condition + * variable receives a notification from another thread, or the timeout + * specified by the millisec parameter is reached. + * + * @param rel_time Timeout value. + * @return `cv_status::timeout` if a timeout occurred, `cv_status::no_timeout` otherwise. + * + * @note - The thread calling this function must be the owner of the + * ConditionVariable's mutex, and it must be locked exactly once. + * + * @note - Spurious notifications can occur, so the caller of this API + * should check to make sure the condition the caller is waiting on has + * been met. + * + * @note - The current thread releases the lock while inside the wait + * function and reacquire it upon exiting the function. + * + * Example: + * @code + * mutex.lock(); + * + * while (!condition_met) { + * cond.wait_for(MAX_SLEEP_TIME); + * if (!condition_met) { + * do_other_work_while_condition_false(); + * } + * } + * + * if (condition_met) { + * function_to_handle_condition(); + * } + * + * mutex.unlock(); + * @endcode + * + * @note You cannot call this function from ISR context. + */ + cv_status wait_for(Kernel::Clock::duration_u32 rel_time); + + /** Wait for a predicate or timeout. + * + * `Wait for` causes the current thread to block until the predicate + * is true, or the timeout specified by the rel_time parameter is reached. + * + * @param rel_time Timeout value. + * @param pred a function-like object such that `pred()` is convertible to bool + * @return The state of the predicate + * + * @note - The thread calling this function must be the owner of the + * ConditionVariable's mutex, and it must be locked exactly once. + * + * @note - The current thread releases the mutex while inside the wait + * function and reacquire it upon exiting the function. + * + * Example: + * @code + * extern bool data_available(); + * + * mutex.lock(); + * + * if (cond.wait_for(2s, data_available)) { + * function_to_handle_data(); + * } + * + * mutex.unlock(); + * @endcode + * + * @note You cannot call this function from ISR context. + */ + template + bool wait_for(Kernel::Clock::duration rel_time, Predicate pred) + { + return wait_until(Kernel::Clock::now() + rel_time, std::move(pred)); + } + + /** Notify one waiter on this condition variable that a condition changed. + * + * This function unblocks one of the threads waiting for the condition + * variable. + * + * @note - The thread calling this function must be the owner of the + * ConditionVariable's mutex. + * + * @note - The thread that is unblocked on ConditionVariable::notify_one is + * undefined if there are multiple waiters. + * + * @note You cannot call this function from ISR context. + */ + void notify_one(); + + /** Notify all waiters on this condition variable that a condition changed. + * + * This function unblocks all of the threads waiting for the condition + * variable. + * + * @note - The thread calling this function must be the owner of the + * ConditionVariable's mutex. + * + * @note - If there are one or more waiters and one or more threads + * attempting to acquire the condition variable's mutex the order in which + * the mutex is acquired is undefined. + * + * @note You cannot call this function from ISR context. + */ + void notify_all(); + + /** ConditionVariable destructor. + * + * @note You cannot call this function from ISR context. + */ + ~ConditionVariable(); + +#if !defined(DOXYGEN_ONLY) +protected: + struct Waiter { + Waiter(); + Semaphore sem; + Waiter *prev; + Waiter *next; + bool in_list; + }; + + static void _add_wait_list(Waiter **wait_list, Waiter *waiter); + static void _remove_wait_list(Waiter **wait_list, Waiter *waiter); + Mutex &_mutex; + Waiter *_wait_list; +#endif // !defined(DOXYGEN_ONLY) +}; + +/** @}*/ +/** @}*/ +} // namespace rtos +#endif + +#endif diff --git a/rtos/EventFlags.h b/rtos/EventFlags.h new file mode 100644 index 0000000000..67691428bc --- /dev/null +++ b/rtos/EventFlags.h @@ -0,0 +1,175 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * SPDX-License-Identifier: MIT + * + * 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 EVENT_FLAG_H +#define EVENT_FLAG_H + +#include +#include +#include "rtos/Kernel.h" +#include "rtos/mbed_rtos_types.h" +#include "rtos/mbed_rtos1_types.h" +#include "rtos/mbed_rtos_storage.h" + +#include "platform/NonCopyable.h" + +namespace rtos { +/** \addtogroup rtos-public-api */ +/** @{*/ + +/** + * \defgroup rtos_EventFlags EventFlags class + * @{ + */ + +/** The EventFlags class is used to control event flags or wait for event flags other threads control. + + @note + EventFlags support 31 flags. The MSB flag is ignored. It is used to return an error code (@a osFlagsError). + + @note + Memory considerations: The EventFlags control structures will be created on the current thread's stack, both for the Mbed OS + and underlying RTOS objects (static or dynamic RTOS memory pools are not being used). +*/ +class EventFlags : private mbed::NonCopyable { +public: + /** Create and initialize an EventFlags object. + * + * @note You cannot call this function from ISR context. + */ + EventFlags(); + + /** Create and initialize an EventFlags object. + + @param name name to be used for this EventFlags. It has to stay allocated for the lifetime of the thread. + + @note You cannot call this function from ISR context. + */ + EventFlags(const char *name); + + /** Set the specified event flags. + @param flags the flags that will be set. + @return event flags after setting or error code if highest bit set (see @a osFlagsError for details). + + @note This function may be called from ISR context. + */ + uint32_t set(uint32_t flags); + + /** Clear the specified event flags. + @param flags the flags that will be cleared (default: 0x7fffffff -- all flags). + @return event flags before clearing or error code if highest bit set (see @a osFlagsError for details). + + @note You may call this function from ISR context. + */ + uint32_t clear(uint32_t flags = 0x7fffffff); + + /** Get the currently set event flags. + @return current event flags. + + @note You may call this function from ISR context. + */ + uint32_t get() const; + + /** Wait for all of the specified event flags to become signaled. + @param flags the flags to wait for (default: 0 -- no flags). + @param millisec timeout value (default: osWaitForever). + @param clear clear specified event flags after waiting for them (default: true). + @return event flags before clearing or error code if highest bit set (see @a osFlagsError for details). + + @note You may call this function from ISR context if the millisec parameter is set to 0. + */ + uint32_t wait_all(uint32_t flags = 0, uint32_t millisec = osWaitForever, bool clear = true); + + /** Wait for all of the specified event flags to become signaled. + @param flags the flags to wait for. + @param rel_time timeout value. + @param clear clear specified event flags after waiting for them (default: true). + @return event flags before clearing or error code if highest bit set (see @a osFlagsError for details). + + @note You may call this function from ISR context if the rel_time parameter is set to 0. + */ + uint32_t wait_all_for(uint32_t flags, Kernel::Clock::duration_u32 rel_time, bool clear = true); + + /** Wait for all of the specified event flags to become signaled. + @param flags the flags to wait for. + @param abs_time timeout value. + @param clear clear specified event flags after waiting for them (default: true). + @return event flags before clearing or error code if highest bit set (see @a osFlagsError for details). + + @note You cannot call this function from ISR context. + */ + uint32_t wait_all_until(uint32_t flags, Kernel::Clock::time_point abs_time, bool clear = true); + + /** Wait for any of the specified event flags to become signaled. + @param flags the flags to wait for (default: 0 -- no flags). + @param millisec timeout value (default: osWaitForever). + @param clear clear specified event flags after waiting for them (default: true). + @return event flags before clearing or error code if highest bit set (see @a osFlagsError for details). + + @note This function may be called from ISR context if the millisec parameter is set to 0. + */ + uint32_t wait_any(uint32_t flags = 0, uint32_t millisec = osWaitForever, bool clear = true); + + /** Wait for any of the specified event flags to become signaled. + @param flags the flags to wait for. + @param rel_time timeout value. + @param clear clear specified event flags after waiting for them (default: true). + @return event flags before clearing or error code if highest bit set (see @a osFlagsError for details). + + @note This function may be called from ISR context if the millisec parameter is set to 0. + */ + uint32_t wait_any_for(uint32_t flags, Kernel::Clock::duration_u32 rel_time, bool clear = true); + + /** Wait for any of the specified event flags to become signaled. + @param flags the flags to wait for. + @param abs_time timeout value. + @param clear clear specified event flags after waiting for them (default: true). + @return event flags before clearing or error code if highest bit set (see @a osFlagsError for details). + + @note You cannot call this function from ISR context. + */ + uint32_t wait_any_until(uint32_t flags, Kernel::Clock::time_point abs_time, bool clear = true); + + /** EventFlags destructor. + + @note You cannot call this function from ISR context. + */ + ~EventFlags(); + +private: + void constructor(const char *name = nullptr); + uint32_t wait_for(uint32_t flags, uint32_t opt, Kernel::Clock::duration_u32 rel_time, bool clear); + uint32_t wait_until(uint32_t flags, uint32_t opt, Kernel::Clock::time_point abs_time, bool clear); + +#if MBED_CONF_RTOS_PRESENT + osEventFlagsId_t _id; + mbed_rtos_storage_event_flags_t _obj_mem; +#else + uint32_t _flags; +#endif +}; + +/** @}*/ +/** @}*/ + +} +#endif diff --git a/rtos/Kernel.h b/rtos/Kernel.h new file mode 100644 index 0000000000..c653b163f0 --- /dev/null +++ b/rtos/Kernel.h @@ -0,0 +1,143 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2019 ARM Limited + * SPDX-License-Identifier: MIT + * + * 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 KERNEL_H +#define KERNEL_H + +#include +#include +#include "rtos/mbed_rtos_types.h" +#include "platform/mbed_toolchain.h" +#if !MBED_CONF_RTOS_PRESENT +#include "platform/source/mbed_os_timer.h" +#endif + + +namespace rtos { + +/** \addtogroup rtos-public-api */ +/** @{*/ + +/** Functions in the Kernel namespace control RTOS kernel information. */ +namespace Kernel { + +namespace impl { +/* Internal integer-returning function. + * + * ARM EABI means that `time_point`s do not get returned in registers, so + * it's worth having the actual exteernal definition return an integer, and only + * convert to `time_point` via the inline function `now()`. + */ +uint64_t get_tick_count(); +} + +/** Read the current RTOS kernel millisecond tick count. + The tick count corresponds to the tick count the RTOS uses for timing + purposes. It increments monotonically from 0 at boot, so it effectively + never wraps. If the underlying RTOS only provides a 32-bit tick count, + this method expands it to 64 bits. + @return RTOS kernel current tick count + @note Mbed OS always uses millisecond RTOS ticks, and this could only wrap + after half a billion years. + @note You cannot call this function from ISR context. + @deprecated Use `Kernel::Clock::now()` to get a chrono time_point instead of an integer millisecond count. + */ +MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Use `Kernel::Clock::now()` to get a chrono time_point instead of an integer millisecond count.") +uint64_t get_ms_count(); + +/** A C++11 chrono TrivialClock for the kernel millisecond tick count + * + * @note To fit better into the chrono framework, Kernel::Clock uses + * std::chrono::milliseconds as its representation, which makes it signed + * and at least 45 bits (so it will be int64_t or equivalent). + */ +struct Clock { + Clock() = delete; + /* Standard TrivialClock fields */ + using duration = std::chrono::milliseconds; + using rep = duration::rep; + using period = duration::period; +#if MBED_CONF_RTOS_PRESENT + using time_point = std::chrono::time_point; +#else + /* In non-RTOS builds, the clock maps directly to the underlying clock, and must + * indicate that here, so we can do implicit conversion internally. + */ + using time_point = std::chrono::time_point; +#endif + static constexpr bool is_steady = true; + static time_point now() + { + return time_point(duration(impl::get_tick_count())); + } + /* Extension to make it easy to use 32-bit durations for some APIs, as we historically have, + * for efficiency. + */ + using duration_u32 = std::chrono::duration; + + /** Lock the clock to ensure it stays running; dummy for API compatibility with HighResClock */ + static void lock() + { + } + + /** Unlock the clock, allowing it to stop during power saving; dummy for API compatibility with HighResClock */ + static void unlock() + { + } +}; + +/** Maximum duration for Kernel::Clock::duration_u32-based APIs + * + * @note As duration_u32-based APIs pass through straight to CMSIS-RTOS, they will + * interpret duration_u32(0xFFFFFFFF) as "wait forever". Indicate maximum + * wait time of 0xFFFFFFFE for these calls (which is ~49 days). + */ +constexpr Clock::duration_u32 wait_for_u32_max{osWaitForever - 1}; + +/** Magic "wait forever" constant for Kernel::Clock::duration_u32-based APIs + * + * Many duration_u32-based APIs treat duration_u32(0xFFFFFFFF) as "wait forever". + */ +constexpr Clock::duration_u32 wait_for_u32_forever{osWaitForever}; + +/** 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. + @note Bare metal profile: This API is not supported. +*/ +void attach_idle_hook(void (*fptr)(void)); + +/** Attach a function to be called when a thread terminates. + @param fptr pointer to the function to be called + + @note You may call this function from ISR context. + @note Bare metal profile: This API is not supported. +*/ +void attach_thread_terminate_hook(void (*fptr)(osThreadId_t id)); + +} // namespace Kernel + +/** @}*/ + +} // namespace rtos +#endif diff --git a/rtos/Mail.h b/rtos/Mail.h new file mode 100644 index 0000000000..b17d78fd0a --- /dev/null +++ b/rtos/Mail.h @@ -0,0 +1,385 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * SPDX-License-Identifier: MIT + * + * 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 MAIL_H +#define MAIL_H + +#include +#include + +#include "rtos/Queue.h" +#include "rtos/MemoryPool.h" +#include "rtos/mbed_rtos_types.h" +#include "rtos/mbed_rtos_storage.h" +#include "rtos/mbed_rtos1_types.h" + +#include "platform/mbed_toolchain.h" +#include "platform/mbed_assert.h" +#include "platform/NonCopyable.h" + +#ifndef MBED_NO_GLOBAL_USING_DIRECTIVE +using namespace rtos; +#endif + +#if MBED_CONF_RTOS_PRESENT || defined(DOXYGEN_ONLY) + +namespace rtos { +/** \addtogroup rtos-public-api */ +/** @{*/ + +/** + * \defgroup rtos_Mail Mail class + * @{ + */ + +/** The Mail class allows you to control, send, receive or wait for mail. + * A mail is a memory block that is sent to a thread or interrupt service routine (ISR). + * @tparam T Data type of a single mail message element. + * @tparam queue_sz Maximum number of mail messages in queue. + * + * @note + * Memory considerations: The mail data store and control structures are part of this class - they do not (themselves) + * allocate memory on the heap, both for the Mbed OS and underlying RTOS objects (static or dynamic RTOS memory + * pools are not being used). + * + * @note + * Bare metal profile: This class is not supported. + */ +template +class Mail : private mbed::NonCopyable > { +public: + /** Create and initialize Mail queue. + * + * @note You cannot call this function from ISR context. + */ + Mail() = default; + + /** Check if the mail queue is empty. + * + * @return State of queue. + * @retval true Mail queue is empty. + * @retval false Mail queue contains mail. + * + * @note You may call this function from ISR context. + */ + bool empty() const + { + return _queue.empty(); + } + + /** Check if the mail queue is full. + * + * @return State of queue. + * @retval true Mail queue is full. + * @retval false Mail queue is not full. + * + * @note You may call this function from ISR context. + */ + bool full() const + { + return _queue.full(); + } + + /** Allocate a memory block of type T, without blocking. + * + * @param millisec Not used (see note). + * + * @return Pointer to memory block that you can fill with mail or nullptr in case error. + * + * @note You may call this function from ISR context. + * @note If blocking is required, use Mail::try_alloc_for or Mail::try_alloc_until + * @deprecated Replaced with try_alloc. In future alloc() will be an untimed blocking call. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_alloc. In future alloc() will be an untimed blocking call.") + T *alloc(MBED_UNUSED uint32_t millisec = 0) + { + return try_alloc(); + } + + /** Allocate a memory block of type T, without blocking. + * + * @return Pointer to memory block that you can fill with mail or nullptr in case error. + * + * @note You may call this function from ISR context. + * @note If blocking is required, use Mail::try_alloc_for or Mail::try_alloc_until + */ + T *try_alloc() + { + return _pool.try_alloc(); + } + + /** Allocate a memory block of type T, optionally blocking. + * + * @param rel_time Timeout value, or Kernel::wait_for_u32_forever. + * + * @return Pointer to memory block that you can fill with mail or nullptr in case error. + * + * @note You may call this function from ISR context if the millisec parameter is set to 0. + */ + T *try_alloc_for(Kernel::Clock::duration_u32 rel_time) + { + return _pool.try_alloc_for(rel_time); + } + + /** Allocate a memory block of type T, optionally blocking. + * + * @param millisec Timeout value, or osWaitForever. + * + * @return Pointer to memory block that you can fill with mail or nullptr in case error. + * + * @note You may call this function from ISR context if the millisec parameter is set to 0. + * @deprecated Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.") + T *alloc_for(uint32_t millisec) + { + return try_alloc_for(std::chrono::duration(millisec)); + } + + /** Allocate a memory block of type T, blocking. + * + * @param abs_time Absolute timeout time, referenced to Kernel::Clock. + * + * @return Pointer to memory block that you can fill with mail or nullptr in case error. + * + * @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. + */ + T *try_alloc_until(Kernel::Clock::time_point abs_time) + { + return _pool.try_alloc_until(abs_time); + } + + /** Allocate a memory block of type T, blocking. + * + * @param millisec Absolute timeout time, referenced to Kernel::get_ms_count(). + * + * @return Pointer to memory block that you can fill with mail or nullptr in case error. + * + * @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. + * @deprecated Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` + * rather than `Kernel::get_ms_count() + 5000`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.") + T *alloc_until(uint64_t millisec) + { + return try_alloc_until(Kernel::Clock::time_point(std::chrono::duration(millisec))); + } + + /** Allocate a memory block of type T, and set memory block to zero. + * + * @param millisec Not used (see note). + * + * @return Pointer to memory block that you can fill with mail or nullptr in case error. + * + * @note You may call this function from ISR context. + * @note If blocking is required, use Mail::try_calloc_for or Mail::try_calloc_until + * @deprecated Replaced with try_calloc. In future calloc() will be an untimed blocking call. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_calloc. In future calloc() will be an untimed blocking call.") + T *calloc(MBED_UNUSED uint32_t millisec = 0) + { + return try_calloc(); + } + + /** Allocate a memory block of type T, and set memory block to zero. + * + * @return Pointer to memory block that you can fill with mail or nullptr in case error. + * + * @note You may call this function from ISR context. + * @note If blocking is required, use Mail::try_calloc_for or Mail::try_calloc_until + */ + T *try_calloc() + { + return _pool.try_calloc(); + } + + /** Allocate a memory block of type T, optionally blocking, and set memory block to zero. + * + * @param rel_time Timeout value, or Kernel::wait_for_u32_forever. + * + * @return Pointer to memory block that you can fill with mail or nullptr in case error. + * + * @note You may call this function from ISR context if the rel_time parameter is set to 0. + */ + T *try_calloc_for(Kernel::Clock::duration_u32 rel_time) + { + return _pool.try_calloc_for(rel_time); + } + + /** Allocate a memory block of type T, optionally blocking, and set memory block to zero. + * + * @param millisec Timeout value, or osWaitForever. + * + * @return Pointer to memory block that you can fill with mail or nullptr in case error. + * + * @note You may call this function from ISR context if the millisec parameter is set to 0. + * @deprecated Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.") + T *calloc_for(uint32_t millisec) + { + return try_calloc_for(std::chrono::duration(millisec)); + } + + /** Allocate a memory block of type T, blocking, and set memory block to zero. + * + * @param abs_time Absolute timeout time, referenced to Kernel::Clock. + * + * @return Pointer to memory block that you can fill with mail or nullptr in case error. + * + * @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. + */ + T *try_calloc_until(Kernel::Clock::time_point abs_time) + { + return _pool.try_calloc_until(abs_time); + } + + /** Allocate a memory block of type T, blocking, and set memory block to zero. + * + * @param millisec Absolute timeout time, referenced to Kernel::get_ms_count(). + * + * @return Pointer to memory block that you can fill with mail or nullptr in case error. + * + * @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. + * @deprecated Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` + * rather than `Kernel::get_ms_count() + 5000`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.") + T *calloc_until(uint64_t millisec) + { + return try_calloc_until(Kernel::Clock::time_point(std::chrono::duration(millisec))); + } + + /** Put a mail in the queue. + * + * @param mptr Memory block previously allocated with Mail::alloc or Mail::calloc. + * + * @return Status code that indicates the execution status of the function (osOK on success). + * See note. + * + * @note You may call this function from ISR context. + * @note As the mail should have already been allocated, and the memory pool is the same size + * as the queue, the put operation should always succeed, despite being implemented with + * Queue::try_put - there is room in the queue for every mail from the pool. Therefore + * use of the return value is deprecated, and the function will return void in future. + */ + osStatus put(T *mptr) + { + bool ok = _queue.try_put(mptr); + MBED_ASSERT(ok); + return ok ? osOK : osErrorResource; + } + + /** Get a mail from the queue. + * + * @param rel_time Timeout value (default: Kernel::wait_for_u32_forever). + * + * @return Event that contains mail information and status code. The status code + * is stored in the status member: + * @a osEventMail Mail successfully received. + * @a osOK No mail is available (and no timeout was specified). + * @a osEventTimeout No mail has arrived during the given timeout period. + * @a osErrorParameter A parameter is invalid or outside of a permitted range. + * + * @note You may call this function from ISR context if the millisec parameter is set to 0. + * @deprecated Replaced with try_get and try_get_for. In future get will be an untimed blocking call. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_get and try_get_for. In future get will be an untimed blocking call.") + osEvent get(uint32_t millisec = osWaitForever) + { + osEvent evt = _queue.get(millisec); + if (evt.status == osEventMessage) { + evt.status = osEventMail; + } + return evt; + } + + /** Get a mail from the queue. + * + * @return Pointer to received mail, or nullptr if none was received. + * + * @note You may call this function from ISR context. + */ + T *try_get() + { + T *mptr = nullptr; + _queue.try_get(&mptr); + return mptr; + } + + /** Get a mail from the queue. + * + * @param rel_time Timeout value or Kernel::wait_for_u32_forever. + * + * @return Pointer to received mail, or nullptr if none was received. + * + * @note You may call this function from ISR context if the millisec parameter is set to 0. + */ + T *try_get_for(Kernel::Clock::duration_u32 rel_time) + { + T *mptr = nullptr; + _queue.try_get_for(rel_time, &mptr); + return mptr; + } + + /** Free a memory block from a mail. + * + * @param mptr Pointer to the memory block that was obtained with Mail::get. + * + * @return Status code that indicates the execution status of the function (osOK on success). + * + * @note You may call this function from ISR context. + */ + osStatus free(T *mptr) + { + return _pool.free(mptr); + } + +private: + Queue _queue; + MemoryPool _pool; +}; + +/** @}*/ +/** @}*/ + +} + +#endif + +#endif diff --git a/rtos/MemoryPool.h b/rtos/MemoryPool.h new file mode 100644 index 0000000000..9d1c6de942 --- /dev/null +++ b/rtos/MemoryPool.h @@ -0,0 +1,288 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * SPDX-License-Identifier: MIT + * + * 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 MEMORYPOOL_H +#define MEMORYPOOL_H + +#include +#include + +#include "rtos/mbed_rtos_types.h" +#include "rtos/mbed_rtos1_types.h" +#include "rtos/mbed_rtos_storage.h" +#include "platform/NonCopyable.h" +#include "platform/mbed_assert.h" +#include "Kernel.h" + + +#if MBED_CONF_RTOS_PRESENT || defined(DOXYGEN_ONLY) +namespace rtos { +/** \addtogroup rtos-public-api */ +/** @{*/ + +/** + * \defgroup rtos_MemoryPool MemoryPool class + * @{ + */ + +/** Define and manage fixed-size memory pools of objects of a given type. + @tparam T data type of a single object (element). + @tparam queue_sz maximum number of objects (elements) in the memory pool. + + @note + Memory considerations: The memory pool data store and control structures will be created on current thread's stack, + both for the mbed OS and underlying RTOS objects (static or dynamic RTOS memory pools are not being used). + + @note + Bare metal profile: This class is not supported. +*/ +template +class MemoryPool : private mbed::NonCopyable > { + MBED_STATIC_ASSERT(pool_sz > 0, "Invalid memory pool size. Must be greater than 0."); +public: + /** Create and Initialize a memory pool. + * + * @note You cannot call this function from ISR context. + */ + MemoryPool() + { + memset(_pool_mem, 0, sizeof(_pool_mem)); + osMemoryPoolAttr_t attr = { 0 }; + attr.mp_mem = _pool_mem; + attr.mp_size = sizeof(_pool_mem); + attr.cb_mem = &_obj_mem; + attr.cb_size = sizeof(_obj_mem); + _id = osMemoryPoolNew(pool_sz, sizeof(T), &attr); + MBED_ASSERT(_id); + } + + /** Destroy a memory pool + * + * @note You cannot call this function from ISR context. + */ + ~MemoryPool() + { + osMemoryPoolDelete(_id); + } + + /** Allocate a memory block from a memory pool, without blocking. + @return address of the allocated memory block or nullptr in case of no memory available. + + @note You may call this function from ISR context. + @deprecated Replaced with try_alloc. In future alloc() will be an untimed blocking call. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_alloc. In future alloc() will be an untimed blocking call.") + T *alloc() + { + return try_alloc(); + } + + /** Allocate a memory block from a memory pool, without blocking. + @return address of the allocated memory block or nullptr in case of no memory available. + + @note You may call this function from ISR context. + */ + T *try_alloc() + { + return (T *)osMemoryPoolAlloc(_id, 0); + } + + /** Allocate a memory block from a memory pool, optionally blocking. + @param millisec timeout value (osWaitForever to wait forever) + @return address of the allocated memory block or nullptr in case of no memory available. + + @note You may call this function from ISR context if the millisec parameter is set to 0. + @deprecated Replaced with `try_alloc_for`. For example use `try_alloc_for(5s)` rather than `alloc_for(5000)`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with `try_alloc_for`. For example use `try_alloc_for(5s)` rather than `alloc_for(5000)`.") + T *alloc_for(uint32_t millisec) + { + return try_alloc_for(std::chrono::duration(millisec)); + } + + /** Allocate a memory block from a memory pool, optionally blocking. + @param rel_time timeout value (Kernel::wait_for_u32_forever to wait forever) + @return address of the allocated memory block or nullptr in case of no memory available. + + @note You may call this function from ISR context if the rel_time parameter is set to 0. + */ + T *try_alloc_for(Kernel::Clock::duration_u32 rel_time) + { + return (T *)osMemoryPoolAlloc(_id, rel_time.count()); + } + + /** Allocate a memory block from a memory pool, blocking. + @param millisec absolute timeout time, referenced to Kernel::get_ms_count(). + @return address of the allocated memory block or nullptr in case of no memory available. + + @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. + @deprecated Replaced with `try_alloc_until`. For example use `try_alloc_until(Kernel::Clock::now() + 5s)` + rather than `alloc_until(Kernel::get_ms_count() + 5000)`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with `try_alloc_until`. For example use `try_alloc_until(Kernel::Clock::now() + 5s)` rather than `alloc_until(Kernel::get_ms_count() + 5000)`.") + T *alloc_until(uint64_t millisec) + { + return try_alloc_until(Kernel::Clock::time_point(std::chrono::duration(millisec))); + } + + /** Allocate a memory block from a memory pool, blocking. + @param abs_time absolute timeout time, referenced to Kernel::Clock. + @return address of the allocated memory block or nullptr in case of no memory available. + + @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. + */ + T *try_alloc_until(Kernel::Clock::time_point abs_time) + { + Kernel::Clock::time_point now = Kernel::Clock::now(); + Kernel::Clock::duration_u32 rel_time; + if (now >= abs_time) { + rel_time = rel_time.zero(); + } else if (abs_time - now > Kernel::wait_for_u32_max) { + rel_time = Kernel::wait_for_u32_max; + } else { + rel_time = abs_time - now; + } + return try_alloc_for(rel_time); + } + + /** Allocate a memory block from a memory pool, without blocking, and set memory block to zero. + @return address of the allocated memory block or nullptr in case of no memory available. + + @note You may call this function from ISR context. + @deprecated Replaced with try_calloc. In future calloc() will be an untimed blocking call. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_calloc. In future calloc() will be an untimed blocking call.") + T *calloc() + { + return try_calloc(); + } + + /** Allocate a memory block from a memory pool, without blocking, and set memory block to zero. + @return address of the allocated memory block or nullptr in case of no memory available. + + @note You may call this function from ISR context. + */ + T *try_calloc() + { + T *item = try_alloc(); + if (item != nullptr) { + memset(item, 0, sizeof(T)); + } + return item; + } + + /** Allocate a memory block from a memory pool, optionally blocking, and set memory block to zero. + @param millisec timeout value (osWaitForever to wait forever) + @return address of the allocated memory block or nullptr in case of no memory available. + + @note You may call this function from ISR context if the millisec parameter is set to 0. + @deprecated Replaced with `try_calloc_for`. For example use `try_calloc_for(5s)` rather than `calloc_for(5000)`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with `try_calloc_for`. For example use `try_calloc_for(5s)` rather than `calloc_for(5000)`.") + T *calloc_for(uint32_t millisec) + { + return try_calloc_for(std::chrono::duration(millisec)); + } + + /** Allocate a memory block from a memory pool, optionally blocking, and set memory block to zero. + @param rel_time timeout value (Kernel::wait_for_u32_forever to wait forever) + @return address of the allocated memory block or nullptr in case of no memory available. + + @note You may call this function from ISR context if the rel_time parameter is set to 0. + */ + T *try_calloc_for(Kernel::Clock::duration_u32 rel_time) + { + T *item = try_alloc_for(rel_time); + if (item != nullptr) { + memset(item, 0, sizeof(T)); + } + return item; + } + + /** Allocate a memory block from a memory pool, blocking, and set memory block to zero. + @param millisec absolute timeout time, referenced to Kernel::get_ms_count(). + @return address of the allocated memory block or nullptr in case of no memory available. + + @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. + @deprecated Replaced with `try_calloc_until`. For example use `try_calloc_until(Kernel::Clock::now() + 5s)` + rather than `calloc_until(Kernel::get_ms_count() + 5000)`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with `try_calloc_until`. For example use `try_calloc_until(Kernel::Clock::now() + 5s)` rather than `calloc_until(Kernel::get_ms_count() + 5000)`.") + T *calloc_until(uint64_t millisec) + { + return try_calloc_until(Kernel::Clock::time_point(std::chrono::duration(millisec))); + } + + /** Allocate a memory block from a memory pool, blocking, and set memory block to zero. + @param abs_time absolute timeout time, referenced to Kernel::Clock. + @return address of the allocated memory block or nullptr in case of no memory available. + + @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. + */ + T *try_calloc_until(Kernel::Clock::time_point abs_time) + { + T *item = try_alloc_until(abs_time); + if (item != nullptr) { + memset(item, 0, sizeof(T)); + } + return item; + } + + /** Free a memory block. + @param block address of the allocated memory block to be freed. + @return osOK on successful deallocation, osErrorParameter if given memory block id + is nullptr or invalid, or osErrorResource if given memory block is in an + invalid memory pool state. + + @note You may call this function from ISR context. + */ + osStatus free(T *block) + { + return osMemoryPoolFree(_id, block); + } + +private: + osMemoryPoolId_t _id; + char _pool_mem[MBED_RTOS_STORAGE_MEM_POOL_MEM_SIZE(pool_sz, sizeof(T))]; + mbed_rtos_storage_mem_pool_t _obj_mem; +}; +/** @}*/ +/** @}*/ +} +#endif +#endif diff --git a/rtos/Mutex.h b/rtos/Mutex.h new file mode 100644 index 0000000000..49963302c0 --- /dev/null +++ b/rtos/Mutex.h @@ -0,0 +1,234 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * SPDX-License-Identifier: MIT + * + * 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 MUTEX_H +#define MUTEX_H + +#include +#include "rtos/mbed_rtos_types.h" +#include "rtos/mbed_rtos1_types.h" +#include "rtos/mbed_rtos_storage.h" +#include "rtos/Kernel.h" + +#include "platform/NonCopyable.h" +#include "platform/ScopedLock.h" +#include "platform/mbed_toolchain.h" + +namespace rtos { +/** \addtogroup rtos-public-api */ +/** @{*/ + +class Mutex; +/** Typedef for the mutex lock + * + * Usage: + * @code + * void foo(Mutex &m) { + * ScopedMutexLock lock(m); + * // Mutex lock protects code in this block + * } + * @endcode + */ +typedef mbed::ScopedLock ScopedMutexLock; + +/** + * \defgroup rtos_Mutex Mutex class + * @{ + */ + +/** The Mutex class is used to synchronize the execution of threads. + This is, for example, used to protect access to a shared resource. + + In bare-metal builds, the Mutex class is a dummy, so lock() and unlock() are no-ops. + + @note You cannot use member functions of this class in ISR context. If you require Mutex functionality within + ISR handler, consider using @a Semaphore. + + @note + Memory considerations: The mutex control structures are created on the current thread's stack, both for the Mbed OS + and underlying RTOS objects (static or dynamic RTOS memory pools are not being used). +*/ +class Mutex : private mbed::NonCopyable { +public: + /** Create and Initialize a Mutex object + * + * @note You cannot call this function from ISR context. + */ + Mutex(); + + /** Create and Initialize a Mutex object + + @param name name to be used for this mutex. It has to stay allocated for the lifetime of the thread. + @note You cannot call this function from ISR context. + */ + Mutex(const char *name); + + /** + Wait until a Mutex becomes available. + + @note You cannot call this function from ISR context. + */ + void lock(); + + /** Try to lock the mutex, and return immediately + @return true if the mutex was acquired, false otherwise. + @note equivalent to trylock_for(0) + + @note You cannot call this function from ISR context. + */ + bool trylock(); + + /** Try to lock the mutex for a specified time + @param millisec timeout value. + @return true if the mutex was acquired, false otherwise. + @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 lock attempt will time out earlier than specified. + + @note You cannot call this function from ISR context. + @deprecated Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.") + bool trylock_for(uint32_t millisec); + + /** Try to lock the mutex for a specified time + @param rel_time timeout value. + @return true if the mutex was acquired, false otherwise. + @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 lock attempt will time out earlier than specified. + + @note You cannot call this function from ISR context. + */ + bool trylock_for(Kernel::Clock::duration_u32 rel_time); + + /** Try to lock the mutex until specified time + @param millisec absolute timeout time, referenced to Kernel::get_ms_count() + @return true if the mutex was acquired, false otherwise. + @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 lock attempt will time out earlier than specified. + + @note You cannot call this function from ISR context. + @deprecated Pass a chrono time_point, not an integer millisecond count. For example use + `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.") + bool trylock_until(uint64_t millisec); + + /** Try to lock the mutex until specified time + @param abs_time absolute timeout time, referenced to Kernel::get_ms_count() + @return true if the mutex was acquired, false otherwise. + @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 lock attempt will time out earlier than specified. + + @note You cannot call this function from ISR context. + */ + bool trylock_until(Kernel::Clock::time_point abs_time); + + /** + Unlock the mutex that has previously been locked by the same thread + + @note You cannot call this function from ISR context. + */ + void unlock(); + + /** Get the owner the this mutex + @return the current owner of this mutex. + + @note You cannot call this function from ISR context. + */ + osThreadId_t get_owner(); + + /** Mutex destructor + * + * @note You cannot call this function from ISR context. + */ + ~Mutex(); + +private: +#if MBED_CONF_RTOS_PRESENT + void constructor(const char *name = nullptr); + friend class ConditionVariable; + + osMutexId_t _id; + mbed_rtos_storage_mutex_t _obj_mem; + uint32_t _count; +#endif +}; + +#if !MBED_CONF_RTOS_PRESENT +inline Mutex::Mutex() +{ +} + +inline Mutex::Mutex(const char *) +{ +} + +inline Mutex::~Mutex() +{ +} + +inline void Mutex::lock() +{ +} + +inline bool Mutex::trylock() +{ + return true; +} + +inline bool Mutex::trylock_for(uint32_t) +{ + return true; +} + +inline bool Mutex::trylock_for(Kernel::Clock::duration_u32) +{ + return true; +} + +inline bool Mutex::trylock_until(uint64_t) +{ + return true; +} + +inline bool Mutex::trylock_until(Kernel::Clock::time_point) +{ + return true; +} + +inline void Mutex::unlock() +{ +} +#endif + +/** @}*/ +/** @}*/ +} +#endif diff --git a/rtos/Queue.h b/rtos/Queue.h new file mode 100644 index 0000000000..203d122727 --- /dev/null +++ b/rtos/Queue.h @@ -0,0 +1,348 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * SPDX-License-Identifier: MIT + * + * 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 QUEUE_H +#define QUEUE_H + +#include "rtos/mbed_rtos_types.h" +#include "rtos/mbed_rtos1_types.h" +#include "rtos/mbed_rtos_storage.h" +#include "rtos/Kernel.h" +#include "platform/mbed_error.h" +#include "platform/NonCopyable.h" + +#if MBED_CONF_RTOS_PRESENT || defined(DOXYGEN_ONLY) + +namespace rtos { +/** \addtogroup rtos-public-api */ +/** @{*/ + +/** + * \defgroup rtos_Queue Queue class + * @{ + */ + +/** The Queue class represents a collection of objects that are stored first by + * order of priority, and then in first-in, first-out (FIFO) order. + * + * You can use a queue when you need to store data and then access it in the same + * order that it has been stored. The order in which you retrieve the data is in + * order of descending priority. If multiple elements have the same priority, + * they are retrieved in FIFO order. + * + * The object type stored in the queue can be an integer, pointer or a generic + * type given by the template parameter T. + * + * @tparam T Specifies the type of elements stored in the queue. + * @tparam queue_sz Maximum number of messages that you can store in the queue. + * + * @note Memory considerations: The queue control structures are created on the + * current thread's stack, both for the Mbed OS and underlying RTOS + * objects (static or dynamic RTOS memory pools are not being used). + * + * @note Bare metal profile: This class is not supported. + */ +template +class Queue : private mbed::NonCopyable > { +public: + /** Create and initialize a message Queue of objects of the parameterized + * type `T` and maximum capacity specified by `queue_sz`. + * + * @note You cannot call this function from ISR context. + */ + Queue() + { + osMessageQueueAttr_t attr = { 0 }; + attr.mq_mem = _queue_mem; + attr.mq_size = sizeof(_queue_mem); + attr.cb_mem = &_obj_mem; + attr.cb_size = sizeof(_obj_mem); + _id = osMessageQueueNew(queue_sz, sizeof(T *), &attr); + MBED_ASSERT(_id); + } + + /** Queue destructor + * + * @note You cannot call this function from ISR context. + */ + ~Queue() + { + osMessageQueueDelete(_id); + } + + /** Check if the queue is empty. + * + * @return True if the queue is empty, false if not + * + * @note You may call this function from ISR context. + */ + bool empty() const + { + return osMessageQueueGetCount(_id) == 0; + } + + /** Check if the queue is full. + * + * @return True if the queue is full, false if not + * + * @note You may call this function from ISR context. + */ + bool full() const + { + return osMessageQueueGetSpace(_id) == 0; + } + + /** Get number of queued messages in the queue. + * + * @return Number of items in the queue + * + * @note You may call this function from ISR context. + */ + uint32_t count() const + { + return osMessageQueueGetCount(_id); + } + + /** Inserts the given element to the end of the queue. + * + * This function puts the message pointed to by `data` into the queue. The + * parameter `prio` is used to sort the message according to their priority + * (higher numbers indicate higher priority) on insertion. + * + * The function does not block, and returns immediately if the queue is full. + * + * @param data Pointer to the element to insert into the queue. + * @param prio Priority of the operation or 0 in case of default. + * (default: 0) + * + * @return true if the element was inserted, false otherwise. + * + * @note You may call this function from ISR context. + */ + bool try_put(T *data, uint8_t prio = 0) + { + return try_put_for(Kernel::Clock::duration_u32::zero(), data, prio); + } + + /** Inserts the given element to the end of the queue. + * + * This function puts the message pointed to by `data` into the queue. The + * parameter `prio` is used to sort the message according to their priority + * (higher numbers indicate higher priority) on insertion. + * + * The timeout indicated by the parameter `rel_time` specifies how long the + * function blocks waiting for the message to be inserted into the + * queue. + * + * The parameter `rel_time` can have the following values: + * - When the duration is 0, the function returns instantly. You could use + * `try_put` instead. + * - When the duration is Kernel::wait_for_u32_forever, the function waits for an + * infinite time. + * - For all other values, the function waits for the given duration. + * + * @param rel_time Timeout for the operation to be executed. + * @param data Pointer to the element to insert into the queue. + * @param prio Priority of the operation or 0 in case of default. + * (default: 0) + * + * @return true if the element was inserted, false otherwise. + * + * @note You may call this function from ISR context if the rel_time + * parameter is set to 0. + * + */ + bool try_put_for(Kernel::Clock::duration_u32 rel_time, T *data, uint8_t prio = 0) + { + osStatus status = osMessageQueuePut(_id, &data, prio, rel_time.count()); + return status == osOK; + } + + /** Inserts the given element to the end of the queue. + * + * This function puts the message pointed to by `data` into the queue. The + * parameter `prio` is used to sort the message according to their priority + * (higher numbers indicate higher priority) on insertion. + * + * The timeout indicated by the parameter `millisec` specifies how long the + * function blocks waiting for the message to be inserted into the + * queue. + * + * The parameter `millisec` can have the following values: + * - When the timeout is 0, the function returns instantly. + * - When the timeout is osWaitForever, the function waits for an + * infinite time. + * - For all other values, the function waits for the given number of + * milliseconds. + * + * @param data Pointer to the element to insert into the queue. + * @param millisec Timeout for the operation to be executed, or 0 in case + * of no timeout. + * @param prio Priority of the operation or 0 in case of default. + * (default: 0) + * + * @return Status code that indicates the execution status of the function: + * @a osOK The message has been successfully inserted + * into the queue. + * @a osErrorTimeout The message could not be inserted into the + * queue in the given time. + * @a osErrorResource The message could not be inserted because + * the queue is full. + * @a osErrorParameter Internal error or nonzero timeout specified + * in an ISR. + * + * @note You may call this function from ISR context if the millisec + * parameter is set to 0. + * @deprecated Replaced with try_put and try_put_for. In future put will be an untimed blocking call. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_put and try_put_for. In future put will be an untimed blocking call.") + osStatus put(T *data, uint32_t millisec = 0, uint8_t prio = 0) + { + return osMessageQueuePut(_id, &data, prio, millisec); + } + + /** Get a message from the queue. + * + * This function retrieves a message from the queue. The message is stored + * in the location pointed to be the parameter `data_out`. + * + * The function does not block, and returns immediately if the queue is empty. + * + * @param[out] data_out Pointer to location to write the element retrieved from the queue. + * + * @return true if an element was received and written to data_out. + * + * @note You may call this function from ISR context. + */ + bool try_get(T **data_out) + { + return try_get_for(Kernel::Clock::duration_u32::zero(), data_out); + } + + /** Get a message or wait for a message from the queue. + * + * This function retrieves a message from the queue. The message is stored + * in the location pointed to be the parameter `data_out`. + * + * The timeout specified by the parameter `rel_time` specifies how long the + * function waits to retrieve the message from the queue. + * + * The timeout parameter can have the following values: + * - When the timeout is 0, the function returns instantly. + * - When the timeout is Kernel::wait_for_u32_forever, the function waits + * infinite time until the message is retrieved. + * - When the timeout is any other value, the function waits for the + * specified time before returning a timeout error. + * + * Messages are retrieved in descending priority order. If two messages + * share the same priority level, they are retrieved in first-in, first-out + * (FIFO) order. + * + * @param rel_time Timeout value. + * @param[out] data_out Pointer to location to write the element retrieved from the queue. + * + * @return true if an element was received and written to data_out. + * + * @note You may call this function from ISR context if the rel_time + * parameter is set to 0. + */ + bool try_get_for(Kernel::Clock::duration_u32 rel_time, T **data_out) + { + osStatus status = osMessageQueueGet(_id, data_out, nullptr, rel_time.count()); + return status == osOK; + } + + /** Get a message or wait for a message from the queue. + * + * This function retrieves a message from the queue. The message is stored + * in the value field of the returned `osEvent` object. + * + * The timeout specified by the parameter `millisec` specifies how long the + * function waits to retrieve the message from the queue. + * + * The timeout parameter can have the following values: + * - When the timeout is 0, the function returns instantly. + * - When the timeout is osWaitForever (default), the function waits + * infinite time until the message is retrieved. + * - When the timeout is any other value, the function waits for the + * specified time before returning a timeout error. + * + * Messages are retrieved in descending priority order. If two messages + * share the same priority level, they are retrieved in first-in, first-out + * (FIFO) order. + * + * @param millisec Timeout value. + * + * @return Event information that includes the message in event. Message + * value and the status code in event.status: + * @a osEventMessage Message successfully received. + * @a osOK No message is available in the queue, and no + * timeout was specified. + * @a osEventTimeout No message was received before a timeout + * event occurred. + * @a osErrorParameter A parameter is invalid or outside of a + * permitted range. + * + * @note You may call this function from ISR context if the millisec + * parameter is set to 0. + * @deprecated Replaced with try_get and try_get_for. In future get will be an untimed blocking call. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Replaced with try_get and try_get_for. In future get will be an untimed blocking call.") + osEvent get(uint32_t millisec = osWaitForever) + { + osEvent event; + T *data = nullptr; + osStatus_t res = osMessageQueueGet(_id, &data, nullptr, millisec); + + switch (res) { + case osOK: + event.status = (osStatus)osEventMessage; + event.value.p = data; + break; + case osErrorResource: + event.status = osOK; + break; + case osErrorTimeout: + event.status = (osStatus)osEventTimeout; + break; + case osErrorParameter: + default: + event.status = osErrorParameter; + break; + } + event.def.message_id = _id; + + return event; + } +private: + osMessageQueueId_t _id; + char _queue_mem[queue_sz * (sizeof(T *) + sizeof(mbed_rtos_storage_message_t))]; + mbed_rtos_storage_msg_queue_t _obj_mem; +}; +/** @}*/ +/** @}*/ + +} // namespace rtos + +#endif + +#endif // QUEUE_H diff --git a/rtos/Semaphore.h b/rtos/Semaphore.h new file mode 100644 index 0000000000..c97f5689b6 --- /dev/null +++ b/rtos/Semaphore.h @@ -0,0 +1,159 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * SPDX-License-Identifier: MIT + * + * 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 SEMAPHORE_H +#define SEMAPHORE_H + +#include +#include +#include "rtos/mbed_rtos_types.h" +#include "rtos/mbed_rtos1_types.h" +#include "rtos/mbed_rtos_storage.h" +#include "rtos/Kernel.h" +#include "platform/mbed_toolchain.h" +#include "platform/NonCopyable.h" + +namespace rtos { +/** \addtogroup rtos-public-api */ +/** @{*/ + +/** + * \defgroup rtos_Semaphore Semaphore class + * @{ + */ + +/** The Semaphore class is used to manage and protect access to a set of shared resources. + * + * @note + * Memory considerations: The semaphore control structures will be created on current thread's stack, both for the mbed OS + * and underlying RTOS objects (static or dynamic RTOS memory pools are not being used). + */ +class Semaphore : private mbed::NonCopyable { +public: + /** Create and Initialize a Semaphore object used for managing resources. + @param count number of available resources; maximum index value is (count-1). (default: 0). + + @note You cannot call this function from ISR context. + */ + Semaphore(int32_t count = 0); + + /** Create and Initialize a Semaphore object used for managing resources. + @param count number of available resources + @param max_count maximum number of available resources + + @note You cannot call this function from ISR context. + */ + Semaphore(int32_t count, uint16_t max_count); + + /** Wait until a Semaphore resource becomes available. + + @note You cannot call this function from ISR context. + */ + void acquire(); + + /** Try to acquire a Semaphore resource, and return immediately + @return true if a resource was acquired, false otherwise. + @note equivalent to try_acquire_for(0) + + @note You may call this function from ISR context. + */ + bool try_acquire(); + + /** Wait until a Semaphore resource becomes available. + @param millisec timeout value. + @return true if a resource was acquired, false otherwise. + + @note You may call this function from ISR context if the millisec parameter is set to 0. + @deprecated Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.") + bool try_acquire_for(uint32_t millisec); + + /** Wait until a Semaphore resource becomes available. + @param rel_time timeout value. + @return true if a resource was acquired, false otherwise. + + @note You may call this function from ISR context if the rel_time parameter is set to 0. + */ + bool try_acquire_for(Kernel::Clock::duration_u32 rel_time); + + /** Wait until a Semaphore resource becomes available. + @param millisec absolute timeout time, referenced to Kernel::get_ms_count() + @return true if a resource was acquired, false otherwise. + @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 acquire attempt will time out earlier than specified. + + @note You cannot call this function from ISR context. + @deprecated Pass a chrono time_point, not an integer millisecond count. For example use + `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`. + */ + MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.") + bool try_acquire_until(uint64_t millisec); + + /** Wait until a Semaphore resource becomes available. + @param millisec absolute timeout time, referenced to Kernel::get_ms_count() + @return true if a resource was acquired, false otherwise. + @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 acquire attempt will time out earlier than specified. + + @note You cannot call this function from ISR context. + */ + bool try_acquire_until(Kernel::Clock::time_point abs_time); + + /** Release a Semaphore resource that was obtain with Semaphore::acquire. + @return status code that indicates the execution status of the function: + @a osOK the token has been correctly released. + @a osErrorResource the maximum token count has been reached. + @a osErrorParameter internal error. + + @note You may call this function from ISR context. + */ + osStatus release(void); + + /** Semaphore destructor + * + * @note You cannot call this function from ISR context. + */ + ~Semaphore(); + +private: + void constructor(int32_t count, uint16_t max_count); + +#if MBED_CONF_RTOS_PRESENT + int32_t _wait(uint32_t millisec); + + osSemaphoreId_t _id; + mbed_rtos_storage_semaphore_t _obj_mem; +#else + static bool semaphore_available(void *); + int32_t _count; + uint16_t _max_count; +#endif +}; +/** @}*/ +/** @}*/ +} +#endif diff --git a/rtos/ThisThread.h b/rtos/ThisThread.h new file mode 100644 index 0000000000..76c1387b0b --- /dev/null +++ b/rtos/ThisThread.h @@ -0,0 +1,290 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * SPDX-License-Identifier: MIT + * + * 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 +#include "platform/mbed_toolchain.h" +#include "rtos/Kernel.h" +#include "rtos/mbed_rtos_types.h" + +namespace rtos { +/** \addtogroup rtos-public-api */ +/** @{*/ + +/** + * \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. + @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 + @deprecated Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`. +*/ +MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.") +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 rel_time timeout value. + @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, Kernel::Clock::duration_u32 rel_time, 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 + @deprecated Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` + rather than `Kernel::get_ms_count() + 5000`. +*/ +MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.") +uint32_t flags_wait_all_until(uint32_t flags, uint64_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 abs_time absolute timeout time, referenced to Kernel::Clock + @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, Kernel::Clock::time_point abs_time, 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. + @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 + @deprecated Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`. +*/ +MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.") +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 rel_time timeout value. + @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, Kernel::Clock::duration_u32 rel_time, 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 + @deprecated Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` + rather than `Kernel::get_ms_count() + 5000`. +*/ +MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.") +uint32_t flags_wait_any_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 abs_time absolute timeout time, referenced to Kernel::Clock + @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, Kernel::Clock::time_point abs_time, 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. + @note The equivalent functionality is accessible in C via thread_sleep_for. + @deprecated Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`. +*/ +MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono duration, not an integer millisecond count. For example use `5s` rather than `5000`.") +void sleep_for(uint32_t millisec); + +/** Sleep for a specified time period: + @param rel_time time delay value + @note You cannot call this function from ISR context. + @note The equivalent functionality is accessible in C via thread_sleep_for. +*/ +void sleep_for(Kernel::Clock::duration_u32 rel_time); + + +/** 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. + @note The equivalent functionality is accessible in C via thread_sleep_until. + @deprecated Pass a chrono time_point, not an integer millisecond count. For example use + `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`. +*/ +MBED_DEPRECATED_SINCE("mbed-os-6.0.0", "Pass a chrono time_point, not an integer millisecond count. For example use `Kernel::Clock::now() + 5s` rather than `Kernel::get_ms_count() + 5000`.") +void sleep_until(uint64_t millisec); + +/** Sleep until a specified time in millisec + The specified time is according to Kernel::Clock. + @param abs_time absolute time + @note You cannot call this function from ISR context. + @note if abs_time is equal to or lower than Kernel::Clock::now(), this + returns immediately. + @note The equivalent functionality is accessible in C via thread_sleep_until. +*/ +void sleep_until(Kernel::Clock::time_point abs_time); + +/** 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 nullptr in case of error or in ISR context. + @note You may call this function from ISR context. +*/ +osThreadId_t get_id(); + +/** Get the thread name of the current running thread. + @return thread name pointer or nullptr if thread has no name or in case of error. + @note You cannot call this function from ISR context. +*/ +const char *get_name(); + +}; +/** @}*/ +/** @}*/ + + +namespace internal { +/** \addtogroup rtos-internal-api */ +/** @{*/ + +struct flags_check_capture { + uint32_t *flags; + uint32_t options; + uint32_t flags_wanted; + uint32_t result; + bool match; +}; + +bool non_rtos_check_flags(void *handle); + +} +/** @}*/ +} +#endif diff --git a/rtos/Thread.h b/rtos/Thread.h new file mode 100644 index 0000000000..576bb9ca74 --- /dev/null +++ b/rtos/Thread.h @@ -0,0 +1,284 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * SPDX-License-Identifier: MIT + * + * 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 THREAD_H +#define THREAD_H + +#include +#include "rtos/mbed_rtos_types.h" +#include "rtos/mbed_rtos1_types.h" +#include "rtos/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" + +#if MBED_CONF_RTOS_PRESENT || defined(DOXYGEN_ONLY) || defined(UNITTEST) + +namespace rtos { +/** \addtogroup rtos-public-api */ +/** @{*/ + +/** + * \defgroup rtos_Thread Thread class + * @{ + */ + +/** The Thread class allow defining, creating, and controlling thread functions in the system. + * + * Example: + * @code + * #include "mbed.h" + * #include "rtos.h" + * + * Thread thread; + * DigitalOut led1(LED1); + * volatile bool running = true; + * + * // Blink function toggles the led in a long running loop + * void blink(DigitalOut *led) { + * while (running) { + * *led = !*led; + * ThisThread::sleep_for(1000); + * } + * } + * + * // Spawns a thread to run blink for 5 seconds + * int main() { + * thread.start(callback(blink, &led1)); + * ThisThread::sleep_for(5000); + * running = false; + * thread.join(); + * } + * @endcode + * + * @note + * Memory considerations: The thread control structures will be created on current thread's stack, both for the mbed OS + * and underlying RTOS objects (static or dynamic RTOS memory pools are not being used). + * Additionally the stack memory for this thread will be allocated on the heap, if it wasn't supplied to the constructor. + * + * @note + * MBED_TZ_DEFAULT_ACCESS (default:0) flag can be used to change the default access of all user threads in non-secure mode. + * MBED_TZ_DEFAULT_ACCESS set to 1, means all non-secure user threads have access to call secure functions. + * MBED_TZ_DEFAULT_ACCESS set to 0, means none of the non-secure user thread have access to call secure functions, + * to give access to particular thread used overloaded constructor with `tz_module` as argument during thread creation. + * + * MBED_TZ_DEFAULT_ACCESS is target specific define, should be set in targets.json file for Cortex-M23/M33 devices. + * + * @note + * Bare metal profile: This class is not supported. + */ + +class Thread : private mbed::NonCopyable { +public: + /** Allocate a new thread without starting execution + @param priority initial priority of the thread function. (default: osPriorityNormal). + @param stack_size stack size (in bytes) requirements for the thread function. (default: OS_STACK_SIZE). + @param stack_mem pointer to the stack area to be used by this thread (default: nullptr). + @param name name to be used for this thread. It has to stay allocated for the lifetime of the thread (default: nullptr) + + @note Default value of tz_module will be MBED_TZ_DEFAULT_ACCESS + @note You cannot call this function from ISR context. + */ + + Thread(osPriority priority = osPriorityNormal, + uint32_t stack_size = OS_STACK_SIZE, + unsigned char *stack_mem = nullptr, const char *name = nullptr) + { + constructor(priority, stack_size, stack_mem, name); + } + + /** Allocate a new thread without starting execution + @param tz_module trustzone thread identifier (osThreadAttr_t::tz_module) + Context of RTOS threads in non-secure state must be saved when calling secure functions. + tz_module ID is used to allocate context memory for threads, and it can be safely set to zero for + threads not using secure calls at all. See "TrustZone RTOS Context Management" for more details. + @param priority initial priority of the thread function. (default: osPriorityNormal). + @param stack_size stack size (in bytes) requirements for the thread function. (default: OS_STACK_SIZE). + @param stack_mem pointer to the stack area to be used by this thread (default: nullptr). + @param name name to be used for this thread. It has to stay allocated for the lifetime of the thread (default: nullptr) + + @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 = nullptr, const char *name = nullptr) + { + constructor(tz_module, priority, stack_size, stack_mem, name); + } + + + /** Starts a thread executing the specified function. + @param task function to be executed by this thread. + @return status code that indicates the execution status of the function. + @note a thread can only be started once + + @note You cannot call this function ISR context. + */ + osStatus start(mbed::Callback task); + + /** Wait for thread to terminate + @return status code that indicates the execution status of the function. + + @note You cannot call this function from ISR context. + */ + osStatus join(); + + /** Terminate execution of a thread and remove it from Active Threads + @return status code that indicates the execution status of the function. + + @note You cannot call this function from ISR context. + */ + osStatus terminate(); + + /** Set priority of an active thread + @param priority new priority value for the thread function. + @return status code that indicates the execution status of the function. + + @note You cannot call this function from ISR context. + */ + osStatus set_priority(osPriority priority); + + /** Get priority of an active thread + @return current priority value of the thread function. + + @note You cannot call this function from ISR context. + */ + 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); + + /** State of the Thread */ + enum State { + Inactive, /**< NOT USED */ + Ready, /**< Ready to run */ + Running, /**< Running */ + WaitingDelay, /**< Waiting for a delay to occur */ + WaitingJoin, /**< Waiting for thread to join. Only happens when using RTX directly. */ + WaitingThreadFlag, /**< Waiting for a thread flag to be set */ + WaitingEventFlag, /**< Waiting for a event flag to be set */ + WaitingMutex, /**< Waiting for a mutex event to occur */ + WaitingSemaphore, /**< Waiting for a semaphore event to occur */ + WaitingMemoryPool, /**< Waiting for a memory pool */ + WaitingMessageGet, /**< Waiting for message to arrive */ + WaitingMessagePut, /**< Waiting for message to be send */ + WaitingInterval, /**< NOT USED */ + WaitingOr, /**< NOT USED */ + WaitingAnd, /**< NOT USED */ + WaitingMailbox, /**< NOT USED (Mail is implemented as MemoryPool and Queue) */ + + /* Not in sync with RTX below here */ + Deleted, /**< The task has been deleted or not started */ + }; + + /** State of this Thread + @return the State of this Thread + + @note You cannot call this function from ISR context. + */ + 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() 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() 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() 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() const; + + /** Get thread name + @return thread name or nullptr if the name was not set. + + @note You may call this function from ISR context. + */ + 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; + + /** Thread destructor + * + * @note You cannot call this function from ISR context. + */ + virtual ~Thread(); + +private: + // Required to share definitions without + // delegated constructors + void constructor(osPriority priority = osPriorityNormal, + uint32_t stack_size = OS_STACK_SIZE, + unsigned char *stack_mem = nullptr, + const char *name = nullptr); + void constructor(uint32_t tz_module, + osPriority priority = osPriorityNormal, + uint32_t stack_size = OS_STACK_SIZE, + unsigned char *stack_mem = nullptr, + const char *name = nullptr); + static void _thunk(void *thread_ptr); + + mbed::Callback _task; + osThreadId_t _tid; + osThreadAttr_t _attr; + bool _dynamic_stack; + bool _finished; + Semaphore _join_sem; + mutable Mutex _mutex; + mbed_rtos_storage_thread_t _obj_mem; +}; +/** @}*/ +/** @}*/ +} +#endif + +#endif diff --git a/rtos/mbed_rtos1_types.h b/rtos/mbed_rtos1_types.h new file mode 100644 index 0000000000..e178b273c1 --- /dev/null +++ b/rtos/mbed_rtos1_types.h @@ -0,0 +1,30 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_RTOS_RTX1_TYPES_H +#define MBED_RTOS_RTX1_TYPES_H + +#if MBED_CONF_RTOS_PRESENT || defined(UNITTEST) + +#include "cmsis_os.h" + +#else + +typedef int32_t osStatus; + +#endif + +#endif diff --git a/rtos/mbed_rtos_storage.h b/rtos/mbed_rtos_storage.h new file mode 100644 index 0000000000..750725dc4e --- /dev/null +++ b/rtos/mbed_rtos_storage.h @@ -0,0 +1,26 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_RTOS_STORAGE_H +#define MBED_RTOS_STORAGE_H + +#if MBED_CONF_RTOS_PRESENT || defined(UNITTEST) + +#include "mbed_rtx_storage.h" + +#endif + +#endif diff --git a/rtos/mbed_rtos_types.h b/rtos/mbed_rtos_types.h new file mode 100644 index 0000000000..eaf5da0e3d --- /dev/null +++ b/rtos/mbed_rtos_types.h @@ -0,0 +1,80 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef RTOS_TYPES_H_ +#define RTOS_TYPES_H_ + +#if MBED_CONF_RTOS_PRESENT || defined(DOXYGEN_ONLY) || defined(UNITTEST) +#include "cmsis_os2.h" +#else + +#ifdef __cplusplus +extern "C" { +#endif + +/** \addtogroup rtos-public-api */ +/** @{*/ + +/* Minimal definitions for bare metal form of RTOS */ + +// Timeout value. +#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value. + +// Flags options (\ref osThreadFlagsWait and \ref osEventFlagsWait). +#define osFlagsWaitAny 0x00000000U ///< Wait for any flag (default). +#define osFlagsWaitAll 0x00000001U ///< Wait for all flags. +#define osFlagsNoClear 0x00000002U ///< Do not clear flags which have been specified to wait for. + +// Flags errors (returned by osThreadFlagsXxxx and osEventFlagsXxxx). +#define osFlagsError 0x80000000U ///< Error indicator. +#define osFlagsErrorUnknown 0xFFFFFFFFU ///< osError (-1). +#define osFlagsErrorTimeout 0xFFFFFFFEU ///< osErrorTimeout (-2). +#define osFlagsErrorResource 0xFFFFFFFDU ///< osErrorResource (-3). +#define osFlagsErrorParameter 0xFFFFFFFCU ///< osErrorParameter (-4). +#define osFlagsErrorISR 0xFFFFFFFAU ///< osErrorISR (-6). + +// Status code values returned by CMSIS-RTOS functions. +typedef enum { + osOK = 0, ///< Operation completed successfully. + osError = -1, ///< Unspecified RTOS error: run-time error but no other error message fits. + osErrorTimeout = -2, ///< Operation not completed within the timeout period. + osErrorResource = -3, ///< Resource not available. + osErrorParameter = -4, ///< Parameter error. + osErrorNoMemory = -5, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation. + osErrorISR = -6, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines. + osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization. +} osStatus_t; + + +// \details Thread ID identifies the thread. +typedef void *osThreadId_t; + +// Set the specified Thread Flags of a thread. +// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. +// \param[in] flags specifies the flags of the thread that shall be set. +// \return thread flags after setting or error code if highest bit set. +uint32_t osThreadFlagsSet(osThreadId_t thread_id, uint32_t flags); + +/** @}*/ + +#ifdef __cplusplus +} +#endif + +#endif + + +#endif /* RTOS_TYPES_H_ */ diff --git a/rtos/rtos.h b/rtos/rtos.h new file mode 100644 index 0000000000..1cb78197b7 --- /dev/null +++ b/rtos/rtos.h @@ -0,0 +1,48 @@ + +/* mbed Microcontroller Library + * Copyright (c) 2006-2012 ARM Limited + * SPDX-License-Identifier: MIT + * + * 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_H +#define RTOS_H + +#include "rtos/mbed_rtos_storage.h" +#include "rtos/Kernel.h" +#include "rtos/Thread.h" +#include "rtos/ThisThread.h" +#include "rtos/Mutex.h" +#include "rtos/Semaphore.h" +#include "rtos/Mail.h" +#include "rtos/MemoryPool.h" +#include "rtos/Queue.h" +#include "rtos/EventFlags.h" +#include "rtos/ConditionVariable.h" + + +/** \defgroup rtos-public-api RTOS + * \ingroup mbed-os-public + */ + +#ifndef MBED_NO_GLOBAL_USING_DIRECTIVE +using namespace rtos; +#endif + +#endif diff --git a/rtos/source/TARGET_CORTEX/CMakeLists.txt b/rtos/source/TARGET_CORTEX/CMakeLists.txt new file mode 100644 index 0000000000..1c29e0b28d --- /dev/null +++ b/rtos/source/TARGET_CORTEX/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (c) 2020 ARM Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +target_sources(mbed-os PRIVATE + mbed_boot.c + mbed_rtos_rtx.c + mbed_rtx_handlers.c + mbed_rtx_idle.cpp +) + +add_subdirectory(rtx5) + +if(${MBED_TOOLCHAIN} STREQUAL "GCC_ARM") + target_sources(mbed-os + PRIVATE + TOOLCHAIN_GCC_ARM/mbed_boot_gcc_arm.c + ) +elseif(${MBED_TOOLCHAIN} STREQUAL "ARM") + target_sources(mbed-os + PRIVATE + TOOLCHAIN_ARM_STD/mbed_boot_arm_std.c + ) +elseif(${MBED_TOOLCHAIN} STREQUAL "IAR") + target_sources(mbed-os + PRIVATE + TOOLCHAIN_IAR/mbed_boot_iar.c + ) +endif() + +target_include_directories(mbed-os + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + rtx4 +) diff --git a/rtos/source/TARGET_CORTEX/rtx5/CMakeLists.txt b/rtos/source/TARGET_CORTEX/rtx5/CMakeLists.txt new file mode 100644 index 0000000000..9cdf870b03 --- /dev/null +++ b/rtos/source/TARGET_CORTEX/rtx5/CMakeLists.txt @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: Apache-2.0 + +function(_mbed_get_rtx_assembly TOOLCHAIN_DIR) + get_property(target_labels GLOBAL PROPERTY MBED_TARGET_LABELS) + foreach(key ${target_labels}) + if(${key} STREQUAL CORTEX_A) + set(STARTUP_RTX_FILE TARGET_CORTEX_A/irq_ca.S) + elseif(${key} STREQUAL M0) + set(STARTUP_RTX_FILE TARGET_M0/irq_cm0.S) + elseif(${key} STREQUAL M0P) + set(STARTUP_RTX_FILE TARGET_M0P/irq_cm0.S) + elseif(${key} STREQUAL M23) + set(STARTUP_RTX_FILE TARGET_M23/irq_armv8mbl.S) + elseif(${key} STREQUAL M3) + set(STARTUP_RTX_FILE TARGET_M3/irq_cm3.S) + elseif(${key} STREQUAL M33) + set(STARTUP_RTX_FILE TARGET_M33/irq_armv8mbl.S) + elseif(${key} STREQUAL RTOS_M4_M7) + set(STARTUP_RTX_FILE TARGET_RTOS_M4_M7/irq_cm4f.S) + endif() + target_sources(mbed-os PRIVATE RTX/Source/${TOOLCHAIN_DIR}/${STARTUP_RTX_FILE}) + endforeach() +endfunction() + +function(_mbed_add_cortexa_handler_if) + get_property(target_labels GLOBAL PROPERTY MBED_TARGET_LABELS) + foreach(key ${target_labels}) + if(${key} STREQUAL CORTEX_A) + target_sources(mbed-os PRIVATE RTX/Config/TARGET_CORTEX_A/handlers.c) + endif() + endforeach() +endfunction() + +target_sources(mbed-os PRIVATE Include/cmsis_os2.h) +target_sources(mbed-os PRIVATE Include/os_tick.h) + +# Add Cortex A handlers if needed +_mbed_add_cortexa_handler_if() + +target_sources(mbed-os PRIVATE RTX/Config/RTX_Config.c) +target_sources(mbed-os PRIVATE RTX/Config/RTX_Config.h) +target_sources(mbed-os PRIVATE RTX/Include/rtx_evr.h) +target_sources(mbed-os PRIVATE RTX/Include/rtx_os.h) + +if(${MBED_TOOLCHAIN} STREQUAL "GCC_ARM") +_mbed_get_rtx_assembly(TOOLCHAIN_GCC) +elseif(${MBED_TOOLCHAIN} STREQUAL "ARM") +_mbed_get_rtx_assembly(TOOLCHAIN_ARM) +elseif(${MBED_TOOLCHAIN} STREQUAL "IAR") +_mbed_get_rtx_assembly(TOOLCHAIN_IAR) +endif() + +target_sources(mbed-os PRIVATE RTX/Source/rtx_core_ca.h) +target_sources(mbed-os PRIVATE RTX/Source/rtx_core_cm.h) +target_sources(mbed-os PRIVATE RTX/Source/rtx_delay.c) +target_sources(mbed-os PRIVATE RTX/Source/rtx_evflags.c) +target_sources(mbed-os PRIVATE RTX/Source/rtx_evr.c) +target_sources(mbed-os PRIVATE RTX/Source/rtx_kernel.c) +target_sources(mbed-os PRIVATE RTX/Source/rtx_lib.c) +target_sources(mbed-os PRIVATE RTX/Source/rtx_lib.h) +target_sources(mbed-os PRIVATE RTX/Source/rtx_memory.c) +target_sources(mbed-os PRIVATE RTX/Source/rtx_mempool.c) +target_sources(mbed-os PRIVATE RTX/Source/rtx_msgqueue.c) +target_sources(mbed-os PRIVATE RTX/Source/rtx_mutex.c) +target_sources(mbed-os PRIVATE RTX/Source/rtx_semaphore.c) +target_sources(mbed-os PRIVATE RTX/Source/rtx_system.c) +target_sources(mbed-os PRIVATE RTX/Source/rtx_thread.c) +target_sources(mbed-os PRIVATE RTX/Source/rtx_timer.c) + +target_sources(mbed-os PRIVATE Source/os_systick.c) +target_sources(mbed-os PRIVATE Source/os_tick_ptim.c) + +target_include_directories(mbed-os PUBLIC Include) +target_include_directories(mbed-os PUBLIC RTX/Include) +target_include_directories(mbed-os PUBLIC RTX/Source) +target_include_directories(mbed-os PUBLIC RTX/Config) diff --git a/rtos/source/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_ARM/CMakeLists.txt b/rtos/source/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_ARM/CMakeLists.txt new file mode 100644 index 0000000000..f403f3ac48 --- /dev/null +++ b/rtos/source/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_ARM/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2020 ARM Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +mbed_add_cmake_directory_if_labels("TARGET") diff --git a/rtos/source/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_GCC/CMakeLists.txt b/rtos/source/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_GCC/CMakeLists.txt new file mode 100644 index 0000000000..f403f3ac48 --- /dev/null +++ b/rtos/source/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_GCC/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2020 ARM Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +mbed_add_cmake_directory_if_labels("TARGET") diff --git a/rtos/source/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_IAR/CMakeLists.txt b/rtos/source/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_IAR/CMakeLists.txt new file mode 100644 index 0000000000..f403f3ac48 --- /dev/null +++ b/rtos/source/TARGET_CORTEX/rtx5/RTX/Source/TOOLCHAIN_IAR/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2020 ARM Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +mbed_add_cmake_directory_if_labels("TARGET")