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 
24 #ifndef RIOT_THREAD_HPP
25 #define RIOT_THREAD_HPP
26 
27 #include "time.h"
28 #include "thread.h"
29 
30 #include <array>
31 #include <tuple>
32 #include <atomic>
33 #include <memory>
34 #include <utility>
35 #include <exception>
36 #include <stdexcept>
37 #include <functional>
38 #include <type_traits>
39 
40 #include "riot/mutex.hpp"
41 #include "riot/chrono.hpp"
43 
45 
46 namespace riot {
47 
51 struct thread_data {
52  thread_data() : ref_count{2}, joining_thread{KERNEL_PID_UNDEF} {
53  // nop
54  }
56  std::atomic<unsigned> ref_count;
57  kernel_pid_t joining_thread;
58  std::array<char, THREAD_STACKSIZE_MAIN> stack;
60 };
61 
71  void operator()(thread_data* ptr) {
72  if (--ptr->ref_count == 0) {
73  delete ptr;
74  }
75  }
76 };
77 
84 class thread_id {
85  template <class T, class Traits>
86  friend std::basic_ostream<T, Traits>& operator<<(std::basic_ostream
87  <T, Traits>& out,
88  thread_id id);
89  friend class thread;
90 
91 public:
95  inline thread_id() noexcept : m_handle{KERNEL_PID_UNDEF} {}
99  explicit inline thread_id(kernel_pid_t handle) : m_handle{handle} {}
100 
104  inline bool operator==(thread_id other) noexcept {
105  return m_handle == other.m_handle;
106  }
110  inline bool operator!=(thread_id other) noexcept {
111  return !(m_handle == other.m_handle);
112  }
116  inline bool operator<(thread_id other) noexcept {
117  return m_handle < other.m_handle;
118  }
122  inline bool operator<=(thread_id other) noexcept {
123  return !(m_handle > other.m_handle);
124  }
128  inline bool operator>(thread_id other) noexcept {
129  return m_handle > other.m_handle;
130  }
134  inline bool operator>=(thread_id other) noexcept {
135  return !(m_handle < other.m_handle);
136  }
137 
138 private:
139  kernel_pid_t m_handle;
140 };
141 
145 template <class T, class Traits>
146 inline std::basic_ostream<T, Traits>& operator<<(std::basic_ostream
147  <T, Traits>& out,
148  thread_id id) {
149  return out << id.m_handle;
150 }
151 
152 namespace this_thread {
153 
157 inline thread_id get_id() noexcept { return thread_id{thread_getpid()}; }
161 inline void yield() noexcept { thread_yield(); }
166 void sleep_for(const std::chrono::microseconds& us);
171 template <class Rep, class Period>
172 void sleep_for(const std::chrono::duration<Rep, Period>& sleep_duration) {
173  using namespace std::chrono;
174  if (sleep_duration > sleep_duration.zero()) {
175  constexpr duration<long double> max = microseconds::max();
176  microseconds us;
177  if (sleep_duration < max) {
178  us = duration_cast<microseconds>(sleep_duration);
179  if (us.count() == 0) {
180  // wait at least 1
181  us = microseconds(1);
182  }
183  if (us < sleep_duration) {
184  ++us;
185  }
186  } else {
187  us = microseconds::max();
188  }
189  sleep_for(us);
190  }
191 }
197 inline void sleep_until(const riot::time_point& sleep_time) {
198  mutex mtx;
200  unique_lock<mutex> lk(mtx);
201  while (riot::now() < sleep_time) {
202  cv.wait_until(lk, sleep_time);
203  }
204 }
205 } // namespace this_thread
206 
214 class thread {
215 public:
219  using id = thread_id;
224 
228  inline thread() noexcept : m_handle{KERNEL_PID_UNDEF} {}
234  template <class F, class... Args>
235  explicit thread(F&& f, Args&&... args);
236 
240  thread(const thread&) = delete;
241 
245  inline thread(thread&& t) noexcept : m_handle{t.m_handle} {
246  t.m_handle = KERNEL_PID_UNDEF;
247  std::swap(m_data, t.m_data);
248  }
249 
250  ~thread();
251 
255  thread& operator=(const thread&) = delete;
256 
260  thread& operator=(thread&&) noexcept;
261 
266  void swap(thread& t) noexcept {
267  std::swap(m_data, t.m_data);
268  std::swap(m_handle, t.m_handle);
269  }
270 
275  inline bool joinable() const noexcept {
276  return m_handle != KERNEL_PID_UNDEF;
277  }
282  void join();
288  void detach();
292  inline id get_id() const noexcept { return thread_id{m_handle}; }
296  inline native_handle_type native_handle() noexcept { return m_handle; }
297 
303  static unsigned hardware_concurrency() noexcept;
304 
305 private:
306  kernel_pid_t m_handle;
307  std::unique_ptr<thread_data, thread_data_deleter> m_data;
308 };
309 
315 void swap(thread& lhs, thread& rhs) noexcept;
316 
318 template <class Tuple>
319 void* thread_proxy(void* vp) {
320  { // without this scope, the objects here are not cleaned up correctly
321  std::unique_ptr<Tuple> p(static_cast<Tuple*>(vp));
322  auto tmp = std::get<0>(*p);
323  std::unique_ptr<thread_data, thread_data_deleter> data{tmp};
324  // create indices for the arguments, 0 is thread_data and 1 is the function
325  auto indices = detail::get_indices<std::tuple_size<Tuple>::value, 2>();
326  try {
327  detail::apply_args(std::get<1>(*p), indices, *p);
328  }
329  catch (...) {
330  // nop
331  }
332  if (data->joining_thread != KERNEL_PID_UNDEF) {
333  thread_wakeup(data->joining_thread);
334  }
335  }
336  // some riot cleanup code
337  sched_task_exit();
338  return nullptr;
339 }
342 template <class F, class... Args>
343 thread::thread(F&& f, Args&&... args) : m_data{new thread_data} {
344  using namespace std;
345  using func_and_args = tuple
346  <thread_data*, typename decay<F>::type, typename decay<Args>::type...>;
347  unique_ptr<func_and_args> p(
348  new func_and_args(m_data.get(), std::forward<F>(f), std::forward<Args>(args)...));
349  m_handle = thread_create(
350  m_data->stack.data(), m_data->stack.size(), THREAD_PRIORITY_MAIN - 1, 0,
351  &thread_proxy<func_and_args>, p.get(), "riot_cpp_thread");
352  if (m_handle >= 0) {
353  p.release();
354  } else {
355  throw std::system_error(
356  std::make_error_code(std::errc::resource_unavailable_try_again),
357  "Failed to create thread.");
358  }
359 }
360 
361 inline thread& thread::operator=(thread&& other) noexcept {
362  if (m_handle != KERNEL_PID_UNDEF) {
363  std::terminate();
364  }
365  m_handle = other.m_handle;
366  other.m_handle = KERNEL_PID_UNDEF;
367  std::swap(m_data, other.m_data);
368  return *this;
369 }
370 
371 inline void swap(thread& lhs, thread& rhs) noexcept { lhs.swap(rhs); }
372 
373 } // namespace riot
374 
375 #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:84
bool operator>(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:128
thread_id() noexcept
Creates a uninitialized thread id.
Definition: thread.hpp:95
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:146
bool operator!=(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:110
bool operator>=(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:134
bool operator<(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:116
bool operator==(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:104
bool operator<=(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:122
thread_id(kernel_pid_t handle)
Create a thread id from a native handle.
Definition: thread.hpp:99
C++11 compliant implementation of thread, however uses the time point from out chrono header instead ...
Definition: thread.hpp:214
id get_id() const noexcept
Returns the id of a thread.
Definition: thread.hpp:292
bool joinable() const noexcept
Query if the thread is joinable.
Definition: thread.hpp:275
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:296
kernel_pid_t native_handle_type
The native handle type is the kernel_pid_t of RIOT.
Definition: thread.hpp:223
thread & operator=(const thread &)=delete
Disallow copy assignment operator.
thread() noexcept
Per default, an uninitialized thread is created.
Definition: thread.hpp:228
void join()
Block until the thread finishes.
void swap(thread &t) noexcept
Swap threads.
Definition: thread.hpp:266
void detach()
Detaches a thread from its handle and allows it to execute independently.
thread(thread &&t) noexcept
Move constructor.
Definition: thread.hpp:245
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:139
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:110
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:393
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:146
void swap(thread &lhs, thread &rhs) noexcept
Swaps two threads.
Definition: thread.hpp:371
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:66
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:71
Holds context data for the thread.
Definition: thread.hpp:51
thread_id get_id() noexcept
Access the id of the currently running thread.
Definition: thread.hpp:157
void sleep_until(const riot::time_point &sleep_time)
Puts the current thread to sleep.
Definition: thread.hpp:197
void yield() noexcept
Yield the currently running thread.
Definition: thread.hpp:161
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