Loading...
Searching...
No Matches
thread.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 Hamburg University of Applied Sciences (HAW)
3 *
4 * This file is subject to the terms and conditions of the GNU Lesser
5 * General Public License v2.1. See the file LICENSE in the top level
6 * directory for more details.
7 */
8
30
31#ifndef RIOT_THREAD_HPP
32#define RIOT_THREAD_HPP
33
34#include "time.h"
35#include "thread.h"
36
37#include <array>
38#include <tuple>
39#include <atomic>
40#include <memory>
41#include <utility>
42#include <exception>
43#include <stdexcept>
44#include <functional>
45#include <type_traits>
46
47#include "riot/mutex.hpp"
48#include "riot/chrono.hpp"
50
52
53namespace riot {
54
58struct thread_data {
59 thread_data() : ref_count{2}, joining_thread{KERNEL_PID_UNDEF} {
60 // nop
61 }
63 std::atomic<unsigned> ref_count;
64 kernel_pid_t joining_thread;
65 std::array<char, THREAD_STACKSIZE_MAIN> stack;
67};
68
79 if (--ptr->ref_count == 0) {
80 delete ptr;
81 }
82 }
83};
84
91class thread_id {
92 template <class T, class Traits>
93 friend std::basic_ostream<T, Traits>& operator<<(std::basic_ostream
94 <T, Traits>& out,
95 thread_id id);
96 friend class thread;
97
98public:
102 inline thread_id() noexcept : m_handle{KERNEL_PID_UNDEF} {}
106 explicit inline thread_id(kernel_pid_t handle) : m_handle{handle} {}
107
111 inline bool operator==(thread_id other) noexcept {
112 return m_handle == other.m_handle;
113 }
114
117 inline bool operator!=(thread_id other) noexcept {
118 return !(m_handle == other.m_handle);
119 }
120
123 inline bool operator<(thread_id other) noexcept {
124 return m_handle < other.m_handle;
125 }
126
129 inline bool operator<=(thread_id other) noexcept {
130 return !(m_handle > other.m_handle);
131 }
132
135 inline bool operator>(thread_id other) noexcept {
136 return m_handle > other.m_handle;
137 }
138
141 inline bool operator>=(thread_id other) noexcept {
142 return !(m_handle < other.m_handle);
143 }
144
145private:
146 kernel_pid_t m_handle;
147};
148
152template <class T, class Traits>
153inline std::basic_ostream<T, Traits>& operator<<(std::basic_ostream
154 <T, Traits>& out,
155 thread_id id) {
156 return out << id.m_handle;
157}
158
159namespace this_thread {
160
164inline thread_id get_id() noexcept { return thread_id{thread_getpid()}; }
168inline void yield() noexcept { thread_yield(); }
173void sleep_for(const std::chrono::microseconds& us);
178template <class Rep, class Period>
179void sleep_for(const std::chrono::duration<Rep, Period>& sleep_duration) {
180 using namespace std::chrono;
181 if (sleep_duration > sleep_duration.zero()) {
182 constexpr duration<long double> max = microseconds::max();
183 microseconds us;
184 if (sleep_duration < max) {
185 us = duration_cast<microseconds>(sleep_duration);
186 if (us.count() == 0) {
187 // wait at least 1
188 us = microseconds(1);
189 }
190 if (us < sleep_duration) {
191 ++us;
192 }
193 } else {
194 us = microseconds::max();
195 }
196 sleep_for(us);
197 }
198}
199
204inline void sleep_until(const riot::time_point& sleep_time) {
205 mutex mtx;
207 unique_lock<mutex> lk(mtx);
208 while (riot::now() < sleep_time) {
209 cv.wait_until(lk, sleep_time);
210 }
211}
212} // namespace this_thread
213
221class thread {
222public:
226 using id = thread_id;
231
235 inline thread() noexcept : m_handle{KERNEL_PID_UNDEF} {}
241 template <class F, class... Args>
242 explicit thread(F&& f, Args&&... args);
243
247 thread(const thread&) = delete;
248
252 inline thread(thread&& t) noexcept : m_handle{t.m_handle} {
253 t.m_handle = KERNEL_PID_UNDEF;
254 std::swap(m_data, t.m_data);
255 }
256
257 ~thread();
258
262 thread& operator=(const thread&) = delete;
263
267 thread& operator=(thread&&) noexcept;
268
273 void swap(thread& t) noexcept {
274 std::swap(m_data, t.m_data);
275 std::swap(m_handle, t.m_handle);
276 }
277
282 inline bool joinable() const noexcept {
283 return m_handle != KERNEL_PID_UNDEF;
284 }
285
289 void join();
295 void detach();
299 inline id get_id() const noexcept { return thread_id{m_handle}; }
303 inline native_handle_type native_handle() noexcept { return m_handle; }
304
310 static unsigned hardware_concurrency() noexcept;
311
312private:
313 kernel_pid_t m_handle;
314 std::unique_ptr<thread_data, thread_data_deleter> m_data;
315};
316
322void swap(thread& lhs, thread& rhs) noexcept;
323
325template <class Tuple>
326void* thread_proxy(void* vp) {
327 { // without this scope, the objects here are not cleaned up correctly
328 std::unique_ptr<Tuple> p(static_cast<Tuple*>(vp));
329 auto tmp = std::get<0>(*p);
330 std::unique_ptr<thread_data, thread_data_deleter> data{tmp};
331 // create indices for the arguments, 0 is thread_data and 1 is the function
333 try {
334 detail::apply_args(std::get<1>(*p), indices, *p);
335 }
336 catch (...) {
337 // nop
338 }
339 if (data->joining_thread != KERNEL_PID_UNDEF) {
340 thread_wakeup(data->joining_thread);
341 }
342 }
343 // some riot cleanup code
345 return nullptr;
346}
348
349template <class F, class... Args>
350thread::thread(F&& f, Args&&... args) : m_data{new thread_data} {
351 using namespace std;
352 using func_and_args = tuple
353 <thread_data*, typename decay<F>::type, typename decay<Args>::type...>;
354 unique_ptr<func_and_args> p(
355 new func_and_args(m_data.get(), std::forward<F>(f), std::forward<Args>(args)...));
356 m_handle = thread_create(
357 m_data->stack.data(), m_data->stack.size(), THREAD_PRIORITY_MAIN - 1, 0,
358 &thread_proxy<func_and_args>, p.get(), "riot_cpp_thread");
359 if (m_handle >= 0) {
360 p.release();
361 } else {
362 throw std::system_error(
363 std::make_error_code(std::errc::resource_unavailable_try_again),
364 "Failed to create thread.");
365 }
366}
367
368inline thread& thread::operator=(thread&& other) noexcept {
369 if (m_handle != KERNEL_PID_UNDEF) {
370 std::terminate();
371 }
372 m_handle = other.m_handle;
373 other.m_handle = KERNEL_PID_UNDEF;
374 std::swap(m_data, other.m_data);
375 return *this;
376}
377
378inline void swap(thread& lhs, thread& rhs) noexcept { lhs.swap(rhs); }
379
380} // namespace riot
381
382#endif // RIOT_THREAD_HPP
C++11 chrono drop in replacement that adds the function now based on ztimer/timex.
C++11 compliant implementation of condition variable, uses the time point implemented in our chrono r...
cv_status wait_until(unique_lock< mutex > &lock, const time_point &timeout_time)
Block until woken up through the condition variable or a specified point in time is reached.
C++11 compliant implementation of mutex, uses the time point implemented in our chrono replacement in...
Definition mutex.hpp:43
implementation of thread::id
Definition thread.hpp:91
bool operator>(thread_id other) noexcept
Comparison operator for thread ids.
Definition thread.hpp:135
thread_id() noexcept
Creates a uninitialized thread id.
Definition thread.hpp:102
bool operator!=(thread_id other) noexcept
Comparison operator for thread ids.
Definition thread.hpp:117
friend std::basic_ostream< T, Traits > & operator<<(std::basic_ostream< T, Traits > &out, thread_id id)
Enable printing of thread ids using output streams.
Definition thread.hpp:153
bool operator>=(thread_id other) noexcept
Comparison operator for thread ids.
Definition thread.hpp:141
bool operator<(thread_id other) noexcept
Comparison operator for thread ids.
Definition thread.hpp:123
bool operator==(thread_id other) noexcept
Comparison operator for thread ids.
Definition thread.hpp:111
bool operator<=(thread_id other) noexcept
Comparison operator for thread ids.
Definition thread.hpp:129
thread_id(kernel_pid_t handle)
Create a thread id from a native handle.
Definition thread.hpp:106
C++11 compliant implementation of thread, however uses the time point from out chrono header instead ...
Definition thread.hpp:221
id get_id() const noexcept
Returns the id of a thread.
Definition thread.hpp:299
bool joinable() const noexcept
Query if the thread is joinable.
Definition thread.hpp:282
thread(const thread &)=delete
Disallow copy constructor.
static unsigned hardware_concurrency() noexcept
Returns the number of concurrent threads supported by the underlying hardware.
native_handle_type native_handle() noexcept
Returns the native handle to a thread.
Definition thread.hpp:303
thread & operator=(const thread &)=delete
Disallow copy assignment operator.
thread_id id
The id is of type thread_id-.
Definition thread.hpp:226
kernel_pid_t native_handle_type
The native handle type is the kernel_pid_t of RIOT.
Definition thread.hpp:230
thread() noexcept
Per default, an uninitialized thread is created.
Definition thread.hpp:235
void join()
Block until the thread finishes.
void swap(thread &t) noexcept
Swap threads.
Definition thread.hpp:273
void detach()
Detaches a thread from its handle and allows it to execute independently.
thread(thread &&t) noexcept
Move constructor.
Definition thread.hpp:252
A time point for timed wait, as clocks from the standard are not available on RIOT.
Definition chrono.hpp:41
C++11 compliant implementation of unique lock.
Definition mutex.hpp:142
C++11 condition variable drop in replacement.
int16_t kernel_pid_t
Unique process identifier.
Definition sched.h:138
NORETURN void sched_task_exit(void)
Removes thread from scheduler and set status to STATUS_STOPPED.
#define KERNEL_PID_UNDEF
Canonical identifier for an invalid PID.
Definition sched.h:109
kernel_pid_t thread_create(char *stack, int stacksize, uint8_t priority, int flags, thread_task_func_t task_func, void *arg, const char *name)
Creates a new thread.
void thread_yield(void)
Lets current thread yield.
int thread_wakeup(kernel_pid_t pid)
Wakes up a sleeping thread.
static kernel_pid_t thread_getpid(void)
Returns the process ID of the currently running thread.
Definition thread.h:429
C++11 mutex drop in replacement.
RIOT C++ namespace.
Definition chrono.hpp:35
std::basic_ostream< T, Traits > & operator<<(std::basic_ostream< T, Traits > &out, thread_id id)
Enable printing of thread ids using output streams.
Definition thread.hpp:153
time_point now()
Returns the current time saved in a time point.
Definition chrono.hpp:104
void swap(unique_lock< Mutex > &lhs, unique_lock< Mutex > &rhs) noexcept
Swaps two mutexes.
Definition mutex.hpp:309
This deleter prevents our thread data from being destroyed if the thread object is destroyed before t...
Definition thread.hpp:73
void operator()(thread_data *ptr)
Called by the deleter of a thread object to manage the lifetime of the thread internal management dat...
Definition thread.hpp:78
Holds context data for the thread.
Definition thread.hpp:58
thread_id get_id() noexcept
Access the id of the currently running thread.
Definition thread.hpp:164
void sleep_until(const riot::time_point &sleep_time)
Puts the current thread to sleep.
Definition thread.hpp:204
void yield() noexcept
Yield the currently running thread.
Definition thread.hpp:168
void sleep_for(const std::chrono::microseconds &us)
Puts the current thread to sleep.
#define THREAD_PRIORITY_MAIN
Priority of the main thread.
utility functions
il_indices< To, From >::type get_indices()
Function to create a list of indices from From to To.
auto apply_args(F &f, detail::int_list< Is... >, Tuple &&tup) -> decltype(f(std::get< Is >(tup)...))
Apply arguments in a tuple to function.