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_RTAI_THREAD
28 #define RL_UTIL_RTAI_THREAD
29 
30 #include <chrono>
31 #include <memory>
32 #include <rtai_lxrt.h>
33 #include <system_error>
34 
35 #include "chrono.h"
36 
37 namespace rl
38 {
39  namespace util
40  {
41  namespace rtai
42  {
43  class thread
44  {
45  public:
46  typedef pthread_t native_handle_type;
47 
48  class id
49  {
50  public:
51  id() :
52  M_task(nullptr),
53  M_thread()
54  {
55  }
56 
57  explicit id(native_handle_type id, RT_TASK* task) :
58  M_task(task),
59  M_thread(id)
60  {
61  }
62 
63  protected:
64 
65  private:
66  friend class thread;
67 
68  friend class ::std::hash<thread::id>;
69 
70  friend bool operator==(thread::id x, thread::id y)
71  {
72  return ::pthread_equal(x.M_thread, y.M_thread);
73  }
74 
75  friend bool operator!=(thread::id x, thread::id y)
76  {
77  return !(x == y);
78  }
79 
80  friend bool operator<(thread::id x, thread::id y)
81  {
82  return x.M_thread < y.M_thread;
83  }
84 
85  friend bool operator<=(thread::id x, thread::id y)
86  {
87  return !(y < x);
88  }
89 
90  friend bool operator>(thread::id x, thread::id y)
91  {
92  return y < x;
93  }
94 
95  friend bool operator>=(thread::id x, thread::id y)
96  {
97  return !(x < y);
98  }
99 
100  template<class CharT, class Traits>
101  friend ::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& out, thread::id id)
102  {
103  if (id == thread::id())
104  {
105  return out << "thread::id of a non-executing thread";
106  }
107  else
108  {
109  return out << id.M_thread;
110  }
111  }
112 
113  RT_TASK* M_task;
114 
116  };
117 
118  thread() = default;
119 
120  thread(thread&) = delete;
121 
122  thread(const thread&) = delete;
123 
124  thread(thread&& other)
125  {
126  this->swap(other);
127  }
128 
129  template<typename Callable, typename... Args>
130  explicit thread(Callable&& f, Args&&... args)
131  {
132  this->start_thread(
133  this->make_routine(
134  ::std::bind<void>(
135  ::std::forward<Callable>(f),
136  ::std::forward<Args>(args)...
137  )
138  )
139  );
140  }
141 
143  {
144  if (this->joinable())
145  {
146  ::std::terminate();
147  }
148  }
149 
150  void detach()
151  {
152  int e = EINVAL;
153 
154  if (this->M_id != id())
155  {
156  e = ::pthread_detach(this->M_id.M_thread);
157  }
158 
159  if (e)
160  {
161  throw ::std::system_error(::std::error_code(e, ::std::generic_category()));
162  }
163 
164  this->M_id = id();
165  }
166 
168  {
169  return this->M_id;
170  }
171 
172  static unsigned int hardware_concurrency()
173  {
174  return 0;
175  }
176 
177  void join()
178  {
179  int e = EINVAL;
180 
181  if (this->M_id != id())
182  {
183  e = ::pthread_join(this->M_id.M_thread, 0);
184  }
185 
186  if (e)
187  {
188  throw ::std::system_error(::std::error_code(e, ::std::generic_category()));
189  }
190 
191  this->M_id = id();
192  }
193 
194  bool joinable() const
195  {
196  return !(this->M_id == id());
197  }
198 
200  {
201  return this->M_id.M_thread;
202  }
203 
204  thread& operator=(const thread&) = delete;
205 
207  {
208  if (this->joinable())
209  {
210  ::std::terminate();
211  }
212 
213  this->swap(t);
214  return *this;
215  }
216 
217  void resume()
218  {
219  int e = ::rt_task_resume(this->M_id.M_task);
220 
221  if (e)
222  {
223  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
224  }
225  }
226 
227  template<typename Rep, typename Period>
228  void set_periodic(const ::std::chrono::duration<Rep, Period>& period)
229  {
230  ::std::chrono::nanoseconds period_ns = ::std::chrono::duration_cast< ::std::chrono::nanoseconds>(period);
231 
232  int e = ::rt_task_make_periodic(this->M_id.M_task, ::rt_get_time(), ::nano2count(period_ns.count()));
233 
234  if (e)
235  {
236  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
237  }
238  }
239 
240  template<typename Duration, typename Rep, typename Period>
241  void set_periodic(const ::std::chrono::time_point<chrono::system_clock, Duration>& idate, const ::std::chrono::duration<Rep, Period>& period)
242  {
243  ::std::chrono::time_point<chrono::system_clock, ::std::chrono::nanoseconds> idate_ns = ::std::chrono::time_point_cast< ::std::chrono::nanoseconds>(idate);
244  ::std::chrono::nanoseconds period_ns = ::std::chrono::duration_cast< ::std::chrono::nanoseconds>(period);
245 
246  int e = ::rt_task_make_periodic(this->M_id.M_task, ::nano2count(idate_ns.time_since_epoch().count()), ::nano2count(period_ns.count()));
247 
248  if (e)
249  {
250  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
251  }
252  }
253 
254  template<typename Clock, typename Duration, typename Rep, typename Period>
255  void set_periodic(const ::std::chrono::time_point<Clock, Duration>& idate, const ::std::chrono::duration<Rep, Period>& period)
256  {
257  const typename Clock::time_point c_entry = Clock::now();
259  const ::std::chrono::nanoseconds delta = idate - c_entry;
260  const chrono::system_clock::time_point s_idate = s_entry + delta;
261  this->set_periodic(s_idate, period);
262  }
263 
264  void set_priority(const int& prio)
265  {
266  int e = ::rt_change_prio(this->M_id.M_task, prio);
267 
268  if (e)
269  {
270  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
271  }
272  }
273 
274  void suspend()
275  {
276  int e = ::rt_task_suspend(this->M_id.M_task);
277 
278  if (e)
279  {
280  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
281  }
282  }
283 
284  void swap(thread& other)
285  {
287  swap(this->M_id, other.M_id);
288  }
289 
290  friend void swap(thread& lhs, thread& rhs)
291  {
292  lhs.swap(rhs);
293  }
294 
295  protected:
296 
297  private:
298  struct Impl_base;
299 
300  typedef ::std::shared_ptr<Impl_base> shared_base_type;
301 
302  struct Impl_base
303  {
304  inline virtual ~Impl_base();
305 
306  virtual void run() = 0;
307 
308  id M_id;
309 
311  };
312 
313  template<typename Callable>
314  struct Impl : public Impl_base
315  {
316  Impl(Callable&& f) :
317  func(::std::forward<Callable>(f))
318  {
319  }
320 
321  void run()
322  {
323  this->func();
324  }
325 
326  Callable func;
327  };
328 
329  static void* execute_native_thread_routine(void* p)
330  {
331  thread::Impl_base* t = static_cast<thread::Impl_base*>(p);
333  local.swap(t->this_ptr);
334 
335  try
336  {
337  t->M_id.M_task = ::rt_task_init(0, 0, 0, 0);
338  ::rt_make_hard_real_time();
339  t->run();
340  ::rt_make_soft_real_time();
341  ::rt_task_delete(t->M_id.M_task);
342  }
343  catch (...)
344  {
345  ::std::terminate();
346  }
347 
348  return 0;
349  }
350 
351  template<typename Callable>
352  ::std::shared_ptr<Impl<Callable>> make_routine(Callable&& f)
353  {
354  return ::std::make_shared<Impl<Callable>>(::std::forward<Callable>(f));
355  }
356 
358  {
359  if (!__gthread_active_p())
360  {
361 #if __EXCEPTIONS
362  throw ::std::system_error(::std::make_error_code(::std::errc::operation_not_permitted), "Enable multithreading to use std::thread");
363 #else
364  throw ::std::system_error(::std::error_code(::std::errc::operation_not_permitted, ::std::generic_category()));
365 #endif
366  }
367 
368  b->M_id = this->M_id;
369  b->this_ptr = b;
370  int e = ::pthread_create(&this->M_id.M_thread, nullptr, &thread::execute_native_thread_routine, b.get());
371 
372  if (e)
373  {
374  b->this_ptr.reset();
375  throw ::std::system_error(::std::error_code(e, ::std::generic_category()));
376  }
377  }
378 
379  id M_id;
380  };
381 
382  inline thread::Impl_base::~Impl_base() = default;
383 
384  namespace this_thread
385  {
387  {
388  return thread::id(::pthread_self(), ::rt_buddy());
389  }
390 
391  inline int get_priority()
392  {
393  return ::rt_get_prio(::rt_buddy());
394  }
395 
396  inline int get_priority_max()
397  {
398  return 0;
399  }
400 
401  inline int get_priority_min()
402  {
403  return RT_SCHED_LOWEST_PRIORITY;
404  }
405 
406  inline void set_priority(const int& priority)
407  {
408  int e = ::rt_change_prio(::rt_buddy(), priority);
409 
410  if (e)
411  {
412  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
413  }
414  }
415 
416  template<typename Rep, typename Period>
417  inline void sleep_for(const ::std::chrono::duration<Rep, Period>& rtime)
418  {
419  ::std::chrono::nanoseconds ns = ::std::chrono::duration_cast< ::std::chrono::nanoseconds>(rtime);
420  int e = ::rt_sleep(::nano2count(ns.count()));
421 
422  if (e)
423  {
424  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
425  }
426  }
427 
428  template<typename Duration>
429  inline void sleep_until(const ::std::chrono::time_point<chrono::system_clock, Duration>& atime)
430  {
431  ::std::chrono::time_point<chrono::system_clock, ::std::chrono::nanoseconds> ns = ::std::chrono::time_point_cast< ::std::chrono::nanoseconds>(atime);
432  int e = ::rt_sleep_until(::nano2count(ns.time_since_epoch().count()));
433 
434  if (e)
435  {
436  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
437  }
438  }
439 
440  template<typename Clock, typename Duration>
441  inline void sleep_until(const ::std::chrono::time_point<Clock, Duration>& atime)
442  {
443  sleep_for(atime - Clock::now());
444  }
445 
446  inline void start_timer()
447  {
448  ::rt_set_oneshot_mode();
449  ::start_rt_timer(0);
450  }
451 
452  inline void stop_timer()
453  {
454  ::stop_rt_timer();
455  }
456 
457  inline void wait_period()
458  {
459  int e = ::rt_task_wait_period();
460 
461  if (e)
462  {
463  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
464  }
465  }
466 
467  inline void yield()
468  {
469  int e = ::rt_task_yield();
470 
471  if (e)
472  {
473  throw ::std::system_error(::std::error_code(-e, ::std::generic_category()));
474  }
475  }
476  }
477  }
478  }
479 }
480 
481 namespace std
482 {
483  template<>
485  {
486  size_t operator()(const ::rl::util::rtai::thread::id& id) const
487  {
488  return hash< ::rl::util::rtai::thread::native_handle_type>()(id.M_thread);
489  }
490  };
491 
493  {
494  x.swap(y);
495  }
496 }
497 
498 #endif // RL_UTIL_RTAI_THREAD
rl::util::rtai::thread::swap
void swap(thread &other)
Definition: thread.h:284
rl::util::rtai::chrono::system_clock::now
static time_point now()
Definition: chrono.h:75
rl::util::rtai::thread::start_thread
void start_thread(shared_base_type b)
Definition: thread.h:357
rl::util::rtai::this_thread::get_priority_max
int get_priority_max()
Definition: thread.h:396
rl::util::rtai::thread::id::M_task
RT_TASK * M_task
Definition: thread.h:113
rl::util::rtai::thread::id
Definition: thread.h:49
std::swap
void swap(::rl::util::xenomai::thread &x, ::rl::util::xenomai::thread &y)
Definition: thread.h:497
rl::util::rtai::thread::M_id
id M_id
Definition: thread.h:379
rl::util::rtai::thread::thread
thread(Callable &&f, Args &&... args)
Definition: thread.h:130
rl::util::rtai::thread::thread
thread(thread &&other)
Definition: thread.h:124
rl::util::rtai::thread::joinable
bool joinable() const
Definition: thread.h:194
rl::util::rtai::this_thread::stop_timer
void stop_timer()
Definition: thread.h:452
rl::util::rtai::thread::set_periodic
void set_periodic(const ::std::chrono::time_point< Clock, Duration > &idate, const ::std::chrono::duration< Rep, Period > &period)
Definition: thread.h:255
rl::util::rtai::thread::operator=
thread & operator=(thread &&t)
Definition: thread.h:206
rl::util::rtai::thread::operator=
thread & operator=(const thread &)=delete
rl::util::rtai::this_thread::get_priority
int get_priority()
Definition: thread.h:391
rl::util::rtai::thread::id::id
id(native_handle_type id, RT_TASK *task)
Definition: thread.h:57
rl::util::rtai::this_thread::get_priority_min
int get_priority_min()
Definition: thread.h:401
rl::util::rtai::thread::id::operator<<
friend ::std::basic_ostream< CharT, Traits > & operator<<(::std::basic_ostream< CharT, Traits > &out, thread::id id)
Definition: thread.h:101
rl::util::rtai::thread::detach
void detach()
Definition: thread.h:150
rl::util::rtai::thread::~thread
~thread()
Definition: thread.h:142
rl::util::rtai::thread::id::operator>=
friend bool operator>=(thread::id x, thread::id y)
Definition: thread.h:95
rl::util::rtai::thread::Impl_base::M_id
id M_id
Definition: thread.h:308
rl::util::rtai::thread::shared_base_type
::std::shared_ptr< Impl_base > shared_base_type
Definition: thread.h:298
rl::util::rtai::thread::native_handle_type
pthread_t native_handle_type
Definition: thread.h:46
rl::util::rtai::thread::set_priority
void set_priority(const int &prio)
Definition: thread.h:264
rl::util::rtai::thread::join
void join()
Definition: thread.h:177
rl::util::rtai::thread::swap
friend void swap(thread &lhs, thread &rhs)
Definition: thread.h:290
rl::util::rtai::thread::set_periodic
void set_periodic(const ::std::chrono::duration< Rep, Period > &period)
Definition: thread.h:228
rl::util::rtai::thread::thread
thread(thread &)=delete
rl::util::rtai::thread::get_id
thread::id get_id() const
Definition: thread.h:167
rl::util::rtai::thread::Impl_base::run
virtual void run()=0
rl::util::rtai::thread
Definition: thread.h:44
rl::util::rtai::thread::Impl_base::~Impl_base
virtual ~Impl_base()
rl::util::rtai::this_thread::start_timer
void start_timer()
Definition: thread.h:446
rl::util::rtai::thread::id::M_thread
native_handle_type M_thread
Definition: thread.h:115
rl::util::rtai::thread::Impl_base
Definition: thread.h:303
std::swap
void swap(::rl::util::rtai::thread &x, ::rl::util::rtai::thread &y)
Definition: thread.h:492
rl::util::rtai::thread::thread
thread()=default
chrono.h
rl::util::rtai::thread::thread
thread(const thread &)=delete
rl::util::rtai::this_thread::sleep_until
void sleep_until(const ::std::chrono::time_point< chrono::system_clock, Duration > &atime)
Definition: thread.h:429
rl::util::rtai::thread::hardware_concurrency
static unsigned int hardware_concurrency()
Definition: thread.h:172
rl::util::rtai::thread::id::operator>
friend bool operator>(thread::id x, thread::id y)
Definition: thread.h:90
rl::util::rtai::this_thread::get_id
thread::id get_id()
Definition: thread.h:386
rl::util::rtai::thread::Impl_base::this_ptr
shared_base_type this_ptr
Definition: thread.h:310
rl::util::rtai::thread::Impl::func
Callable func
Definition: thread.h:326
std::hash< ::rl::util::rtai::thread::id >::operator()
size_t operator()(const ::rl::util::rtai::thread::id &id) const
Definition: thread.h:486
rl::util::rtai::thread::id::operator<=
friend bool operator<=(thread::id x, thread::id y)
Definition: thread.h:85
rl::util::rtai::thread::id::operator==
friend bool operator==(thread::id x, thread::id y)
Definition: thread.h:70
std
Definition: thread.h:482
rl::util::rtai::thread::Impl::Impl
Impl(Callable &&f)
Definition: thread.h:316
rl::util::rtai::thread::id::id
id()
Definition: thread.h:51
rl::util::rtai::chrono::system_clock::time_point
::std::chrono::time_point< system_clock, duration > time_point
Definition: chrono.h:69
rl::util::rtai::thread::id::operator!=
friend bool operator!=(thread::id x, thread::id y)
Definition: thread.h:75
rl::util::rtai::this_thread::yield
void yield()
Definition: thread.h:467
rl::util::rtai::thread::Impl
Definition: thread.h:315
rl::util::rtai::thread::suspend
void suspend()
Definition: thread.h:274
rl::util::rtai::thread::Impl::run
void run()
Definition: thread.h:321
rl::util::rtai::thread::native_handle
native_handle_type native_handle()
Definition: thread.h:199
rl::util::rtai::this_thread::wait_period
void wait_period()
Definition: thread.h:457
rl::util::rtai::thread::execute_native_thread_routine
static void * execute_native_thread_routine(void *p)
Definition: thread.h:329
rl::util::rtai::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:241
rl::util::rtai::this_thread::set_priority
void set_priority(const int &priority)
Definition: thread.h:406
rl::util::rtai::thread::id::operator<
friend bool operator<(thread::id x, thread::id y)
Definition: thread.h:80
rl::util::rtai::thread::resume
void resume()
Definition: thread.h:217
rl::util::rtai::this_thread::sleep_for
void sleep_for(const ::std::chrono::duration< Rep, Period > &rtime)
Definition: thread.h:417
rl::util::rtai::thread::make_routine
::std::shared_ptr< Impl< Callable > > make_routine(Callable &&f)
Definition: thread.h:352
rl
Robotics Library.
Definition: AnalogInput.cpp:30