The friendly Operating System for the Internet of Things
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 <tuple>
31 #include <atomic>
32 #include <memory>
33 #include <utility>
34 #include <exception>
35 #include <stdexcept>
36 #include <functional>
37 #include <type_traits>
38 
39 #include "riot/mutex.hpp"
40 #include "riot/chrono.hpp"
42 
44 
45 namespace riot {
46 
47 namespace {
51 constexpr kernel_pid_t thread_uninitialized = -1;
55 constexpr size_t stack_size = THREAD_STACKSIZE_MAIN;
56 }
57 
61 struct thread_data {
62  thread_data() : ref_count{2}, joining_thread{thread_uninitialized} {
63  // nop
64  }
66  std::atomic<unsigned> ref_count;
67  kernel_pid_t joining_thread;
68  char stack[stack_size];
70 };
71 
81  void operator()(thread_data* ptr) {
82  if (--ptr->ref_count == 0) {
83  delete ptr;
84  }
85  }
86 };
87 
94 class thread_id {
95  template <class T, class Traits>
96  friend std::basic_ostream<T, Traits>& operator<<(std::basic_ostream
97  <T, Traits>& out,
98  thread_id id);
99  friend class thread;
100 
101 public:
105  inline thread_id() noexcept : m_handle{thread_uninitialized} {}
109  inline thread_id(kernel_pid_t handle) : m_handle{handle} {}
110 
114  inline bool operator==(thread_id other) noexcept {
115  return m_handle == other.m_handle;
116  }
120  inline bool operator!=(thread_id other) noexcept {
121  return !(m_handle == other.m_handle);
122  }
126  inline bool operator<(thread_id other) noexcept {
127  return m_handle < other.m_handle;
128  }
132  inline bool operator<=(thread_id other) noexcept {
133  return !(m_handle > other.m_handle);
134  }
138  inline bool operator>(thread_id other) noexcept {
139  return m_handle > other.m_handle;
140  }
144  inline bool operator>=(thread_id other) noexcept {
145  return !(m_handle < other.m_handle);
146  }
147 
148 private:
149  kernel_pid_t m_handle;
150 };
151 
155 template <class T, class Traits>
156 inline std::basic_ostream<T, Traits>& operator<<(std::basic_ostream
157  <T, Traits>& out,
158  thread_id id) {
159  return out << id.m_handle;
160 }
161 
162 namespace this_thread {
163 
167 inline thread_id get_id() noexcept { return thread_getpid(); }
171 inline void yield() noexcept { thread_yield(); }
176 void sleep_for(const std::chrono::nanoseconds& ns);
181 template <class Rep, class Period>
182 void sleep_for(const std::chrono::duration<Rep, Period>& sleep_duration) {
183  using namespace std::chrono;
184  if (sleep_duration > std::chrono::duration<Rep, Period>::zero()) {
185  constexpr std::chrono::duration<long double> max = nanoseconds::max();
186  nanoseconds ns;
187  if (sleep_duration < max) {
188  ns = duration_cast<nanoseconds>(sleep_duration);
189  if (ns < sleep_duration) {
190  ++ns;
191  }
192  } else {
193  ns = nanoseconds::max();
194  }
195  sleep_for(ns);
196  }
197 }
203 inline void sleep_until(const riot::time_point& sleep_time) {
204  mutex mtx;
205  condition_variable cv;
206  unique_lock<mutex> lk(mtx);
207  while (riot::now() < sleep_time) {
208  cv.wait_until(lk, sleep_time);
209  }
210 }
211 } // namespace this_thread
212 
220 class thread {
221 public:
225  using id = thread_id;
230 
234  inline thread() noexcept : m_handle{thread_uninitialized} {}
240  template <class F, class... Args>
241  explicit thread(F&& f, Args&&... args);
242  thread(const thread&) = delete;
246  inline thread(thread&& t) noexcept : m_handle{t.m_handle} {
247  t.m_handle = thread_uninitialized;
248  std::swap(m_data, t.m_data);
249  }
250 
251  ~thread();
252 
253  thread& operator=(const thread&) = delete;
257  thread& operator=(thread&&) noexcept;
258 
263  void swap(thread& t) noexcept {
264  std::swap(m_data, t.m_data);
265  std::swap(m_handle, t.m_handle);
266  }
267 
272  inline bool joinable() const noexcept {
273  return m_handle != thread_uninitialized;
274  }
279  void join();
285  void detach();
289  inline id get_id() const noexcept { return m_handle; }
293  inline native_handle_type native_handle() noexcept { return m_handle; }
294 
300  static unsigned hardware_concurrency() noexcept;
301 
302 private:
303  kernel_pid_t m_handle;
304  std::unique_ptr<thread_data, thread_data_deleter> m_data;
305 };
306 
312 void swap(thread& lhs, thread& rhs) noexcept;
313 
315 template <class Tuple>
316 void* thread_proxy(void* vp) {
317  { // without this scope, the objects here are not cleaned up corrctly
318  std::unique_ptr<Tuple> p(static_cast<Tuple*>(vp));
319  auto tmp = std::get<0>(*p);
320  std::unique_ptr<thread_data, thread_data_deleter> data{tmp};
321  // create indices for the arguments, 0 is thread_data and 1 is the function
322  auto indices = detail::get_indices<std::tuple_size<Tuple>::value, 2>();
323  try {
324  detail::apply_args(std::get<1>(*p), indices, *p);
325  }
326  catch (...) {
327  // nop
328  }
329  if (data->joining_thread != thread_uninitialized) {
330  thread_wakeup(data->joining_thread);
331  }
332  }
333  // some riot cleanup code
334  sched_task_exit();
335  return nullptr;
336 }
339 template <class F, class... Args>
340 thread::thread(F&& f, Args&&... args)
341  : m_data{new thread_data} {
342  using namespace std;
343  using func_and_args = tuple
344  <thread_data*, typename decay<F>::type, typename decay<Args>::type...>;
345  unique_ptr<func_and_args> p(
346  new func_and_args(m_data.get(), forward<F>(f), forward<Args>(args)...));
347  m_handle = thread_create(
348  m_data->stack, stack_size, THREAD_PRIORITY_MAIN - 1, 0,
349  &thread_proxy<func_and_args>, p.get(), "riot_cpp_thread");
350  if (m_handle >= 0) {
351  p.release();
352  } else {
353  throw std::system_error(
354  std::make_error_code(std::errc::resource_unavailable_try_again),
355  "Failed to create thread.");
356  }
357 }
358 
359 inline thread& thread::operator=(thread&& other) noexcept {
360  if (m_handle != thread_uninitialized) {
361  std::terminate();
362  }
363  m_handle = other.m_handle;
364  other.m_handle = thread_uninitialized;
365  std::swap(m_data, other.m_data);
366  return *this;
367 }
368 
369 inline void swap(thread& lhs, thread& rhs) noexcept { lhs.swap(rhs); }
370 
371 } // namespace riot
372 
373 #endif // RIOT_THREAD_HPP
thread() noexcept
Per default, an uninitialized thread is created.
Definition: thread.hpp:234
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:156
bool operator>=(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:144
Definition: chrono.hpp:34
bool operator>(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:138
static kernel_pid_t thread_getpid(void)
Returns the process ID of the currently running thread.
Definition: thread.h:405
kernel_pid_t native_handle_type
The native handle type is the kernel_pid_t of RIOT.
Definition: thread.hpp:229
int16_t kernel_pid_t
Unique process identifier.
Definition: kernel_types.h:83
C++11 mutex drop in replacement.
native_handle_type native_handle() noexcept
Returns the native handle to a thread.
Definition: thread.hpp:293
C++11 condition variable drop in replacement.
utility functions
bool operator<=(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:132
void thread_yield(void)
Lets current thread yield.
bool operator==(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:114
id get_id() const noexcept
Returns the id of a thread.
Definition: thread.hpp:289
Threading API.
#define THREAD_PRIORITY_MAIN
Priority of the main thread.
Definition: thread.h:276
thread_id() noexcept
Creates a uninitialized thread id.
Definition: thread.hpp:105
int thread_wakeup(kernel_pid_t pid)
Wakes up a sleeping thread.
#define THREAD_STACKSIZE_MAIN
Size of the main task's stack in bytes.
Definition: thread.h:250
C++11 compliant implementation of thread, however uses the time point from out chrono header instead ...
Definition: thread.hpp:220
NORETURN void sched_task_exit(void)
Removes thread from scheduler and set status to STATUS_STOPPED.
A time point for timed wait, as clocks from the standard are not available on RIOT.
Definition: chrono.hpp:44
bool operator!=(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:120
C++11 chrono drop in replacement that adds the function now based on xtimer/timex.
bool joinable() const noexcept
Query if the thread is joinable.
Definition: thread.hpp:272
Holds context data for the thread.
Definition: thread.hpp:61
implementation of thread::id
Definition: thread.hpp:94
kernel_pid_t thread_create(char *stack, int stacksize, char priority, int flags, thread_task_func_t task_func, void *arg, const char *name)
Creates a new thread.
void operator()(thread_data *ptr)
 .
Definition: thread.hpp:81
thread_id(kernel_pid_t handle)
Create a thread id from a native handle.
Definition: thread.hpp:109
thread(thread &&t) noexcept
Move constructor.
Definition: thread.hpp:246
This deleter prevents our thread data from being destroyed if the thread object is destroyed before t...
Definition: thread.hpp:76
bool operator<(thread_id other) noexcept
Comparison operator for thread ids.
Definition: thread.hpp:126