µOS++ IIIe Reference  v6.3.15
“Perfekt ist nicht gut genug”
The third edition of µOS++, a POSIX inspired open source system, written in C++.
os-thread.h
Go to the documentation of this file.
1 /*
2  * This file is part of the µOS++ distribution.
3  * (https://github.com/micro-os-plus)
4  * Copyright (c) 2016 Liviu Ionescu.
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense, and/or
11  * sell copies of the Software, and to permit persons to whom
12  * the Software is furnished to do so, subject to the following
13  * conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  */
27 
28 #ifndef CMSIS_PLUS_RTOS_OS_THREAD_H_
29 #define CMSIS_PLUS_RTOS_OS_THREAD_H_
30 
31 // ----------------------------------------------------------------------------
32 
33 #if defined(__cplusplus)
34 
38 
39 #if !defined(__ARM_EABI__)
40 #include <memory>
41 #endif
42 
43 // ----------------------------------------------------------------------------
44 
49 namespace
50 {
51  // Anonymous definition required for the next forward definition.
52  using _func_args_t = void*;
53 }
54 
55 void
57 
62 namespace os
63 {
64  namespace rtos
65  {
66  // ------------------------------------------------------------------------
67 
68  namespace this_thread
69  {
76  thread&
77  thread (void);
78 
84  _thread (void);
85 
97  void
98  yield (void);
99 
107  void
108  suspend (void);
109 
117  [[noreturn]] void
118  exit (void* exit_ptr = nullptr);
119 
134  result_t
135  flags_wait (flags::mask_t mask, flags::mask_t* oflags = nullptr,
137 
151  result_t
153  flags::mask_t mask, flags::mask_t* oflags = nullptr,
155 
173  result_t
175  flags::mask_t mask, clock::duration_t timeout, flags::mask_t* oflags =
176  nullptr,
178 
188  result_t
189  flags_clear (flags::mask_t mask, flags::mask_t* oflags = nullptr);
190 
201  flags_get (flags::mask_t mask,
203 
208  int*
209  __errno (void);
210 
211  } /* namespace this_thread */
212 
213  // Forward definitions required by thread friends.
214  namespace scheduler
215  {
216 
217  } /* namespace scheduler */
218 
219  // ========================================================================
220 
221 #pragma GCC diagnostic push
222 #pragma GCC diagnostic ignored "-Wpadded"
223 
231  {
232  public:
233 
234  // Must be the very first, for easy access and to keep the
235  // tiny thread used during initialisations to a minimum size.
236  int errno_ = 0;
237 
238  public:
239 
240  // ======================================================================
241 
252  using priority_t = uint8_t;
253 
262  struct priority
263  {
278  static constexpr uint32_t range = 4;
279 
284  enum
285  : priority_t
286  {
290  none = 0,
291 
295  idle = (1 << range),
296 
300  lowest = (2 << range),
301 
302  low = (2 << range),
303 
304  below_normal = (4 << range),
305 
309  normal = (6 << range),
310 
311  above_normal = (8 << range),
312 
313  high = (10 << range),
314 
315  realtime = (12 << range),
316 
320  highest = (((13 + 1) << range) - 1),
321 
325  isr = (((14 + 1) << range) - 1),
326 
330  error = (((15 + 1) << range) - 1)
331  };
332  }; /* struct priority */
333 
337  using state_t = uint8_t;
338 
347  struct state
348  {
352  enum
353  : state_t
354  {
358  undefined = 0, //
362  ready = 1, //
366  running = 2, //
370  suspended = 3, //
374  terminated = 4, //
378  destroyed = 5
379  };
380  /* enum */
381  }; /* struct state */
382 
389  using func_args_t = _func_args_t;
390 
397  using func_t = void* (*) (func_args_t args);
398 
399  // ======================================================================
400 
406  class stack
407  {
408  public:
409 
416  using element_t = os::rtos::port::stack::element_t;
417 
424  using allocation_element_t = os::rtos::port::stack::allocation_element_t;
425 
426  static const element_t magic = os::rtos::port::stack::magic;
427 
436  stack ();
437 
442  // The rule of five.
443  stack (const stack&) = delete;
444  stack (stack&&) = delete;
445  stack&
446  operator= (const stack&) = delete;
447  stack&
448  operator= (stack&&) = delete;
449 
457  ~stack () = default;
458 
463  public:
464 
477  void
478  clear (void);
479 
489  void
490  set (stack::element_t* address, std::size_t size_bytes);
491 
499  void
500  initialize (void);
501 
509  bottom (void);
510 
518  top (void);
519 
526  std::size_t
527  size (void);
528 
536  bool
537  check_bottom_magic (void);
538 
546  bool
547  check_top_magic (void);
548 
555  std::size_t
556  available (void);
557 
562  public:
563 
575  static std::size_t
576  min_size (void);
577 
583  static std::size_t
584  min_size (std::size_t size_bytes);
585 
592  static std::size_t
593  default_size (void);
594 
600  static std::size_t
601  default_size (std::size_t size_bytes);
602 
607  protected:
608 
613  friend class rtos::thread;
614 
615  stack::element_t* bottom_address_;
616  std::size_t size_bytes_;
617 
618  static std::size_t min_size_bytes_;
619  static std::size_t default_size_bytes_;
620 
625  }; /* class stack */
626 
627  // ======================================================================
633  class context
634  {
635  public:
636 
645  context ();
646 
651  // The rule of five.
652  context (const context&) = delete;
653  context (context&&) = delete;
654  context&
655  operator= (const context&) = delete;
656  context&
657  operator= (context&&) = delete;
658 
666  ~context () = default;
667 
672  public:
673 
686  stack (void);
687 
692  protected:
693 
703  friend class rtos::thread;
704  friend class rtos::port::thread;
705  friend void
706  port::scheduler::start (void);
707  friend void
709 
710 #if !defined(OS_USE_RTOS_PORT_SCHEDULER)
711 
712  friend class port::context;
713 
714  friend port::stack::element_t*
715  port::scheduler::switch_stacks (port::stack::element_t* sp);
716 
717 #endif
718 
726  protected:
727 
740  thread::stack stack_;
741 
742 #if !defined(OS_USE_RTOS_PORT_SCHEDULER)
743 
747  port::thread_context_t port_;
748 
749 #endif
750 
759  }; /* class context */
760 
761  // ======================================================================
762 #pragma GCC diagnostic push
763 #pragma GCC diagnostic ignored "-Wpadded"
764 
771  {
772  public:
773 
784  constexpr
785  attributes ();
786 
787  // The rule of five.
788  attributes (const attributes&) = default;
789  attributes (attributes&&) = default;
790  attributes&
791  operator= (const attributes&) = default;
792  attributes&
793  operator= (attributes&&) = default;
794 
798  ~attributes () = default;
799 
804  public:
805 
811  // Public members; no accessors and mutators required.
812  // Warning: must match the type & order of the C file header.
818  void* th_stack_address = nullptr;
819 
831  std::size_t th_stack_size_bytes = 0;
832 
842  priority_t th_priority = priority::normal;
843 
844  // Add more attributes here.
845 
850  }; /* class attributes */
851 
852 #if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
853  || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
854 
861  {
862  public:
873  statistics () = default;
874 
879  // The rule of five.
880  statistics (const statistics&) = delete;
881  statistics (statistics&&) = delete;
882  statistics&
883  operator= (const statistics&) = delete;
884  statistics&
885  operator= (statistics&&) = delete;
886 
894  ~statistics () = default;
895 
900  public:
901 
907 #if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
908 
917  context_switches (void);
918 
919 #endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
920 
921 #if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
922 
930  cpu_cycles (void);
931 
932 #endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
933 
938  protected:
939 
944  friend void
945  rtos::scheduler::internal_switch_threads (void);
946 
947 #if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
948  rtos::statistics::counter_t context_switches_ = 0;
949 #endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
950 
951 #if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
952  rtos::statistics::duration_t cpu_cycles_ = 0;
953 #endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
954 
959  };
960 
961 #endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
962 
963 #pragma GCC diagnostic pop
964 
968  static const attributes initializer;
969 
970  // ======================================================================
971 
976 
989  thread (func_t function, func_args_t args, const attributes& attr =
990  initializer,
992 
1001  thread (const char* name, func_t function, func_args_t args,
1002  const attributes& attr = initializer,
1004 
1005  protected:
1006 
1011  // Internal constructors, used from templates.
1012  thread ();
1013  thread (const char* name);
1014 
1019  public:
1020 
1025  // The rule of five.
1026  thread (const thread&) = delete;
1027  thread (thread&&) = delete;
1028  thread&
1029  operator= (const thread&) = delete;
1030  thread&
1031  operator= (thread&&) = delete;
1032 
1040  virtual
1041  ~thread ();
1042 
1057  bool
1058  operator== (const thread& rhs) const;
1059 
1064  public:
1065 
1078  result_t
1079  cancel (void);
1080 
1088  result_t
1089  detach (void);
1090 
1097  result_t
1098  join (void** exit_ptr = nullptr);
1099 
1100  // Accessors & mutators.
1101 
1110  result_t
1111  priority (priority_t prio);
1112 
1121  result_t
1122  priority_inherited (priority_t prio);
1123 
1130  priority_t
1131  priority (void);
1132 
1139  priority_t
1140  priority_inherited (void);
1141 
1142 #if 0
1143  // ???
1144  result_t
1145  set_cancel_state (int, int*);
1146  result_t
1147  set_cancel_type (int, int*);
1148 
1149  result_t
1150  get_sched_param (int*, struct sched_param*);
1151  result_t
1152  set_sched_param (int, const struct sched_param*);
1153 
1154  //void test_cancel(void);
1155 #endif
1156 
1157  // TODO: study how to integrate signals and POSIX cancellation.
1165  bool
1166  interrupted (void);
1167 
1173  bool
1174  interrupt (bool interrupt = true);
1175 
1182  state_t
1183  state (void) const;
1184 
1191  void
1192  resume (void);
1193 
1200  void*
1201  function_args (void) const;
1202 
1203 #if defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) || defined(__DOXYGEN__)
1204 
1211  os_thread_user_storage_t*
1212  user_storage (void);
1213 
1214 #endif /* defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) */
1215 
1225  result_t
1226  flags_raise (flags::mask_t mask, flags::mask_t* oflags = nullptr);
1227 
1228 #if defined(OS_INCLUDE_RTOS_THREAD_PUBLIC_FLAGS_CLEAR)
1229 
1230  // This is a kludge required to support CMSIS RTOS V1
1231  // public osSignalClear().
1232  result_t
1233  flags_clear (flags::mask_t mask, flags::mask_t* oflags);
1234 
1235 #endif
1236 
1243  result_t
1244  kill (void);
1245 
1252  class thread::stack&
1253  stack (void);
1254 
1255 #if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
1256  || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
1257 
1258  class thread::statistics&
1259  statistics (void);
1260 
1261 #endif
1262 
1267  protected:
1268 
1278  friend class mutex;
1279 
1280  friend void
1281  this_thread::suspend (void);
1282 
1283  friend void
1284  this_thread::exit (void* exit_ptr);
1285 
1286  friend result_t
1288  flags::mode_t mode);
1289 
1290  friend result_t
1292  flags::mode_t mode);
1293  friend result_t
1295  clock::duration_t timeout,
1296  flags::mask_t* oflags, flags::mode_t mode);
1297 
1298  friend result_t
1300 
1301  friend flags::mask_t
1303 
1304  friend int*
1305  this_thread::__errno (void);
1306 
1307  friend void
1308  scheduler::internal_link_node (internal::waiting_threads_list& list,
1310 
1311  friend void
1312  scheduler::internal_unlink_node (internal::waiting_thread_node& node);
1313 
1314  friend void
1315  scheduler::internal_link_node (
1318  internal::clock_timestamps_list& timeout_list,
1319  internal::timeout_thread_node& timeout_node);
1320 
1321  friend void
1322  scheduler::internal_unlink_node (
1324  internal::timeout_thread_node& timeout_node);
1325 
1326  friend void
1327  scheduler::internal_switch_threads (void);
1328 
1329  friend void
1331 
1332  friend void
1333  port::scheduler::start (void);
1334 
1335  friend port::stack::element_t*
1336  port::scheduler::switch_stacks (port::stack::element_t* sp);
1337 
1338  friend void
1340 
1341  friend class internal::ready_threads_list;
1342  friend class internal::thread_children_list;
1343  friend class internal::waiting_threads_list;
1344  friend class internal::clock_timestamps_list;
1345  friend class internal::terminated_threads_list;
1346 
1347  friend class clock;
1348  friend class condition_variable;
1349  friend class mutex;
1350 
1359  protected:
1360 
1378  void
1379  internal_construct_ (func_t function, func_args_t args,
1380  const attributes& attr, void* stack_address,
1381  std::size_t stack_size_bytes);
1382 
1390  void
1391  internal_suspend_ (void);
1392 
1398  [[noreturn]]
1399  void
1400  internal_exit_ (void* exit_ptr = nullptr);
1401 
1408  [[noreturn]]
1409  static void
1410  internal_invoke_with_exit_ (thread* thread);
1411 
1426  result_t
1427  internal_flags_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1428  flags::mode_t mode);
1429 
1443  result_t
1444  internal_flags_try_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1445  flags::mode_t mode);
1446 
1464  result_t
1465  internal_flags_timed_wait_ (flags::mask_t mask, clock::duration_t timeout,
1466  flags::mask_t* oflags, flags::mode_t mode);
1467 
1479  bool
1480  internal_try_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1481  flags::mode_t mode);
1482 
1492  result_t
1493  internal_flags_clear_ (flags::mask_t mask, flags::mask_t* oflags);
1494 
1505  internal_flags_get_ (flags::mask_t mask, flags::mode_t mode);
1506 
1514  virtual void
1515  internal_destroy_ (void);
1516 
1523  void
1524  internal_relink_running_ (void);
1525 
1532  void
1533  internal_check_stack_ (void);
1534 
1543  protected:
1544 
1554  // TODO: make it fully intrusive with computed offset.
1555  internal::waiting_thread_node ready_node_
1556  { *this };
1557 
1558  func_t func_ = nullptr;
1559  func_args_t func_args_ = nullptr;
1560  void* func_result_ = nullptr;
1561 
1562  // Pointer to parent, or null for top/detached thread.
1563  thread* parent_ = nullptr;
1564 
1565  public:
1566 
1567  // Intrusive node used to link this thread to parent list.
1568  utils::double_list_links child_links_;
1569 
1570  using threads_list = utils::intrusive_list<
1571  thread, utils::double_list_links, &thread::child_links_>;
1572 
1573  // List of children threads. Force a clear.
1574  threads_list children_
1575  { true };
1576 
1577  // List of mutexes that this thread owns.
1578  utils::double_list mutexes_;
1579 
1580  protected:
1581 
1582  // Thread waiting to join.
1583  thread* joiner_ = nullptr;
1584 
1585  // Pointer to waiting node (stored on stack)
1586  internal::waiting_thread_node* waiting_node_ = nullptr;
1587 
1588  // Pointer to timeout node (stored on stack)
1589  internal::timeout_thread_node* clock_node_ = nullptr;
1590 
1594  clock* clock_ = nullptr;
1595 
1599  const void* allocator_ = nullptr;
1600 
1601  stack::element_t* allocated_stack_address_ = nullptr;
1602 
1603  std::size_t allocated_stack_size_elements_ = 0;
1604 
1605  // TODO: Add a list, to properly process robustness.
1606  std::size_t volatile acquired_mutexes_ = 0;
1607 
1608  // The thread state is set:
1609  // - running - in ready_threads_list::unlink_head()
1610  // - ready - in ready_threads_list::link()
1611  // - waiting - in clock::internal_wait_until(),
1612  // scheduler::internal_link_node()
1613  // thread::_timed_flags_wait()
1614  // - terminated - in state::internal_exit_()
1615  // - destroyed - in thread::internal_destroy_()
1616  state_t volatile state_ = state::undefined;
1617 
1618  // There are two values used as thread priority. The main one is
1619  // assigned via `priority(int)`, and is stored in `prio_assigned_`.
1620  // This value is normally used by the scheduler.
1621  // However, to prevent priority inversion, mutexes might temporarily
1622  // boost priorities via `priority_inherited(int)`; this second
1623  // value is stored in `prio_inherited_`.
1624 
1625  // POSIX: While a thread is holding a mutex which has been
1626  // initialised with the mutex::protocol::inherit or
1627  // mutex::protocol::protect protocol attributes, it shall
1628  // not be subject to being moved to the tail of the scheduling
1629  // queue at its priority in the event that its original
1630  // priority is changed, such as by a POSIX call to sched_setparam().
1631  priority_t volatile prio_assigned_ = priority::none;
1632  priority_t volatile prio_inherited_ = priority::none;
1633 
1634  bool volatile interrupted_ = false;
1635 
1636  internal::event_flags event_flags_;
1637 
1638 #if defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) || defined(__DOXYGEN__)
1639  os_thread_user_storage_t user_storage_;
1640 #endif /* defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) */
1641 
1642 #if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
1643 
1644  class statistics statistics_;
1645 
1646 #endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
1647 
1648  // Add other internal data
1649 
1650  // Implementation
1651 #if defined(OS_USE_RTOS_PORT_SCHEDULER)
1652  friend class port::thread;
1653  os_thread_port_data_t port_;
1654 #endif
1655 
1656  // Better be the last one!
1657  context context_;
1658 
1666  };
1667  /* class thread */
1668 
1676  template<typename Allocator = memory::allocator<void*>>
1677  class thread_allocated : public thread
1678  {
1679  public:
1680 
1684  using allocator_type = Allocator;
1685 
1699  thread_allocated (func_t function, func_args_t args,
1700  const attributes& attr = initializer,
1702 
1712  thread_allocated (const char* name, func_t function, func_args_t args,
1713  const attributes& attr = initializer,
1715 
1720  // The rule of five.
1721  thread_allocated (const thread_allocated&) = delete;
1722  thread_allocated (thread_allocated&&) = delete;
1724  operator= (const thread_allocated&) = delete;
1726  operator= (thread_allocated&&) = delete;
1727 
1735  virtual
1736  ~thread_allocated () override;
1737 
1751  virtual void
1752  internal_destroy_ (void) override;
1753 
1762  };
1763 
1771  template<std::size_t N = port::stack::default_size_bytes>
1772  class thread_inclusive : public thread
1773  {
1774  public:
1775 
1779  static const std::size_t stack_size_bytes = N;
1780 
1792  thread_inclusive (func_t function, func_args_t args,
1793  const attributes& attr = initializer);
1794 
1802  thread_inclusive (const char* name, func_t function, func_args_t args,
1803  const attributes& attr = initializer);
1804 
1809  // The rule of five.
1810  thread_inclusive (const thread_inclusive&) = delete;
1811  thread_inclusive (thread_inclusive&&) = delete;
1813  operator= (const thread_inclusive&) = delete;
1815  operator= (thread_inclusive&&) = delete;
1816 
1824  virtual
1825  ~thread_inclusive ();
1826 
1831  private:
1832 
1837  stack::allocation_element_t stack_[(stack_size_bytes
1838  + sizeof(stack::allocation_element_t) - 1)
1839  / sizeof(stack::allocation_element_t)];
1840 
1845  };
1846 
1847 #pragma GCC diagnostic pop
1848 
1849  } /* namespace rtos */
1850 } /* namespace os */
1851 
1852 // ===== Inline & template implementations ====================================
1853 
1854 namespace os
1855 {
1856  namespace rtos
1857  {
1858  namespace this_thread
1859  {
1875  inline void
1876  suspend (void)
1877  {
1878  this_thread::thread ().internal_suspend_ ();
1879  }
1880 
1902  inline result_t
1904  {
1905  return this_thread::thread ().internal_flags_wait_ (mask, oflags, mode);
1906  }
1907 
1919  inline result_t
1921  flags::mode_t mode)
1922  {
1923  return this_thread::thread ().internal_flags_try_wait_ (mask, oflags,
1924  mode);
1925  }
1926 
1965  inline result_t
1967  flags::mask_t* oflags, flags::mode_t mode)
1968  {
1969  return this_thread::thread ().internal_flags_timed_wait_ (mask, timeout,
1970  oflags, mode);
1971  }
1972 
1984  inline flags::mask_t
1986  {
1987  return this_thread::thread ().internal_flags_get_ (mask, mode);
1988  }
1989 
1995  inline result_t
1997  {
1998  return this_thread::thread ().internal_flags_clear_ (mask, oflags);
1999  }
2000 
2038  inline void
2039  exit (void* exit_ptr)
2040  {
2041  this_thread::thread ().internal_exit_ (exit_ptr);
2042  }
2043 
2052  inline int*
2053  __attribute__ ((always_inline))
2054  __errno (void)
2055  {
2056  return &this_thread::thread ().errno_;
2057  }
2058 
2059  } /* namespace this_thread */
2060 
2061  constexpr
2063  {
2064  ;
2065  }
2066 
2067  // ======================================================================
2068 
2074  inline
2076  {
2077  clear ();
2078  }
2079 
2085  inline void
2087  {
2088  bottom_address_ = nullptr;
2089  size_bytes_ = 0;
2090  }
2091 
2097  inline void
2098  thread::stack::set (stack::element_t* address, std::size_t size_bytes)
2099  {
2100  assert (size_bytes >= min_size_bytes_);
2101  bottom_address_ = address;
2102  size_bytes_ = size_bytes;
2103  }
2104 
2110  inline thread::stack::element_t*
2112  {
2113  return bottom_address_;
2114  }
2115 
2121  inline thread::stack::element_t*
2123  {
2124  return bottom_address_ + (size_bytes_ / sizeof(element_t));
2125  }
2126 
2132  inline std::size_t
2134  {
2135  return size_bytes_;
2136  }
2137 
2143  inline bool
2145  {
2146  return *bottom () == stack::magic;
2147  }
2148 
2154  inline bool
2156  {
2157  return *top () == stack::magic;
2158  }
2159 
2165  inline std::size_t
2167  {
2168  return min_size_bytes_;
2169  }
2170 
2176  inline std::size_t
2177  thread::stack::min_size (std::size_t size_bytes)
2178  {
2179  std::size_t tmp = min_size_bytes_;
2180  min_size_bytes_ = size_bytes;
2181  return tmp;
2182  }
2183 
2189  inline std::size_t
2191  {
2192  return default_size_bytes_;
2193  }
2194 
2200  inline std::size_t
2201  thread::stack::default_size (std::size_t size_bytes)
2202  {
2203  assert (size_bytes != 0);
2204  assert (size_bytes >= min_size_bytes_);
2205 
2206  std::size_t tmp = default_size_bytes_;
2207  default_size_bytes_ = size_bytes;
2208  return tmp;
2209  }
2210 
2211  // ========================================================================
2212 
2218  inline
2220  {
2221  ;
2222  }
2223 
2229  inline class thread::stack&
2231  {
2232  return stack_;
2233  }
2234 
2235  // ========================================================================
2236 
2237 #if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
2238 
2253  inline statistics::counter_t
2255  {
2256  return context_switches_;
2257  }
2258 
2259 #endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
2260 
2261 #if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
2262 
2277  {
2278  return cpu_cycles_;
2279  }
2280 
2281 #endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
2282 
2283  // ========================================================================
2284 
2292  inline bool
2293  thread::operator== (const thread& rhs) const
2294  {
2295  return this == &rhs;
2296  }
2297 
2303  inline thread::state_t
2304  thread::state (void) const
2305  {
2306  return state_;
2307  }
2308 
2314  inline void*
2316  {
2317  return func_args_;
2318  }
2319 
2325  inline bool
2327  {
2328  return interrupted_;
2329  }
2330 
2331 #if defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) || defined(__DOXYGEN__)
2332 
2350  inline os_thread_user_storage_t*
2352  {
2353  return &user_storage_;
2354  }
2355 
2356 #endif /* defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) */
2357 
2358 #if !defined(OS_USE_RTOS_PORT_SCHEDULER)
2359 
2364  inline void
2365  thread::internal_relink_running_ (void)
2366  {
2367  if (state_ == state::running)
2368  {
2369  // If the current thread is running, add it to the
2370  // ready list, so that it will be resumed later.
2371  internal::waiting_thread_node& crt_node = ready_node_;
2372  if (crt_node.next () == nullptr)
2373  {
2374  rtos::scheduler::ready_threads_list_.link (crt_node);
2375  // Ready state set in above link().
2376  }
2377 
2378  // Simple test to verify that the old thread
2379  // did not underflow the stack.
2380  assert (stack ().check_bottom_magic ());
2381  }
2382  }
2383 
2388 #endif
2389 
2395  inline class thread::stack&
2397  {
2398  return context_.stack_;
2399  }
2400 
2401 #if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
2402 
2408  inline class thread::statistics&
2410  {
2411  return statistics_;
2412  }
2413 
2414 #endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
2415 
2416 #if defined(OS_INCLUDE_RTOS_THREAD_PUBLIC_FLAGS_CLEAR)
2417 
2418  inline result_t
2420  {
2421  return internal_flags_clear_ (mask, oflags);
2422  }
2423 
2424 #endif
2425 
2426  // ========================================================================
2427 
2469  template<typename Allocator>
2470  inline
2472  func_t function, func_args_t args, const attributes& attr,
2473  const allocator_type& allocator) :
2475  { nullptr, function, args, attr, allocator }
2476  {
2477  ;
2478  }
2479 
2521  template<typename Allocator>
2523  const char* name, func_t function, func_args_t args,
2524  const attributes& attr, const allocator_type& allocator) :
2525  thread
2526  { name }
2527  {
2528 #if defined(OS_TRACE_RTOS_THREAD)
2529  trace::printf ("%s @%p %s\n", __func__, this, this->name ());
2530 #endif
2531  if (attr.th_stack_address != nullptr
2532  && attr.th_stack_size_bytes > stack::min_size ())
2533  {
2534  internal_construct_ (function, args, attr, nullptr, 0);
2535  }
2536  else
2537  {
2538  allocator_ = &allocator;
2539 
2540  if (attr.th_stack_size_bytes > stack::min_size ())
2541  {
2542  allocated_stack_size_elements_ = (attr.th_stack_size_bytes
2543  + sizeof(typename allocator_type::value_type) - 1)
2544  / sizeof(typename allocator_type::value_type);
2545  }
2546  else
2547  {
2548  allocated_stack_size_elements_ = (stack::default_size ()
2549  + sizeof(typename allocator_type::value_type) - 1)
2550  / sizeof(typename allocator_type::value_type);
2551  }
2552 
2553  // The reinterpret_cast<> is required since the allocator
2554  // uses allocation_element_t, which is usually larger.
2555  allocated_stack_address_ =
2556  reinterpret_cast<stack::element_t*> ((const_cast<allocator_type&> (allocator)).allocate (
2557  allocated_stack_size_elements_));
2558 
2559  assert (allocated_stack_address_ != nullptr);
2560 
2561  internal_construct_ (
2562  function,
2563  args,
2564  attr,
2565  allocated_stack_address_,
2566  allocated_stack_size_elements_
2567  * sizeof(typename allocator_type::value_type));
2568  }
2569  }
2570 
2575  template<typename Allocator>
2576  void
2578  {
2579 #if defined(OS_TRACE_RTOS_THREAD)
2580  trace::printf ("thread_allocated::%s() @%p %s\n", __func__, this,
2581  name ());
2582 #endif
2583 
2584  if (allocated_stack_address_ != nullptr)
2585  {
2586  internal_check_stack_ ();
2587 
2588  typedef typename std::allocator_traits<allocator_type>::pointer pointer;
2589 
2590  static_cast<allocator_type*> (const_cast<void*> (allocator_))->deallocate (
2591  reinterpret_cast<pointer> (allocated_stack_address_),
2592  allocated_stack_size_elements_);
2593 
2594  allocated_stack_address_ = nullptr;
2595  }
2596 
2597  thread::internal_destroy_ ();
2598  }
2599 
2617  template<typename Allocator>
2619  {
2620 #if defined(OS_TRACE_RTOS_THREAD)
2621  trace::printf ("%s @%p %s\n", __func__, this, name ());
2622 #endif
2623  }
2624 
2625  // ========================================================================
2626 
2673  template<std::size_t N>
2674  inline
2676  const attributes& attr) :
2677  thread_inclusive<N>
2678  { nullptr, function, args, attr }
2679  {
2680  ;
2681  }
2682 
2729  template<std::size_t N>
2731  func_args_t args,
2732  const attributes& attr) :
2733  thread
2734  { name }
2735  {
2736 #if defined(OS_TRACE_RTOS_THREAD)
2737  trace::printf ("%s @%p %s\n", __func__, this, this->name ());
2738 #endif
2739  internal_construct_ (function, args, attr, &stack_, stack_size_bytes);
2740  }
2741 
2753  template<std::size_t N>
2755  {
2756 #if defined(OS_TRACE_RTOS_THREAD)
2757  trace::printf ("%s @%p %s\n", __func__, this, name ());
2758 #endif
2759  }
2760 
2761  } /* namespace rtos */
2762 } /* namespace os */
2763 
2764 // ----------------------------------------------------------------------------
2765 
2766 #endif /* __cplusplus */
2767 
2768 #endif /* CMSIS_PLUS_RTOS_OS_THREAD_H_ */
Thread attributes.
Definition: os-thread.h:770
static const attributes initializer
Default thread initialiser.
Definition: os-thread.h:968
void os_rtos_idle_actions(void)
Definition: os-idle.cpp:70
Thread stack.
Definition: os-thread.h:406
static std::size_t default_size(void)
Get the default stack size.
Definition: os-thread.h:2190
bool check_top_magic(void)
Check if top magic word is still there.
Definition: os-thread.h:2155
void * function_args(void) const
Get the thread function arguments.
Definition: os-thread.h:2315
class thread::stack * stack(void)
Get the interrupts stack.
Definition: os-core.cpp:562
List of intrusive nodes.
Definition: lists.h:708
void start(void)
Start the RTOS scheduler.
Definition: os-core.cpp:186
virtual ~thread_allocated() override
Destruct the thread object instance.
Definition: os-thread.h:2618
void yield(void)
Yield execution to the next ready thread.
Definition: os-thread.cpp:1564
void exit(void *exit_ptr=nullptr)
Terminate the current running thread.
Definition: os-thread.h:2039
void initialize(void)
Definition: trace.cpp:50
os_thread_user_storage_t * user_storage(void)
Get the user storage.
Definition: os-thread.h:2351
void deallocate(value_type *addr, std::size_t elements) noexcept
Deallocate the number of memory blocks of type value_type.
Definition: os-memory.h:1500
Priority ordered list of threads.
Definition: os-lists.h:536
POSIX compliant mutex.
Definition: os-mutex.h:53
Ask for flags to be cleared after read.
Definition: os-decls.h:303
Double linked list node, with thread reference.
Definition: os-lists.h:58
uint8_t state_t
Type of variables holding thread states.
Definition: os-thread.h:337
int * __errno(void)
Implementation of the library __errno() function.
Definition: os-thread.h:2054
stack::element_t * top(void)
Get the top stack address.
Definition: os-thread.h:2122
void clear(void)
Clear the stack pointer and size.
Definition: os-thread.h:2086
Base class for attributes.
Definition: os-decls.h:562
std::size_t size(void)
Get the stack size.
Definition: os-thread.h:2133
System namespace.
Template of a POSIX compliant thread with local stack.
Definition: os-thread.h:1772
Double linked list node, with time stamp and thread.
Definition: os-lists.h:213
void set(stack::element_t *address, std::size_t size_bytes)
Set the stack address and size.
Definition: os-thread.h:2098
os::rtos::port::stack::element_t element_t
Type of a stack element.
Definition: os-thread.h:416
stack::element_t * switch_stacks(stack::element_t *sp)
result_t flags_try_wait(flags::mask_t mask, flags::mask_t *oflags=nullptr, flags::mode_t mode=flags::mode::all|flags::mode::clear)
Try to wait for thread event flags.
Definition: os-thread.h:1920
Thread statistics.
Definition: os-thread.h:860
bool operator==(thread::id x, thread::id y) noexcept
Standard thread.
stack::element_t * bottom(void)
Get the stack lowest reserved address.
Definition: os-thread.h:2111
virtual ~thread_inclusive()
Destruct the thread object instance.
Definition: os-thread.h:2754
constexpr attributes()
Construct a thread attributes object instance.
Definition: os-thread.h:2062
Internal event flags implementation.
Definition: os-flags.h:51
rtos::statistics::duration_t cpu_cycles(void)
Get the thread execution time.
Definition: os-thread.h:2276
os::rtos::port::stack::allocation_element_t allocation_element_t
Type of a stack allocation element.
Definition: os-thread.h:424
const char * name(void) const
Get object name.
Definition: os-decls.h:760
Base class for named system objects.
Definition: os-decls.h:444
uint8_t priority_t
Type of variables holding thread priorities.
Definition: os-thread.h:252
context()
Construct a thread context object instance.
Definition: os-thread.h:2219
Priority ordered list of threads waiting too run.
Definition: os-lists.h:452
A namespace for functions applying to the current thread.
POSIX compliant thread, using the default RTOS allocator.
Definition: os-thread.h:230
port::clock::duration_t duration_t
Type of variables holding clock durations.
Definition: os-clocks.h:72
POSIX compliant condition variable.
Definition: os-condvar.h:51
stack()
Construct a thread stack object instance.
Definition: os-thread.h:2075
thread_allocated(func_t function, func_args_t args, const attributes &attr=initializer, const allocator_type &allocator=allocator_type())
Construct a thread object instance.
Definition: os-thread.h:2471
Return when all flags are set.
Definition: os-decls.h:293
rtos::statistics::counter_t context_switches(void)
Get the total number of context switches.
Definition: os-sched.h:1044
state_t state(void) const
Get thread scheduler state.
Definition: os-thread.h:2304
class thread::statistics & statistics(void)
Definition: os-thread.h:2409
flags::mask_t flags_get(flags::mask_t mask, flags::mode_t mode=flags::mode::all|flags::mode::clear)
Get/clear thread event flags.
Definition: os-thread.h:1985
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition: trace.cpp:74
class thread::stack & stack(void)
Get the thread context stack.
Definition: os-thread.h:2396
Template of a POSIX compliant thread with allocator.
Definition: os-thread.h:1677
static const std::size_t stack_size_bytes
Local constant based on template definition.
Definition: os-thread.h:1779
thread::stack & stack(void)
Get the associated stack.
Definition: os-thread.h:2230
void suspend(void)
Suspend the current running thread to wait for an event.
Definition: os-thread.h:1876
thread_inclusive(func_t function, func_args_t args, const attributes &attr=initializer)
Construct a thread object instance.
Definition: os-thread.h:2675
bool check_bottom_magic(void)
Check if bottom magic word is still there.
Definition: os-thread.h:2144
rtos::statistics::counter_t context_switches(void)
Get the number of thread context switches.
Definition: os-thread.h:2254
T value_type
Type of elements to be allocated.
Definition: os-memory.h:539
Thread priorities.
Definition: os-thread.h:262
Thread states.
Definition: os-thread.h:347
Unordered list of threads.
Definition: os-lists.h:739
static std::size_t min_size(void)
Get the min stack size.
Definition: os-thread.h:2166
result_t flags_clear(flags::mask_t mask, flags::mask_t *oflags=nullptr)
Clear thread event flags.
Definition: os-thread.h:1996
result_t flags_timed_wait(flags::mask_t mask, clock::duration_t timeout, flags::mask_t *oflags=nullptr, flags::mode_t mode=flags::mode::all|flags::mode::clear)
Timed wait for thread event flags.
Definition: os-thread.h:1966
uint64_t counter_t
Type of variables holding context switches counters.
Definition: os-decls.h:217
Circular double linked list of nodes.
Definition: lists.h:500
Ordered list of time stamp nodes.
Definition: os-lists.h:657
Generic clock.
Definition: os-clocks.h:54
void *(*)(func_args_t args) func_t
Type of thread function.
Definition: os-thread.h:397
thread & thread(void)
Get the current running thread.
Definition: os-thread.cpp:1543
uint32_t mask_t
Type of variables holding flags masks.
Definition: os-decls.h:265
Thread context.
Definition: os-thread.h:633
List of children threads.
Definition: os-lists.h:386
uint32_t mode_t
Type of variables holding flags modes.
Definition: os-decls.h:275
result_t flags_wait(flags::mask_t mask, flags::mask_t *oflags=nullptr, flags::mode_t mode=flags::mode::all|flags::mode::clear)
Wait for thread event flags.
Definition: os-thread.h:1903
uint32_t result_t
Type of values returned by RTOS functions.
Definition: os-decls.h:96
bool operator==(const thread &rhs) const
Compare threads.
Definition: os-thread.h:2293
allocator_stateless_default_resource< T > allocator
Type of allocator used by the system objects. Must be stateless.
Definition: os-types.h:57
Standard allocator based on the RTOS system default memory manager.
Definition: os-decls.h:82
_func_args_t func_args_t
Type of thread function arguments.
Definition: os-thread.h:389
bool interrupted(void)
Check if interrupted.
Definition: os-thread.h:2326
uint64_t duration_t
Type of variables holding durations in CPU cycles.
Definition: os-decls.h:222
int kill(pid_t pid, int sig)
rtos::statistics::duration_t cpu_cycles(void)
Get the total duration of all threads.
Definition: os-sched.h:1069