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 
48 namespace {
52 constexpr kernel_pid_t thread_uninitialized = -1;
56 constexpr size_t stack_size = THREAD_STACKSIZE_MAIN;
57 }
58 
62 struct thread_data {
63  thread_data() : ref_count{2}, joining_thread{thread_uninitialized} {
64  // nop
65  }
67  std::atomic<unsigned> ref_count;
68  kernel_pid_t joining_thread;
69  std::array<char, stack_size> stack;
71 };
72 
82  void operator()(thread_data* ptr) {
83  if (--ptr->ref_count == 0) {
84  delete ptr;
85  }
86  }
87 };
88 
95 class thread_id {
96  template <class T, class Traits>
97  friend std::basic_ostream<T, Traits>& operator<<(std::basic_ostream
98  <T, Traits>& out,
99  thread_id id);
100  friend class thread;
101 
102 public:
106  inline thread_id() noexcept : m_handle{thread_uninitialized} {}
110  explicit inline thread_id(kernel_pid_t handle) : m_handle{handle} {}
111 
115  inline bool operator==(thread_id other) noexcept {
116  return m_handle == other.m_handle;
117  }
121  inline bool operator!=(thread_id other) noexcept {
122  return !(m_handle == other.m_handle);
123  }
127  inline bool operator<(thread_id other) noexcept {
128  return m_handle < other.m_handle;
129  }
133  inline bool operator<=(thread_id other) noexcept {
134  return !(m_handle > other.m_handle);
135  }
139  inline bool operator>(thread_id other) noexcept {
140  return m_handle > other.m_handle;
141  }
145  inline bool operator>=(thread_id other) noexcept {
146  return !(m_handle < other.m_handle);
147  }
148 
149 private:
150  kernel_pid_t m_handle;
151 };
152 
156 template <class T, class Traits>
157 inline std::basic_ostream<T, Traits>& operator<<(std::basic_ostream
158  <T, Traits>& out,
159  thread_id id) {
160  return out << id.m_handle;
161 }
162 
163 namespace this_thread {
164 
168 inline thread_id get_id() noexcept { return thread_id{thread_getpid()}; }
172 inline void yield() noexcept { thread_yield(); }
177 void sleep_for(const std::chrono::nanoseconds& ns);
182 template <class Rep, class Period>
183 void sleep_for(const std::chrono::duration<Rep, Period>& sleep_duration) {
184  using namespace std::chrono;
185  if (sleep_duration > std::chrono::duration<Rep, Period>::zero()) {
186  constexpr std::chrono::duration<long double> max = nanoseconds::max();
187  nanoseconds ns;
188  if (sleep_duration < max) {
189  ns = duration_cast<nanoseconds>(sleep_duration);
190  if (ns < sleep_duration) {
191  ++ns;
192  }
193  } else {
194  ns = nanoseconds::max();
195  }
196  sleep_for(ns);
197  }
198 }
204 inline 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 
221 class thread {
222 public:
226  using id = thread_id;
231 
235  inline thread() noexcept : m_handle{thread_uninitialized} {}
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 = thread_uninitialized;
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 != thread_uninitialized;
284  }
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 
312 private:
313  kernel_pid_t m_handle;
314  std::unique_ptr<thread_data, thread_data_deleter> m_data;
315 };
316 
322 void swap(thread& lhs, thread& rhs) noexcept;
323 
325 template <class Tuple>
326 void* thread_proxy(void* vp) {
327  { // without this scope, the objects here are not cleaned up corrctly
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
332  auto indices = detail::get_indices<std::tuple_size<Tuple>::value, 2>();
333  try {
334  detail::apply_args(std::get<1>(*p), indices, *p);
335  }
336  catch (...) {
337  // nop
338  }
339  if (data->joining_thread != thread_uninitialized) {
340  thread_wakeup(data->joining_thread);
341  }
342  }
343  // some riot cleanup code
344  sched_task_exit();
345  return nullptr;
346 }
349 template <class F, class... Args>
350 thread::thread(F&& f, Args&&... args)
351  : m_data{new thread_data} {
352  using namespace std;
353  using func_and_args = tuple
354  <thread_data*, typename decay<F>::type, typename decay<Args>::type...>;
355  unique_ptr<func_and_args> p(
356  new func_and_args(m_data.get(), forward<F>(f), forward<Args>(args)...));
357  m_handle = thread_create(
358  m_data->stack.data(), stack_size, THREAD_PRIORITY_MAIN - 1, 0,
359  &thread_proxy<func_and_args>, p.get(), "riot_cpp_thread");
360  if (m_handle >= 0) {
361  p.release();
362  } else {
363  throw std::system_error(
364  std::make_error_code(std::errc::resource_unavailable_try_again),
365  "Failed to create thread.");
366  }
367 }
368 
369 inline thread& thread::operator=(thread&& other) noexcept {
370  if (m_handle != thread_uninitialized) {
371  std::terminate();
372  }
373  m_handle = other.m_handle;
374  other.m_handle = thread_uninitialized;
375  std::swap(m_data, other.m_data);
376  return *this;
377 }
378 
379 inline void swap(thread& lhs, thread& rhs) noexcept { lhs.swap(rhs); }
380 
381 } // namespace riot
382 
383 #endif // RIOT_THREAD_HPP
riot::thread_data_deleter::operator()
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:82
kernel_pid_t
int16_t kernel_pid_t
Unique process identifier.
Definition: sched.h:125
riot::thread::native_handle
native_handle_type native_handle() noexcept
Returns the native handle to a thread.
Definition: thread.hpp:303
thread_wakeup
int thread_wakeup(kernel_pid_t pid)
Wakes up a sleeping thread.
riot::operator<<
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:157
riot::thread_id::thread_id
thread_id() noexcept
Creates a uninitialized thread id.
Definition: thread.hpp:106
thread_create
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.
riot::thread_data_deleter
This deleter prevents our thread data from being destroyed if the thread object is destroyed before t...
Definition: thread.hpp:77
riot::thread_id
implementation of thread::id
Definition: thread.hpp:95
riot::this_thread::sleep_for
void sleep_for(const std::chrono::nanoseconds &ns)
Puts the current thread to sleep.
riot::thread_id::operator<<
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:157
riot::thread_id::operator<
bool operator<(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:127
thread_getpid
static kernel_pid_t thread_getpid(void)
Returns the process ID of the currently running thread.
Definition: thread.h:472
riot::this_thread::yield
void yield() noexcept
Yield the currently running thread.
Definition: thread.hpp:172
sched_task_exit
NORETURN void sched_task_exit(void)
Removes thread from scheduler and set status to STATUS_STOPPED.
riot::swap
void swap(unique_lock< Mutex > &lhs, unique_lock< Mutex > &rhs) noexcept
Swaps two mutexes.
Definition: mutex.hpp:309
riot::unique_lock
C++11 compliant implementation of unique lock.
Definition: mutex.hpp:142
thread_yield
void thread_yield(void)
Lets current thread yield.
chrono.hpp
C++11 chrono drop in replacement that adds the function now based on xtimer/timex.
riot::now
time_point now()
Returns the current time saved in a time point.
Definition: chrono.hpp:107
riot::thread::thread
thread(thread &&t) noexcept
Move constructor.
Definition: thread.hpp:252
riot::thread::get_id
id get_id() const noexcept
Returns the id of a thread.
Definition: thread.hpp:299
riot::time_point
A time point for timed wait, as clocks from the standard are not available on RIOT.
Definition: chrono.hpp:44
riot::thread_id::operator>=
bool operator>=(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:145
thread_util.hpp
utility functions
condition_variable.hpp
C++11 condition variable drop in replacement.
riot::thread::operator=
thread & operator=(const thread &)=delete
Disallow copy assignment operator.
THREAD_STACKSIZE_MAIN
#define THREAD_STACKSIZE_MAIN
Size of the main task's stack in bytes.
Definition: thread.h:247
riot::thread_id::operator>
bool operator>(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:139
riot::mutex
C++11 compliant implementation of mutex, uses the time point implemented in our chrono replacement in...
Definition: mutex.hpp:43
riot::thread_data
Holds context data for the thread.
Definition: thread.hpp:62
riot::thread_id::operator!=
bool operator!=(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:121
riot::thread::joinable
bool joinable() const noexcept
Query if the thread is joinable.
Definition: thread.hpp:282
riot::condition_variable::wait_until
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.
riot::thread::thread
thread() noexcept
Per default, an uninitialized thread is created.
Definition: thread.hpp:235
riot::this_thread::sleep_until
void sleep_until(const riot::time_point &sleep_time)
Puts the current thread to sleep.
Definition: thread.hpp:204
riot::thread
C++11 compliant implementation of thread, however uses the time point from out chrono header instead ...
Definition: thread.hpp:221
riot::condition_variable
C++11 compliant implementation of condition variable, uses the time point implemented in our chrono r...
Definition: condition_variable.hpp:52
riot::this_thread::get_id
thread_id get_id() noexcept
Access the id of the currently running thread.
Definition: thread.hpp:168
THREAD_PRIORITY_MAIN
#define THREAD_PRIORITY_MAIN
Priority of the main thread.
Definition: thread.h:303
riot::thread_id::operator<=
bool operator<=(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:133
riot::thread_id::operator==
bool operator==(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:115
riot::thread_id::thread_id
thread_id(kernel_pid_t handle)
Create a thread id from a native handle.
Definition: thread.hpp:110
mutex.hpp
C++11 mutex drop in replacement.
riot::thread::native_handle_type
kernel_pid_t native_handle_type
The native handle type is the kernel_pid_t of RIOT.
Definition: thread.hpp:230