Robotics Library  0.7.0
thread.h
Go to the documentation of this file.
1 //
2 // Copyright (c) 2009, Markus Rickert
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 //
14 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 // POSSIBILITY OF SUCH DAMAGE.
25 //
26 
27 #ifndef RL_UTIL_XENOMAI_THREAD
28 #define RL_UTIL_XENOMAI_THREAD
29 
30 #include <chrono>
31 #include <memory>
32 #include <system_error>
33 #include <native/task.h>
34 #include <native/timer.h>
35 
36 #include "chrono.h"
37 
38 namespace rl
39 {
40  namespace util
41  {
42  namespace xenomai
43  {
44  class thread
45  {
46  public:
47  typedef RT_TASK native_type;
48 
50 
51  class id
52  {
53  public:
54  id() :
55  M_thread()
56  {
57  }
58 
59  explicit id(native_type id) :
60  M_thread(id)
61  {
62  }
63 
64  protected:
65 
66  private:
67  friend class thread;
68 
69  friend class ::std::hash<thread::id>;
70 
71  friend bool operator==(thread::id x, thread::id y)
72  {
73  return ::rt_task_same(&x.M_thread, &y.M_thread);
74  }
75 
76  friend bool operator!=(thread::id x, thread::id y)
77  {
78  return !(x == y);
79  }
80 
81  friend bool operator<(thread::id x, thread::id y)
82  {
83  return x.M_thread.opaque < y.M_thread.opaque;
84  }
85 
86  friend bool operator<=(thread::id x, thread::id y)
87  {
88  return !(y < x);
89  }
90 
91  friend bool operator>(thread::id x, thread::id y)
92  {
93  return y < x;
94  }
95 
96  friend bool operator>=(thread::id x, thread::id y)
97  {
98  return !(x < y);
99  }
100 
101  template<class CharT, class Traits>
102  friend ::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& out, thread::id id)
103  {
104  if (id == thread::id())
105  {
106  return out << "thread::id of a non-executing thread";
107  }
108  else
109  {
110  return out << id.M_thread;
111  }
112  }
113 
115  };
116 
117  thread() = default;
118 
119  thread(thread&) = delete;
120 
121  thread(const thread&) = delete;
122 
123  thread(thread&& other)
124  {
125  this->swap(other);
126  }
127 
128  template<typename Callable, typename... Args>
129  explicit thread(Callable&& f, Args&&... args)
130  {
131  this->start_thread(
132  this->make_routine(
133  ::std::bind<void>(
134  ::std::forward<Callable>(f),
135  ::std::forward<Args>(args)...
136  )
137  )
138  );
139  }
140 
142  {
143  if (this->joinable())
144  {
145  ::std::terminate();
146  }
147  }
148 
149  void detach()
150  {
151  this->M_id = id();
152  }
153 
155  {
156  return this->M_id;
157  }
158 
159  static unsigned int hardware_concurrency()
160  {
161  return 0;
162  }
163 
164  void join()
165  {
166  int e = EINVAL;
167 
168  if (this->M_id != id())
169  {
170  e = ::rt_task_join(&this->M_id.M_thread);
171  }
172 
173  if (e)
174  {
175  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
176  }
177 
178  this->M_id = id();
179  }
180 
181  bool joinable() const
182  {
183  return !(this->M_id == id());
184  }
185 
187  {
188  return &this->M_id.M_thread;
189  }
190 
191  thread& operator=(const thread&) = delete;
192 
194  {
195  if (this->joinable())
196  {
197  ::std::terminate();
198  }
199 
200  this->swap(t);
201  return *this;
202  }
203 
204  void resume()
205  {
206  int e = ::rt_task_resume(&this->M_id.M_thread);
207 
208  if (e)
209  {
210  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
211  }
212  }
213 
214  template<typename Rep, typename Period>
215  void set_periodic(const ::std::chrono::duration<Rep, Period>& period)
216  {
217  ::std::chrono::nanoseconds period_ns = ::std::chrono::duration_cast< ::std::chrono::nanoseconds>(period);
218 
219  int e = ::rt_task_set_periodic(&this->M_id.M_thread, TM_NOW, ::rt_timer_ns2ticks(period_ns.count()));
220 
221  if (e)
222  {
223  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
224  }
225  }
226 
227  template<typename Duration, typename Rep, typename Period>
228  void set_periodic(const ::std::chrono::time_point<chrono::system_clock, Duration>& idate, const ::std::chrono::duration<Rep, Period>& period)
229  {
230  ::std::chrono::time_point<chrono::system_clock, ::std::chrono::nanoseconds> idate_ns = ::std::chrono::time_point_cast< ::std::chrono::nanoseconds>(idate);
231  ::std::chrono::nanoseconds period_ns = ::std::chrono::duration_cast< ::std::chrono::nanoseconds>(period);
232 
233  int e = ::rt_task_set_periodic(&this->M_id.M_thread, ::rt_timer_ns2ticks(idate_ns.time_since_epoch().count()), ::rt_timer_ns2ticks(period_ns.count()));
234 
235  if (e)
236  {
237  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
238  }
239  }
240 
241  template<typename Clock, typename Duration, typename Rep, typename Period>
242  void set_periodic(const ::std::chrono::time_point<Clock, Duration>& idate, const ::std::chrono::duration<Rep, Period>& period)
243  {
244  const typename Clock::time_point c_entry = Clock::now();
246  const ::std::chrono::nanoseconds delta = idate - c_entry;
247  const chrono::system_clock::time_point s_idate = s_entry + delta;
248  this->set_periodic(s_idate, period);
249  }
250 
251  void set_priority(const int& prio)
252  {
253  int e = ::rt_task_set_priority(&this->M_id.M_thread, prio);
254 
255  if (e)
256  {
257  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
258  }
259  }
260 
261  void suspend()
262  {
263  int e = ::rt_task_suspend(&this->M_id.M_thread);
264 
265  if (e)
266  {
267  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
268  }
269  }
270 
271  void swap(thread& other)
272  {
274  swap(this->M_id, other.M_id);
275  }
276 
277  friend void swap(thread& lhs, thread& rhs)
278  {
279  lhs.swap(rhs);
280  }
281 
282  void unblock()
283  {
284  int e = ::rt_task_unblock(&this->M_id.M_thread);
285 
286  if (e)
287  {
288  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
289  }
290  }
291 
292  protected:
293 
294  private:
295  struct Impl_base;
296 
297  typedef ::std::shared_ptr<Impl_base> shared_base_type;
298 
299  struct Impl_base
300  {
301  inline virtual ~Impl_base();
302 
303  virtual void run() = 0;
304 
306  };
307 
308  template<typename Callable>
309  struct Impl : public Impl_base
310  {
311  Impl(Callable&& f) :
312  func(::std::forward<Callable>(f))
313  {
314  }
315 
316  void run()
317  {
318  this->func();
319  }
320 
321  Callable func;
322  };
323 
324  static void execute_native_thread_routine(void* p)
325  {
326  thread::Impl_base* t = static_cast<thread::Impl_base*>(p);
328  local.swap(t->this_ptr);
329 
330  try
331  {
332  t->run();
333  }
334  catch (...)
335  {
336  ::std::terminate();
337  }
338  }
339 
340  template<typename Callable>
341  ::std::shared_ptr<Impl<Callable>> make_routine(Callable&& f)
342  {
343  return ::std::make_shared<Impl<Callable>>(::std::forward<Callable>(f));
344  }
345 
347  {
348  if (!__gthread_active_p())
349  {
350 #if __EXCEPTIONS
351  throw ::std::system_error(::std::make_error_code(::std::errc::operation_not_permitted), "Enable multithreading to use std::thread");
352 #else
353  throw ::std::system_error(::std::error_code(::std::errc::operation_not_permitted, ::std::generic_category()));
354 #endif
355  }
356 
357  b->this_ptr = b;
358  int e = ::rt_task_spawn(&this->M_id.M_thread, nullptr, 0, 0, T_FPU | T_JOINABLE, &thread::execute_native_thread_routine, b.get());
359 
360  if (e)
361  {
362  b->this_ptr.reset();
363  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
364  }
365  }
366 
367  id M_id;
368  };
369 
370  inline thread::Impl_base::~Impl_base() = default;
371 
372  namespace this_thread
373  {
375  {
376  return thread::id(*::rt_task_self());
377  }
378 
379  inline int get_priority()
380  {
381  RT_TASK_INFO info;
382  rt_task_inquire(::rt_task_self(), &info);
383  return info.cprio;
384  }
385 
386  inline int get_priority_max()
387  {
388  return 99;
389  }
390 
391  inline int get_priority_min()
392  {
393  return 0;
394  }
395 
396  inline int set_mode(const int& clrmask, const int& setmask)
397  {
398  int mode;
399  int e = ::rt_task_set_mode(clrmask, setmask, &mode);
400 
401  if (e)
402  {
403  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
404  }
405 
406  return mode;
407  }
408 
409  inline void set_priority(const int& priority)
410  {
411  int e = ::rt_task_set_priority(::rt_task_self(), priority);
412 
413  if (e)
414  {
415  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
416  }
417  }
418 
419  inline void shadow()
420  {
421  int e = ::rt_task_shadow(nullptr, nullptr, 0, T_FPU | T_JOINABLE);
422 
423  if (e)
424  {
425  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
426  }
427  }
428 
429  template<typename Rep, typename Period>
430  inline void sleep_for(const ::std::chrono::duration<Rep, Period>& rtime)
431  {
432  ::std::chrono::nanoseconds ns = ::std::chrono::duration_cast< ::std::chrono::nanoseconds>(rtime);
433  int e = ::rt_task_sleep(::rt_timer_ns2ticks(ns.count()));
434 
435  if (e)
436  {
437  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
438  }
439  }
440 
441  template<typename Duration>
442  inline void sleep_until(const ::std::chrono::time_point<chrono::system_clock, Duration>& atime)
443  {
444  ::std::chrono::time_point<chrono::system_clock, ::std::chrono::nanoseconds> ns = ::std::chrono::time_point_cast< ::std::chrono::nanoseconds>(atime);
445  int e = ::rt_task_sleep_until(::rt_timer_ns2ticks(ns.time_since_epoch().count()));
446 
447  if (e)
448  {
449  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
450  }
451  }
452 
453  template<typename Clock, typename Duration>
454  inline void sleep_until(const ::std::chrono::time_point<Clock, Duration>& atime)
455  {
456  sleep_for(atime - Clock::now());
457  }
458 
459  inline unsigned long int wait_period()
460  {
461  unsigned long int overruns;
462  int e = ::rt_task_wait_period(&overruns);
463 
464  if (e)
465  {
466  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
467  }
468 
469  return overruns;
470  }
471 
472  inline void yield()
473  {
474  int e = ::rt_task_yield();
475 
476  if (e)
477  {
478  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
479  }
480  }
481  }
482  }
483  }
484 }
485 
486 namespace std
487 {
488  template<>
490  {
491  size_t operator()(const ::rl::util::xenomai::thread::id& id) const
492  {
493  return hash< ::xnhandle_t>()(id.M_thread.opaque);
494  }
495  };
496 
498  {
499  x.swap(y);
500  }
501 }
502 
503 #endif // RL_UTIL_XENOMAI_THREAD
rl::util::xenomai::this_thread::get_priority_min
int get_priority_min()
Definition: thread.h:391
rl::util::xenomai::thread::Impl_base::this_ptr
shared_base_type this_ptr
Definition: thread.h:305
rl::util::xenomai::thread::id::operator>
friend bool operator>(thread::id x, thread::id y)
Definition: thread.h:91
rl::util::xenomai::thread::id::id
id(native_type id)
Definition: thread.h:59
rl::util::xenomai::thread::native_type
RT_TASK native_type
Definition: thread.h:47
rl::util::xenomai::thread::operator=
thread & operator=(thread &&t)
Definition: thread.h:193
std::swap
void swap(::rl::util::xenomai::thread &x, ::rl::util::xenomai::thread &y)
Definition: thread.h:497
rl::util::xenomai::thread::detach
void detach()
Definition: thread.h:149
rl::util::xenomai::thread::Impl_base::run
virtual void run()=0
rl::util::xenomai::thread::id::operator>=
friend bool operator>=(thread::id x, thread::id y)
Definition: thread.h:96
rl::util::xenomai::this_thread::get_priority_max
int get_priority_max()
Definition: thread.h:386
rl::util::xenomai::thread::get_id
thread::id get_id() const
Definition: thread.h:154
rl::util::xenomai::thread::shared_base_type
::std::shared_ptr< Impl_base > shared_base_type
Definition: thread.h:295
rl::util::xenomai::this_thread::get_id
thread::id get_id()
Definition: thread.h:374
rl::util::xenomai::thread::Impl
Definition: thread.h:310
rl::util::xenomai::thread::Impl_base
Definition: thread.h:300
rl::util::xenomai::thread::id::operator!=
friend bool operator!=(thread::id x, thread::id y)
Definition: thread.h:76
rl::util::xenomai::thread::set_priority
void set_priority(const int &prio)
Definition: thread.h:251
rl::util::xenomai::thread::thread
thread(Callable &&f, Args &&... args)
Definition: thread.h:129
rl::util::xenomai::this_thread::yield
void yield()
Definition: thread.h:472
rl::util::xenomai::thread::thread
thread(thread &&other)
Definition: thread.h:123
rl::util::xenomai::thread::~thread
~thread()
Definition: thread.h:141
rl::util::xenomai::thread::id::operator<<
friend ::std::basic_ostream< CharT, Traits > & operator<<(::std::basic_ostream< CharT, Traits > &out, thread::id id)
Definition: thread.h:102
rl::util::xenomai::thread
Definition: thread.h:45
rl::util::xenomai::thread::id::operator==
friend bool operator==(thread::id x, thread::id y)
Definition: thread.h:71
rl::util::xenomai::thread::set_periodic
void set_periodic(const ::std::chrono::time_point< Clock, Duration > &idate, const ::std::chrono::duration< Rep, Period > &period)
Definition: thread.h:242
rl::util::xenomai::thread::id::operator<=
friend bool operator<=(thread::id x, thread::id y)
Definition: thread.h:86
std::swap
void swap(::rl::util::rtai::thread &x, ::rl::util::rtai::thread &y)
Definition: thread.h:492
rl::util::xenomai::thread::Impl_base::~Impl_base
virtual ~Impl_base()
rl::util::xenomai::this_thread::shadow
void shadow()
Definition: thread.h:419
rl::util::xenomai::thread::swap
friend void swap(thread &lhs, thread &rhs)
Definition: thread.h:277
rl::util::xenomai::this_thread::sleep_until
void sleep_until(const ::std::chrono::time_point< chrono::system_clock, Duration > &atime)
Definition: thread.h:442
rl::util::xenomai::thread::unblock
void unblock()
Definition: thread.h:282
rl::util::xenomai::thread::id::M_thread
native_type M_thread
Definition: thread.h:114
chrono.h
rl::util::xenomai::thread::Impl::run
void run()
Definition: thread.h:316
rl::util::xenomai::this_thread::sleep_for
void sleep_for(const ::std::chrono::duration< Rep, Period > &rtime)
Definition: thread.h:430
rl::util::xenomai::thread::thread
thread(const thread &)=delete
rl::util::xenomai::thread::M_id
id M_id
Definition: thread.h:367
rl::util::xenomai::thread::set_periodic
void set_periodic(const ::std::chrono::duration< Rep, Period > &period)
Definition: thread.h:215
rl::util::xenomai::thread::thread
thread(thread &)=delete
rl::util::xenomai::thread::resume
void resume()
Definition: thread.h:204
rl::util::xenomai::chrono::system_clock::time_point
::std::chrono::time_point< system_clock, duration > time_point
Definition: chrono.h:69
rl::util::xenomai::thread::native_handle
native_handle_type native_handle()
Definition: thread.h:186
rl::util::xenomai::thread::suspend
void suspend()
Definition: thread.h:261
rl::util::xenomai::thread::Impl::func
Callable func
Definition: thread.h:321
rl::util::xenomai::thread::thread
thread()=default
rl::util::xenomai::thread::native_handle_type
native_type * native_handle_type
Definition: thread.h:49
rl::util::xenomai::thread::id
Definition: thread.h:52
rl::util::xenomai::thread::operator=
thread & operator=(const thread &)=delete
rl::util::xenomai::this_thread::set_mode
int set_mode(const int &clrmask, const int &setmask)
Definition: thread.h:396
rl::util::xenomai::this_thread::set_priority
void set_priority(const int &priority)
Definition: thread.h:409
std
Definition: thread.h:482
rl::util::xenomai::thread::start_thread
void start_thread(shared_base_type b)
Definition: thread.h:346
rl::util::xenomai::thread::Impl::Impl
Impl(Callable &&f)
Definition: thread.h:311
std::hash< ::rl::util::xenomai::thread::id >::operator()
size_t operator()(const ::rl::util::xenomai::thread::id &id) const
Definition: thread.h:491
rl::util::xenomai::thread::id::id
id()
Definition: thread.h:54
rl::util::xenomai::thread::make_routine
::std::shared_ptr< Impl< Callable > > make_routine(Callable &&f)
Definition: thread.h:341
rl::util::xenomai::thread::hardware_concurrency
static unsigned int hardware_concurrency()
Definition: thread.h:159
rl::util::xenomai::this_thread::wait_period
unsigned long int wait_period()
Definition: thread.h:459
rl::util::xenomai::thread::joinable
bool joinable() const
Definition: thread.h:181
rl::util::xenomai::thread::execute_native_thread_routine
static void execute_native_thread_routine(void *p)
Definition: thread.h:324
rl::util::xenomai::thread::join
void join()
Definition: thread.h:164
rl::util::xenomai::chrono::system_clock::now
static time_point now()
Definition: chrono.h:75
rl::util::xenomai::this_thread::get_priority
int get_priority()
Definition: thread.h:379
rl::util::xenomai::thread::id::operator<
friend bool operator<(thread::id x, thread::id y)
Definition: thread.h:81
rl::util::xenomai::thread::set_periodic
void set_periodic(const ::std::chrono::time_point< chrono::system_clock, Duration > &idate, const ::std::chrono::duration< Rep, Period > &period)
Definition: thread.h:228
rl::util::xenomai::thread::swap
void swap(thread &other)
Definition: thread.h:271
rl
Robotics Library.
Definition: AnalogInput.cpp:30