|
|
|
@ -45,24 +45,39 @@
|
|
|
|
|
namespace riot { |
|
|
|
|
|
|
|
|
|
namespace { |
|
|
|
|
/**
|
|
|
|
|
* @brief Identify uninitialized threads. |
|
|
|
|
*/ |
|
|
|
|
constexpr kernel_pid_t thread_uninitialized = -1; |
|
|
|
|
/**
|
|
|
|
|
* @brief The stack size for new threads. |
|
|
|
|
*/ |
|
|
|
|
constexpr size_t stack_size = THREAD_STACKSIZE_MAIN; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Holds context data for the thread. |
|
|
|
|
*/ |
|
|
|
|
struct thread_data { |
|
|
|
|
thread_data() : ref_count{2}, joining_thread{thread_uninitialized} { |
|
|
|
|
// nop
|
|
|
|
|
} |
|
|
|
|
/** @cond INTERNAL */ |
|
|
|
|
std::atomic<unsigned> ref_count; |
|
|
|
|
kernel_pid_t joining_thread; |
|
|
|
|
char stack[stack_size]; |
|
|
|
|
/** @endcond */ |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This deleter prevents our thread data from being destroyed if the thread |
|
|
|
|
* object is destroyed before the thread had a chance to run |
|
|
|
|
* @brief This deleter prevents our thread data from being destroyed if the |
|
|
|
|
* thread object is destroyed before the thread had a chance to run. |
|
|
|
|
*/ |
|
|
|
|
struct thread_data_deleter { |
|
|
|
|
/**
|
|
|
|
|
* @brief Called by the deleter of a thread object to manage the lifetime of |
|
|
|
|
* the thread internal management data. |
|
|
|
|
*/ |
|
|
|
|
void operator()(thread_data* ptr) { |
|
|
|
|
if (--ptr->ref_count == 0) { |
|
|
|
|
delete ptr; |
|
|
|
@ -83,33 +98,60 @@ class thread_id {
|
|
|
|
|
thread_id id); |
|
|
|
|
friend class thread; |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
public: |
|
|
|
|
/**
|
|
|
|
|
* @brief Creates a uninitialized thread id. |
|
|
|
|
*/ |
|
|
|
|
inline thread_id() noexcept : m_handle{thread_uninitialized} {} |
|
|
|
|
/**
|
|
|
|
|
* @brief Create a thread id from a native handle. |
|
|
|
|
*/ |
|
|
|
|
inline thread_id(kernel_pid_t handle) : m_handle{handle} {} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Comparison operator for thread ids. |
|
|
|
|
*/ |
|
|
|
|
inline bool operator==(thread_id other) noexcept { |
|
|
|
|
return m_handle == other.m_handle; |
|
|
|
|
} |
|
|
|
|
/**
|
|
|
|
|
* @brief Comparison operator for thread ids. |
|
|
|
|
*/ |
|
|
|
|
inline bool operator!=(thread_id other) noexcept { |
|
|
|
|
return !(m_handle == other.m_handle); |
|
|
|
|
} |
|
|
|
|
/**
|
|
|
|
|
* @brief Comparison operator for thread ids. |
|
|
|
|
*/ |
|
|
|
|
inline bool operator<(thread_id other) noexcept { |
|
|
|
|
return m_handle < other.m_handle; |
|
|
|
|
} |
|
|
|
|
/**
|
|
|
|
|
* @brief Comparison operator for thread ids. |
|
|
|
|
*/ |
|
|
|
|
inline bool operator<=(thread_id other) noexcept { |
|
|
|
|
return !(m_handle > other.m_handle); |
|
|
|
|
} |
|
|
|
|
/**
|
|
|
|
|
* @brief Comparison operator for thread ids. |
|
|
|
|
*/ |
|
|
|
|
inline bool operator>(thread_id other) noexcept { |
|
|
|
|
return m_handle > other.m_handle; |
|
|
|
|
} |
|
|
|
|
/**
|
|
|
|
|
* @brief Comparison operator for thread ids. |
|
|
|
|
*/ |
|
|
|
|
inline bool operator>=(thread_id other) noexcept { |
|
|
|
|
return !(m_handle < other.m_handle); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
private: |
|
|
|
|
kernel_pid_t m_handle; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Enable printing of thread ids using output streams. |
|
|
|
|
*/ |
|
|
|
|
template <class T, class Traits> |
|
|
|
|
inline std::basic_ostream<T, Traits>& operator<<(std::basic_ostream |
|
|
|
|
<T, Traits>& out, |
|
|
|
@ -119,9 +161,23 @@ inline std::basic_ostream<T, Traits>& operator<<(std::basic_ostream
|
|
|
|
|
|
|
|
|
|
namespace this_thread { |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Access the id of the currently running thread. |
|
|
|
|
*/ |
|
|
|
|
inline thread_id get_id() noexcept { return thread_getpid(); } |
|
|
|
|
/**
|
|
|
|
|
* @brief Yield the currently running thread. |
|
|
|
|
*/ |
|
|
|
|
inline void yield() noexcept { thread_yield(); } |
|
|
|
|
/**
|
|
|
|
|
* @brief Puts the current thread to sleep. |
|
|
|
|
* @param[in] ns Duration to sleep in nanoseconds. |
|
|
|
|
*/ |
|
|
|
|
void sleep_for(const std::chrono::nanoseconds& ns); |
|
|
|
|
/**
|
|
|
|
|
* @brief Puts the current thread to sleep. |
|
|
|
|
* @param[in] sleep_duration The duration to sleep. |
|
|
|
|
*/ |
|
|
|
|
template <class Rep, class Period> |
|
|
|
|
void sleep_for(const std::chrono::duration<Rep, Period>& sleep_duration) { |
|
|
|
|
using namespace std::chrono; |
|
|
|
@ -139,6 +195,11 @@ void sleep_for(const std::chrono::duration<Rep, Period>& sleep_duration) {
|
|
|
|
|
sleep_for(ns); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
/**
|
|
|
|
|
* @brief Puts the current thread to sleep. |
|
|
|
|
* @param[in] sleep_time A point in time that specifies when the thread |
|
|
|
|
* should wake up. |
|
|
|
|
*/ |
|
|
|
|
inline void sleep_until(const riot::time_point& sleep_time) { |
|
|
|
|
mutex mtx; |
|
|
|
|
condition_variable cv; |
|
|
|
@ -149,7 +210,7 @@ inline void sleep_until(const riot::time_point& sleep_time) {
|
|
|
|
|
} |
|
|
|
|
} // namespace this_thread
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
/**
|
|
|
|
|
* @brief C++11 compliant implementation of thread, however uses the time |
|
|
|
|
* point from out chrono header instead of the specified one |
|
|
|
|
* @see <a href="http://en.cppreference.com/w/cpp/thread/thread"> |
|
|
|
@ -157,44 +218,100 @@ inline void sleep_until(const riot::time_point& sleep_time) {
|
|
|
|
|
* </a> |
|
|
|
|
*/ |
|
|
|
|
class thread { |
|
|
|
|
public: |
|
|
|
|
public: |
|
|
|
|
/**
|
|
|
|
|
* @brief The id is of type `thread_id`- |
|
|
|
|
*/ |
|
|
|
|
using id = thread_id; |
|
|
|
|
/**
|
|
|
|
|
* @brief The native handle type is the `kernel_pid_t` of RIOT. |
|
|
|
|
*/ |
|
|
|
|
using native_handle_type = kernel_pid_t; |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Per default, an uninitialized thread is created. |
|
|
|
|
*/ |
|
|
|
|
inline thread() noexcept : m_handle{thread_uninitialized} {} |
|
|
|
|
/**
|
|
|
|
|
* @brief Create a thread from a functor and arguments for it. |
|
|
|
|
* @param[in] f Functor to run as a thread. |
|
|
|
|
* @param[in] args Arguments passed to the functor. |
|
|
|
|
*/ |
|
|
|
|
template <class F, class... Args> |
|
|
|
|
explicit thread(F&& f, Args&&... args); |
|
|
|
|
~thread(); |
|
|
|
|
|
|
|
|
|
thread(const thread&) = delete; |
|
|
|
|
/**
|
|
|
|
|
* @brief Move constructor. |
|
|
|
|
*/ |
|
|
|
|
inline thread(thread&& t) noexcept : m_handle{t.m_handle} { |
|
|
|
|
t.m_handle = thread_uninitialized; |
|
|
|
|
std::swap(m_data, t.m_data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
~thread(); |
|
|
|
|
|
|
|
|
|
thread& operator=(const thread&) = delete; |
|
|
|
|
/**
|
|
|
|
|
* @brief Move assignment operator. |
|
|
|
|
*/ |
|
|
|
|
thread& operator=(thread&&) noexcept; |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Swap threads. |
|
|
|
|
* @param[inout] t Thread to swap data with. |
|
|
|
|
*/ |
|
|
|
|
void swap(thread& t) noexcept { |
|
|
|
|
std::swap(m_data, t.m_data); |
|
|
|
|
std::swap(m_handle, t.m_handle); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Query if the thread is joinable. |
|
|
|
|
* @return `true` if the thread is joinable, `false` otherwise. |
|
|
|
|
*/ |
|
|
|
|
inline bool joinable() const noexcept { |
|
|
|
|
return m_handle != thread_uninitialized; |
|
|
|
|
} |
|
|
|
|
/**
|
|
|
|
|
* @brief Block until the thread finishes. Leads to an error if the thread is |
|
|
|
|
* not joinable or a thread joins itself. |
|
|
|
|
*/ |
|
|
|
|
void join(); |
|
|
|
|
/**
|
|
|
|
|
* @brief Detaches a thread from its handle and allows it to execute |
|
|
|
|
* independently. The thread cleans up its resources when it |
|
|
|
|
* finishes. |
|
|
|
|
*/ |
|
|
|
|
void detach(); |
|
|
|
|
/**
|
|
|
|
|
* @brief Returns the id of a thread. |
|
|
|
|
*/ |
|
|
|
|
inline id get_id() const noexcept { return m_handle; } |
|
|
|
|
/**
|
|
|
|
|
* @brief Returns the native handle to a thread. |
|
|
|
|
*/ |
|
|
|
|
inline native_handle_type native_handle() noexcept { return m_handle; } |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Returns the number of concurrent threads supported by the |
|
|
|
|
* underlying hardware. Since there is no RIOT API to query this |
|
|
|
|
* information, the function always returns 1; |
|
|
|
|
*/ |
|
|
|
|
static unsigned hardware_concurrency() noexcept; |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
kernel_pid_t m_handle; |
|
|
|
|
std::unique_ptr<thread_data, thread_data_deleter> m_data; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Swaps two threads. |
|
|
|
|
* @param[inout] lhs Reference to one thread. |
|
|
|
|
* @param[inout] rhs Reference to the other thread. |
|
|
|
|
*/ |
|
|
|
|
void swap(thread& lhs, thread& rhs) noexcept; |
|
|
|
|
|
|
|
|
|
/** @cond INTERNAL */ |
|
|
|
|
template <class Tuple> |
|
|
|
|
void* thread_proxy(void* vp) { |
|
|
|
|
{ // without this scope, the objects here are not cleaned up corrctly
|
|
|
|
@ -217,6 +334,7 @@ void* thread_proxy(void* vp) {
|
|
|
|
|
sched_task_exit(); |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
/** @endcond */ |
|
|
|
|
|
|
|
|
|
template <class F, class... Args> |
|
|
|
|
thread::thread(F&& f, Args&&... args) |
|
|
|
@ -224,7 +342,7 @@ thread::thread(F&& f, Args&&... args)
|
|
|
|
|
using namespace std; |
|
|
|
|
using func_and_args = tuple |
|
|
|
|
<thread_data*, typename decay<F>::type, typename decay<Args>::type...>; |
|
|
|
|
std::unique_ptr<func_and_args> p( |
|
|
|
|
unique_ptr<func_and_args> p( |
|
|
|
|
new func_and_args(m_data.get(), forward<F>(f), forward<Args>(args)...)); |
|
|
|
|
m_handle = thread_create( |
|
|
|
|
m_data->stack, stack_size, THREAD_PRIORITY_MAIN - 1, 0, |
|
|
|
|