µOS++ IIIe Reference 7.0.0
The third edition of µOS++, a POSIX inspired open source framework, written in C++
Loading...
Searching...
No Matches
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
35// ----------------------------------------------------------------------------
36
40
41#if !defined(__ARM_EABI__)
42#include <memory>
43#endif
44
45// ----------------------------------------------------------------------------
46
47#pragma GCC diagnostic push
48
49#if defined(__clang__)
50#pragma clang diagnostic ignored "-Wc++98-compat"
51#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
52#endif
53
54// ----------------------------------------------------------------------------
55
60namespace
61{
62 // Anonymous definition required for the next forward definition.
63 using _func_args_t = void*;
64}
65
66void
68
69#pragma GCC diagnostic push
70#if defined(__clang__)
71#pragma clang diagnostic ignored "-Wc++98-compat"
72#endif
76#pragma GCC diagnostic pop
77
78namespace os
79{
80 namespace rtos
81 {
82 // ------------------------------------------------------------------------
83
84 namespace this_thread
85 {
92 thread&
93 thread (void);
94
99 rtos::thread*
100 _thread (void);
101
113 void
114 yield (void);
115
123 void
124 suspend (void);
125
133 [[noreturn]] void
134 exit (void* exit_ptr = nullptr);
135
151 flags_wait (flags::mask_t mask, flags::mask_t* oflags = nullptr,
153
169 flags::mask_t mask, flags::mask_t* oflags = nullptr,
171
191 flags::mask_t mask, clock::duration_t timeout, flags::mask_t* oflags =
192 nullptr,
194
205 flags_clear (flags::mask_t mask, flags::mask_t* oflags = nullptr);
206
219
224 int*
225 __errno (void);
226
227 } /* namespace this_thread */
228
229 // Forward definitions required by thread friends.
230 namespace scheduler
231 {
232
233 } /* namespace scheduler */
234
235 // ========================================================================
236
237#pragma GCC diagnostic push
238#pragma GCC diagnostic ignored "-Wpadded"
239
247 {
248 public:
249
250 // Must be the very first, for easy access and to keep the
251 // tiny thread used during initialisations to a minimum size.
252 int errno_ = 0;
253
254 public:
255
256 // ======================================================================
257
268 using priority_t = uint8_t;
269
278 struct priority
279 {
294 static constexpr uint32_t range = 4;
295
300 enum
301 : priority_t
302 {
306 none = 0,
307
311 idle = (1 << range),
312
316 lowest = (2 << range),
317
318 low = (2 << range),
319
321
325 normal = (6 << range),
326
328
329 high = (10 << range),
330
331 realtime = (12 << range),
332
336 highest = (((13 + 1) << range) - 1),
337
341 isr = (((14 + 1) << range) - 1),
342
346 error = (((15 + 1) << range) - 1)
347 };
348 }; /* struct priority */
349
353 using state_t = uint8_t;
354
363 struct state
364 {
368 enum
369 : state_t
370 {
374 undefined = 0, //
378 ready = 1, //
382 running = 2, //
386 suspended = 3, //
394 destroyed = 5, //
398 initializing = 6 //
399 };
400 /* enum */
401 }; /* struct state */
402
409 using func_args_t = _func_args_t;
410
417 using func_t = void* (*) (func_args_t args);
418
419 // ======================================================================
420
426 class stack
427 {
428 public:
429
436 using element_t = os::rtos::port::stack::element_t;
437
444 using allocation_element_t = os::rtos::port::stack::allocation_element_t;
445
446 static const element_t magic = os::rtos::port::stack::magic;
447
456 stack ();
457
462 // The rule of five.
463 stack (const stack&) = delete;
464 stack (stack&&) = delete;
465 stack&
466 operator= (const stack&) = delete;
467 stack&
468 operator= (stack&&) = delete;
469
477 ~stack () = default;
478
483 public:
484
497 void
498 clear (void);
499
509 void
510 set (stack::element_t* address, std::size_t size_bytes);
511
519 void
521
529 bottom (void);
530
538 top (void);
539
546 std::size_t
547 size (void);
548
556 bool
557 check_bottom_magic (void);
558
566 bool
567 check_top_magic (void);
568
575 std::size_t
576 available (void);
577
582 public:
583
595 static std::size_t
596 min_size (void);
597
603 static std::size_t
604 min_size (std::size_t size_bytes);
605
612 static std::size_t
613 default_size (void);
614
620 static std::size_t
621 default_size (std::size_t size_bytes);
622
627 protected:
628
633 friend class rtos::thread;
634
635 stack::element_t* bottom_address_;
636 std::size_t size_bytes_;
637
638 static std::size_t min_size_bytes_;
639 static std::size_t default_size_bytes_;
640
645 }; /* class stack */
646
647 // ======================================================================
654 {
655 public:
656
665 context ();
666
671 // The rule of five.
672 context (const context&) = delete;
673 context (context&&) = delete;
674 context&
675 operator= (const context&) = delete;
676 context&
677 operator= (context&&) = delete;
678
686 ~context () = default;
687
692 public:
693
706 stack (void);
707
712 protected:
713
723 friend class rtos::thread;
724 friend class rtos::port::thread;
725 friend void
727 friend void
729
730#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
731
732 friend class port::context;
733
734 friend port::stack::element_t*
735 port::scheduler::switch_stacks (port::stack::element_t* sp);
736
737#endif
746 protected:
747
760 thread::stack stack_;
761
762#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
763
767 port::thread_context_t port_;
768
769#endif
770
779 }; /* class context */
780
781 // ======================================================================
782#pragma GCC diagnostic push
783#pragma GCC diagnostic ignored "-Wpadded"
784
791 {
792 public:
793
804 constexpr
805 attributes ();
806
807 // The rule of five.
808 attributes (const attributes&) = default;
809 attributes (attributes&&) = default;
811 operator= (const attributes&) = default;
813 operator= (attributes&&) = default;
814
818 ~attributes () = default;
819
824 public:
825
831 // Public members; no accessors and mutators required.
832 // Warning: must match the type & order of the C file header.
838 void* th_stack_address = nullptr;
839
851 std::size_t th_stack_size_bytes = 0;
852
863
865
866 // Add more attributes here.
867
872 }; /* class attributes */
873
874#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
875 || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
876
883 {
884 public:
895 statistics () = default;
896
901 // The rule of five.
902 statistics (const statistics&) = delete;
903 statistics (statistics&&) = delete;
905 operator= (const statistics&) = delete;
907 operator= (statistics&&) = delete;
908
916 ~statistics () = default;
917
922 public:
923
929#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
930
939 context_switches (void);
940
941#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
942
943#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
944
952 cpu_cycles (void);
953
954#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
955
963 void
964 clear (void);
965
970 protected:
971
976 friend void
977 rtos::scheduler::internal_switch_threads (void);
978
979#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
980 rtos::statistics::counter_t context_switches_ = 0;
981#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
982
983#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
984 rtos::statistics::duration_t cpu_cycles_ = 0;
985#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
986
991 };
992
993#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
994
995#pragma GCC diagnostic pop
996
1001
1002 // ======================================================================
1003
1008
1021 thread (func_t function, func_args_t args, const attributes& attr =
1023 const allocator_type& allocator = allocator_type ());
1024
1033 thread (const char* name, func_t function, func_args_t args,
1034 const attributes& attr = initializer,
1035 const allocator_type& allocator = allocator_type ());
1036
1037 protected:
1038
1043 // Internal constructors, used from templates.
1044 thread ();
1045 thread (const char* name);
1046
1051 public:
1052
1057 // The rule of five.
1058 thread (const thread&) = delete;
1059 thread (thread&&) = delete;
1060 thread&
1061 operator= (const thread&) = delete;
1062 thread&
1063 operator= (thread&&) = delete;
1064
1072 virtual
1073 ~thread ();
1074
1089 bool
1090 operator== (const thread& rhs) const;
1091
1096 public:
1097
1103 static bool
1105
1118 result_t
1119 cancel (void);
1120
1128 result_t
1129 detach (void);
1130
1137 result_t
1138 join (void** exit_ptr = nullptr);
1139
1140 // Accessors & mutators.
1141
1150 result_t
1151 priority (priority_t prio);
1152
1161 result_t
1163
1171 priority (void);
1172
1180 priority_inherited (void);
1181
1182#if 0
1183 // ???
1184 result_t
1185 set_cancel_state (int, int*);
1186 result_t
1187 set_cancel_type (int, int*);
1188
1189 result_t
1190 get_sched_param (int*, struct sched_param*);
1191 result_t
1192 set_sched_param (int, const struct sched_param*);
1193
1194 //void test_cancel(void);
1195#endif
1196
1197 // TODO: study how to integrate signals and POSIX cancellation.
1205 bool
1206 interrupted (void);
1207
1213 bool
1214 interrupt (bool interrupt = true);
1215
1222 state_t
1223 state (void) const;
1224
1232 void
1233 resume (void);
1234
1241 void*
1242 function_args (void) const;
1243
1244#if defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) || defined(__DOXYGEN__)
1245
1252 os_thread_user_storage_t*
1253 user_storage (void);
1254
1255#endif /* defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) */
1256
1266 result_t
1267 flags_raise (flags::mask_t mask, flags::mask_t* oflags = nullptr);
1268
1269#if defined(OS_INCLUDE_RTOS_THREAD_PUBLIC_FLAGS_CLEAR)
1270
1271 // This is a kludge required to support CMSIS RTOS V1
1272 // public osSignalClear().
1273 result_t
1274 flags_clear (flags::mask_t mask, flags::mask_t* oflags);
1275
1276#endif
1277
1284 result_t
1285 kill (void);
1286
1293 class thread::stack&
1294 stack (void);
1295
1296#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
1297 || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
1298
1299 class thread::statistics&
1300 statistics (void);
1301
1302#endif
1303
1308 protected:
1309
1319 friend class mutex;
1320
1321 friend void
1322 this_thread::suspend (void);
1323
1324 friend void
1325 this_thread::exit (void* exit_ptr);
1326
1327 friend result_t
1329 flags::mode_t mode);
1330
1331 friend result_t
1333 flags::mode_t mode);
1334 friend result_t
1336 clock::duration_t timeout,
1337 flags::mask_t* oflags, flags::mode_t mode);
1338
1339 friend result_t
1341
1342 friend flags::mask_t
1344
1345 friend int*
1346 this_thread::__errno (void);
1347
1348 friend void
1349 scheduler::internal_link_node (internal::waiting_threads_list& list,
1351
1352 friend void
1353 scheduler::internal_unlink_node (internal::waiting_thread_node& node);
1354
1355 friend void
1356 scheduler::internal_link_node (
1359 internal::clock_timestamps_list& timeout_list,
1360 internal::timeout_thread_node& timeout_node);
1361
1362 friend void
1363 scheduler::internal_unlink_node (
1365 internal::timeout_thread_node& timeout_node);
1366
1367 friend void
1368 scheduler::internal_switch_threads (void);
1369
1370 friend void
1372
1373 friend void
1375
1376 friend port::stack::element_t*
1377 port::scheduler::switch_stacks (port::stack::element_t* sp);
1378
1379 friend void
1380 ::os_rtos_idle_actions (void);
1381
1382 friend class internal::ready_threads_list;
1383 friend class internal::thread_children_list;
1384 friend class internal::waiting_threads_list;
1387
1388 friend class clock;
1389 friend class condition_variable;
1390 friend class mutex;
1391
1400 protected:
1401
1419 void
1420 internal_construct_ (func_t function, func_args_t args,
1421 const attributes& attr, void* stack_address,
1422 std::size_t stack_size_bytes);
1423
1431 void
1432 internal_suspend_ (void);
1433
1440 [[noreturn]]
1441 void
1442 internal_exit_ (void* exit_ptr = nullptr);
1443
1450 [[noreturn]]
1451 static void
1452 internal_invoke_with_exit_ (thread* thread);
1453
1468 result_t
1469 internal_flags_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1470 flags::mode_t mode);
1471
1485 result_t
1486 internal_flags_try_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1487 flags::mode_t mode);
1488
1506 result_t
1507 internal_flags_timed_wait_ (flags::mask_t mask, clock::duration_t timeout,
1508 flags::mask_t* oflags, flags::mode_t mode);
1509
1521 bool
1522 internal_try_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1523 flags::mode_t mode);
1524
1534 result_t
1535 internal_flags_clear_ (flags::mask_t mask, flags::mask_t* oflags);
1536
1547 internal_flags_get_ (flags::mask_t mask, flags::mode_t mode);
1548
1556 virtual void
1557 internal_destroy_ (void);
1558
1565 void
1566 internal_relink_running_ (void);
1567
1574 void
1575 internal_check_stack_ (void);
1576
1585 protected:
1586
1596 // TODO: make it fully intrusive with computed offset.
1598 { *this };
1599
1600 func_t func_ = nullptr;
1601 func_args_t func_args_ = nullptr;
1602 void* func_result_ = nullptr;
1603
1604 // Pointer to parent, or null for top/detached thread.
1605 thread* parent_ = nullptr;
1606
1607 public:
1608
1609 // Intrusive node used to link this thread to parent list.
1610 utils::double_list_links child_links_;
1611
1612 using threads_list = utils::intrusive_list<
1613 thread, utils::double_list_links, &thread::child_links_>;
1614
1615 // List of children threads. Force a clear.
1616 threads_list children_
1617 { true };
1618
1619 // List of mutexes that this thread owns.
1620 utils::double_list mutexes_;
1621
1622 protected:
1623
1624 // Thread waiting to join.
1625 thread* joiner_ = nullptr;
1626
1627 // Pointer to waiting node (stored on stack)
1628 internal::waiting_thread_node* waiting_node_ = nullptr;
1629
1630 // Pointer to timeout node (stored on stack)
1631 internal::timeout_thread_node* clock_node_ = nullptr;
1632
1636 clock* clock_ = nullptr;
1637
1641 const void* allocator_ = nullptr;
1642
1643 stack::element_t* allocated_stack_address_ = nullptr;
1644
1645 std::size_t allocated_stack_size_elements_ = 0;
1646
1647 // TODO: Add a list, to properly process robustness.
1648 std::size_t volatile acquired_mutexes_ = 0;
1649
1650 // The thread state is set:
1651 // - running - in ready_threads_list::unlink_head()
1652 // - ready - in ready_threads_list::link()
1653 // - waiting - in clock::internal_wait_until(),
1654 // scheduler::internal_link_node()
1655 // thread::_timed_flags_wait()
1656 // - terminated - in state::internal_exit_()
1657 // - destroyed - in thread::internal_destroy_()
1658 // DO NOT initialise here, it is used to check for reuse.
1659 state_t volatile state_; // = state::initializing;
1660
1661 // There are two values used as thread priority. The main one is
1662 // assigned via `priority(int)`, and is stored in `prio_assigned_`.
1663 // This value is normally used by the scheduler.
1664 // However, to prevent priority inversion, mutexes might temporarily
1665 // boost priorities via `priority_inherited(int)`; this second
1666 // value is stored in `prio_inherited_`.
1667
1668 // POSIX: While a thread is holding a mutex which has been
1669 // initialised with the mutex::protocol::inherit or
1670 // mutex::protocol::protect protocol attributes, it shall
1671 // not be subject to being moved to the tail of the scheduling
1672 // queue at its priority in the event that its original
1673 // priority is changed, such as by a POSIX call to sched_setparam().
1674 priority_t volatile prio_assigned_ = priority::none;
1675 priority_t volatile prio_inherited_ = priority::none;
1676
1677 bool volatile interrupted_ = false;
1678
1679 internal::event_flags event_flags_;
1680
1681#if defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) || defined(__DOXYGEN__)
1682 os_thread_user_storage_t user_storage_;
1683#endif /* defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) */
1684
1685#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
1686
1687 class statistics statistics_;
1688
1689#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
1690
1691 // Add other internal data
1692
1693 // Implementation
1694#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1695 friend class port::thread;
1696 os_thread_port_data_t port_;
1697#endif
1698
1699 // Better be the last one!
1700 context context_;
1701
1709 };
1710 /* class thread */
1711
1719 template<typename Allocator = memory::allocator<void*>>
1721 {
1722 public:
1723
1727 using allocator_type = Allocator;
1728
1742 thread_allocated (func_t function, func_args_t args,
1743 const attributes& attr = initializer,
1744 const allocator_type& allocator = allocator_type ());
1745
1755 thread_allocated (const char* name, func_t function, func_args_t args,
1756 const attributes& attr = initializer,
1757 const allocator_type& allocator = allocator_type ());
1758
1763 // The rule of five.
1764 thread_allocated (const thread_allocated&) = delete;
1767 operator= (const thread_allocated&) = delete;
1769 operator= (thread_allocated&&) = delete;
1770
1778 virtual
1779 ~thread_allocated () override;
1780
1794 virtual void
1795 internal_destroy_ (void) override;
1796
1805 };
1806
1814 template<std::size_t N = port::stack::default_size_bytes>
1816 {
1817 public:
1818
1822 static const std::size_t stack_size_bytes = N;
1823
1835 thread_inclusive (func_t function, func_args_t args,
1836 const attributes& attr = initializer);
1837
1845 thread_inclusive (const char* name, func_t function, func_args_t args,
1846 const attributes& attr = initializer);
1847
1852 // The rule of five.
1853 thread_inclusive (const thread_inclusive&) = delete;
1856 operator= (const thread_inclusive&) = delete;
1858 operator= (thread_inclusive&&) = delete;
1859
1867 virtual
1868 ~thread_inclusive () override;
1869
1874 private:
1875
1880 stack::allocation_element_t stack_[(stack_size_bytes
1881 + sizeof(stack::allocation_element_t) - 1)
1882 / sizeof(stack::allocation_element_t)];
1883
1888 };
1889
1890#pragma GCC diagnostic pop
1891
1892 } /* namespace rtos */
1893} /* namespace os */
1894
1895// ===== Inline & template implementations ====================================
1896
1897namespace os
1898{
1899 namespace rtos
1900 {
1901 namespace this_thread
1902 {
1918 inline void
1919 suspend (void)
1920 {
1921 this_thread::thread ().internal_suspend_ ();
1922 }
1923
1945 inline result_t
1947 {
1948 return this_thread::thread ().internal_flags_wait_ (mask, oflags, mode);
1949 }
1950
1962 inline result_t
1964 flags::mode_t mode)
1965 {
1966 return this_thread::thread ().internal_flags_try_wait_ (mask, oflags,
1967 mode);
1968 }
1969
2008 inline result_t
2010 flags::mask_t* oflags, flags::mode_t mode)
2011 {
2012 return this_thread::thread ().internal_flags_timed_wait_ (mask, timeout,
2013 oflags, mode);
2014 }
2015
2027 inline flags::mask_t
2029 {
2030 return this_thread::thread ().internal_flags_get_ (mask, mode);
2031 }
2032
2036 inline result_t
2038 {
2039 return this_thread::thread ().internal_flags_clear_ (mask, oflags);
2040 }
2041
2079 inline void
2080 exit (void* exit_ptr)
2081 {
2082 this_thread::thread ().internal_exit_ (exit_ptr);
2083 }
2084
2093 inline int*
2094 __attribute__ ((always_inline))
2095 __errno (void)
2096 {
2097 return &this_thread::thread ().errno_;
2098 }
2099
2100 } /* namespace this_thread */
2101
2102 constexpr
2104 {
2105 ;
2106 }
2107
2108 // ======================================================================
2109
2113 inline
2115 {
2116 clear ();
2117 }
2118
2122 inline void
2124 {
2125 bottom_address_ = nullptr;
2126 size_bytes_ = 0;
2127 }
2128
2132 inline void
2133 thread::stack::set (stack::element_t* address, std::size_t size_bytes)
2134 {
2135 assert (size_bytes >= min_size_bytes_);
2136 bottom_address_ = address;
2137 size_bytes_ = size_bytes;
2138 }
2139
2145 {
2146 return bottom_address_;
2147 }
2148
2154 {
2155 return bottom_address_ + (size_bytes_ / sizeof(element_t));
2156 }
2157
2161 inline std::size_t
2163 {
2164 return size_bytes_;
2165 }
2166
2170 inline bool
2172 {
2173 return *bottom () == stack::magic;
2174 }
2175
2179 inline bool
2181 {
2182 return *top () == stack::magic;
2183 }
2184
2188 inline std::size_t
2190 {
2191 return min_size_bytes_;
2192 }
2193
2197 inline std::size_t
2198 thread::stack::min_size (std::size_t size_bytes)
2199 {
2200 std::size_t tmp = min_size_bytes_;
2201 min_size_bytes_ = size_bytes;
2202 return tmp;
2203 }
2204
2208 inline std::size_t
2210 {
2211 return default_size_bytes_;
2212 }
2213
2217 inline std::size_t
2218 thread::stack::default_size (std::size_t size_bytes)
2219 {
2220 assert (size_bytes != 0);
2221 assert (size_bytes >= min_size_bytes_);
2222
2223 std::size_t tmp = default_size_bytes_;
2224 default_size_bytes_ = size_bytes;
2225 return tmp;
2226 }
2227
2228 // ========================================================================
2229
2233 inline
2235 {
2236 ;
2237 }
2238
2242 inline class thread::stack&
2244 {
2245 return stack_;
2246 }
2247
2248 // ========================================================================
2249
2250#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
2251
2268 {
2269 return context_switches_;
2270 }
2271
2272#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
2273
2274#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
2275
2289 {
2290 return cpu_cycles_;
2291 }
2292
2293#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
2294
2295#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
2296 || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
2297
2310 inline void
2312#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
2313 context_switches_ = 0;
2314#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
2315
2316#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
2317 cpu_cycles_ = 0;
2318#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
2319 }
2320
2321#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
2322 || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
2323
2324 // ========================================================================
2325
2333 inline bool
2334 thread::operator== (const thread& rhs) const
2335 {
2336 return this == &rhs;
2337 }
2338
2342 inline thread::state_t
2343 thread::state (void) const
2344 {
2345 return state_;
2346 }
2347
2351 inline void*
2353 {
2354 return func_args_;
2355 }
2356
2360 inline bool
2362 {
2363 return interrupted_;
2364 }
2365
2366#if defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) || defined(__DOXYGEN__)
2367
2385 inline os_thread_user_storage_t*
2387 {
2388 return &user_storage_;
2389 }
2390
2391#endif /* defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) */
2392
2393#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
2394
2399 // Runs during context switches, on the
2400 // scheduler timer interrupt context, for the thread being
2401 // switched out.
2402 inline void
2403 thread::internal_relink_running_ (void)
2404 {
2405 if (state_ == state::running)
2406 {
2407 // If the current thread is running, add it to the
2408 // ready list, so that it will be resumed later.
2409 internal::waiting_thread_node& crt_node = ready_node_;
2410 if (crt_node.next () == nullptr)
2411 {
2412 rtos::scheduler::ready_threads_list_.link (crt_node);
2413 // Ready state set in above link().
2414 }
2415
2416 // Simple test to verify that the old thread
2417 // did not underflow the stack.
2418 if (!stack ().check_bottom_magic ())
2419 {
2420 // The `\n` is intentional, to make the message more readable,
2421 // since it can occur inside another message.
2422 trace::printf("\n%s() @%p %s\n", __func__, this, name ());
2423 assert (stack ().check_bottom_magic ());
2424 }
2425 }
2426 }
2427
2432#endif
2433
2437 inline class thread::stack&
2439 {
2440 return context_.stack_;
2441 }
2442
2443#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
2444
2448 inline class thread::statistics&
2450 {
2451 return statistics_;
2452 }
2453
2454#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
2455
2456#if defined(OS_INCLUDE_RTOS_THREAD_PUBLIC_FLAGS_CLEAR)
2457
2458 inline result_t
2459 thread::flags_clear (flags::mask_t mask, flags::mask_t* oflags)
2460 {
2461 return internal_flags_clear_ (mask, oflags);
2462 }
2463
2464#endif
2465
2466 // ========================================================================
2467
2509 template<typename Allocator>
2510 inline
2512 func_t function, func_args_t args, const attributes& attr,
2513 const allocator_type& allocator) :
2515 { nullptr, function, args, attr, allocator }
2516 {
2517 ;
2518 }
2519
2561 template<typename Allocator>
2563 const char* name, func_t function, func_args_t args,
2564 const attributes& attr, const allocator_type& allocator) :
2565 thread
2566 { name }
2567 {
2568#if defined(OS_TRACE_RTOS_THREAD)
2569 trace::printf ("%s @%p %s\n", __func__, this, this->name ());
2570#endif
2571 if (attr.th_stack_address != nullptr
2572 && attr.th_stack_size_bytes > stack::min_size ())
2573 {
2574 internal_construct_ (function, args, attr, nullptr, 0);
2575 }
2576 else
2577 {
2578 allocator_ = &allocator;
2579
2580 if (attr.th_stack_size_bytes > stack::min_size ())
2581 {
2582 allocated_stack_size_elements_ = (attr.th_stack_size_bytes
2583 + sizeof(typename allocator_type::value_type) - 1)
2584 / sizeof(typename allocator_type::value_type);
2585 }
2586 else
2587 {
2588 allocated_stack_size_elements_ = (stack::default_size ()
2589 + sizeof(typename allocator_type::value_type) - 1)
2590 / sizeof(typename allocator_type::value_type);
2591 }
2592
2593 // The reinterpret_cast<> is required since the allocator
2594 // uses allocation_element_t, which is usually larger.
2595 allocated_stack_address_ =
2596 reinterpret_cast<stack::element_t*> ((const_cast<allocator_type&> (allocator)).allocate (
2597 allocated_stack_size_elements_));
2598
2599 assert (allocated_stack_address_ != nullptr);
2600
2601 internal_construct_ (
2602 function,
2603 args,
2604 attr,
2605 allocated_stack_address_,
2606 allocated_stack_size_elements_
2607 * sizeof(typename allocator_type::value_type));
2608 }
2609 }
2610
2615 template<typename Allocator>
2616 void
2617 thread_allocated<Allocator>::internal_destroy_ (void)
2618 {
2619#if defined(OS_TRACE_RTOS_THREAD)
2620 trace::printf ("thread_allocated::%s() @%p %s\n", __func__, this,
2621 name ());
2622#endif
2623
2624 if (allocated_stack_address_ != nullptr)
2625 {
2626 internal_check_stack_ ();
2627
2628 typedef typename std::allocator_traits<allocator_type>::pointer pointer;
2629
2630 static_cast<allocator_type*> (const_cast<void*> (allocator_))->deallocate (
2631 reinterpret_cast<pointer> (allocated_stack_address_),
2632 allocated_stack_size_elements_);
2633
2634 allocated_stack_address_ = nullptr;
2635 }
2636
2637 thread::internal_destroy_ ();
2638 }
2639
2657 template<typename Allocator>
2659 {
2660#if defined(OS_TRACE_RTOS_THREAD)
2661 trace::printf ("%s @%p %s\n", __func__, this, name ());
2662#endif
2663 }
2664
2665 // ========================================================================
2666
2713 template<std::size_t N>
2714 inline
2716 const attributes& attr) :
2718 { nullptr, function, args, attr }
2719 {
2720 ;
2721 }
2722
2769 template<std::size_t N>
2771 func_args_t args,
2772 const attributes& attr) :
2773 thread
2774 { name }
2775 {
2776#if defined(OS_TRACE_RTOS_THREAD)
2777 trace::printf ("%s @%p %s\n", __func__, this, this->name ());
2778#endif
2779 internal_construct_ (function, args, attr, &stack_, stack_size_bytes);
2780 }
2781
2793 template<std::size_t N>
2795 {
2796#if defined(OS_TRACE_RTOS_THREAD)
2797 trace::printf ("%s @%p %s\n", __func__, this, name ());
2798#endif
2799 }
2800
2801 } /* namespace rtos */
2802} /* namespace os */
2803
2804#pragma GCC diagnostic pop
2805
2806// ----------------------------------------------------------------------------
2807
2808#endif /* __cplusplus */
2809
2810// ----------------------------------------------------------------------------
2811
2812#endif /* CMSIS_PLUS_RTOS_OS_THREAD_H_ */
Generic clock.
Definition os-clocks.h:66
POSIX compliant condition variable.
Definition os-condvar.h:62
Base class for attributes.
Definition os-decls.h:577
Ordered list of time stamp nodes.
Definition os-lists.h:671
Base class for named system objects.
Definition os-decls.h:459
const char * name(void) const
Get object name.
Definition os-decls.h:774
Priority ordered list of threads waiting too run.
Definition os-lists.h:466
List of children threads.
Definition os-lists.h:400
Double linked list node, with time stamp and thread.
Definition os-lists.h:227
Double linked list node, with thread reference.
Definition os-lists.h:72
Priority ordered list of threads.
Definition os-lists.h:550
Standard allocator based on the RTOS system default memory manager.
Definition os-memory.h:544
POSIX compliant mutex.
Definition os-mutex.h:65
Thread attributes.
Definition os-thread.h:791
~attributes()=default
Destruct the thread attributes object instance.
std::size_t th_stack_size_bytes
Size of the user defined storage for the thread stack, in bytes.
Definition os-thread.h:851
priority_t th_priority
Thread initial priority.
Definition os-thread.h:862
constexpr attributes()
Construct a thread attributes object instance.
Definition os-thread.h:2103
void * th_stack_address
Address of the user defined storage for the thread stack.
Definition os-thread.h:838
attributes & operator=(const attributes &)=default
attributes(attributes &&)=default
attributes(const attributes &)=default
context()
Construct a thread context object instance.
Definition os-thread.h:2234
thread::stack & stack(void)
Get the associated stack.
Definition os-thread.h:2243
~context()=default
Destruct the context object instance.
void initialize(void)
Align the pointers and initialise to a known pattern.
~stack()=default
Destruct the stack object instance.
bool check_top_magic(void)
Check if top magic word is still there.
Definition os-thread.h:2180
stack()
Construct a thread stack object instance.
Definition os-thread.h:2114
std::size_t size(void)
Get the stack size.
Definition os-thread.h:2162
os::rtos::port::stack::element_t element_t
Type of a stack element.
Definition os-thread.h:436
stack::element_t * bottom(void)
Get the stack lowest reserved address.
Definition os-thread.h:2144
bool check_bottom_magic(void)
Check if bottom magic word is still there.
Definition os-thread.h:2171
static std::size_t default_size(void)
Get the default stack size.
Definition os-thread.h:2209
static std::size_t min_size(void)
Get the min stack size.
Definition os-thread.h:2189
os::rtos::port::stack::allocation_element_t allocation_element_t
Type of a stack allocation element.
Definition os-thread.h:444
void clear(void)
Clear the stack pointer and size.
Definition os-thread.h:2123
std::size_t available(void)
Compute how much available stack remains.
static const element_t magic
Definition os-thread.h:446
stack::element_t * top(void)
Get the top stack address.
Definition os-thread.h:2153
void set(stack::element_t *address, std::size_t size_bytes)
Set the stack address and size.
Definition os-thread.h:2133
Thread statistics.
Definition os-thread.h:883
rtos::statistics::counter_t context_switches(void)
Get the number of thread context switches.
Definition os-thread.h:2267
rtos::statistics::duration_t cpu_cycles(void)
Get the thread execution time.
Definition os-thread.h:2288
statistics()=default
Construct a thread attributes object instance.
void clear(void)
Clear the thread statistic counters.
Definition os-thread.h:2311
~statistics()=default
Destruct the thread attributes object instance.
Template of a POSIX compliant thread with allocator.
Definition os-thread.h:1721
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:2511
virtual ~thread_allocated() override
Destruct the thread object instance.
Definition os-thread.h:2658
Allocator allocator_type
Standard allocator type definition.
Definition os-thread.h:1727
Template of a POSIX compliant thread with local stack.
Definition os-thread.h:1816
thread_inclusive(func_t function, func_args_t args, const attributes &attr=initializer)
Construct a thread object instance.
Definition os-thread.h:2715
virtual ~thread_inclusive() override
Destruct the thread object instance.
Definition os-thread.h:2794
static const std::size_t stack_size_bytes
Local constant based on template definition.
Definition os-thread.h:1822
POSIX compliant thread, using the default RTOS allocator.
Definition os-thread.h:247
result_t flags_raise(flags::mask_t mask, flags::mask_t *oflags=nullptr)
Raise thread event flags.
result_t kill(void)
Force thread termination.
virtual ~thread()
Destruct the thread object instance.
void * function_args(void) const
Get the thread function arguments.
Definition os-thread.h:2352
uint8_t state_t
Type of variables holding thread states.
Definition os-thread.h:353
void *(*)(func_args_t args) func_t
Type of thread function.
Definition os-thread.h:417
os_thread_user_storage_t * user_storage(void)
Get the user storage.
Definition os-thread.h:2386
void resume(void)
Resume the thread.
static const attributes initializer
Default thread initialiser.
Definition os-thread.h:1000
result_t join(void **exit_ptr=nullptr)
Wait for thread termination.
priority_t priority_inherited(void)
Get the inherited scheduling priority.
bool interrupted(void)
Check if interrupted.
Definition os-thread.h:2361
result_t detach(void)
Detach a thread.
result_t cancel(void)
Cancel thread execution.
bool interrupt(bool interrupt=true)
Set the interrupt flag, possibly interrupting the thread.
_func_args_t func_args_t
Type of thread function arguments.
Definition os-thread.h:409
static bool is_constructed(const thread &thread)
Check if the thread is constructed.
bool operator==(const thread &rhs) const
Compare threads.
Definition os-thread.h:2334
Circular double linked list of nodes.
Definition lists.h:513
List of intrusive nodes.
Definition lists.h:721
Standard thread.
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:74
clock_t clock(void)
port::clock::duration_t duration_t
Type of variables holding clock durations.
Definition os-clocks.h:83
allocator_stateless_default_resource< T > allocator
Type of allocator used by the system objects. Must be stateless.
Definition os-types.h:67
uint8_t priority_t
Type of variables holding thread priorities.
Definition os-thread.h:268
@ all
Return when all flags are set.
Definition os-decls.h:307
@ clear
Ask for flags to be cleared after read.
Definition os-decls.h:317
uint32_t mode_t
Type of variables holding flags modes.
Definition os-decls.h:289
uint32_t mask_t
Type of variables holding flags masks.
Definition os-decls.h:279
stack::element_t * switch_stacks(stack::element_t *sp)
uint64_t duration_t
Type of variables holding durations in CPU cycles.
Definition os-decls.h:236
uint64_t counter_t
Type of variables holding context switches counters.
Definition os-decls.h:231
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:2009
void suspend(void)
Suspend the current running thread to wait for an event.
Definition os-thread.h:1919
thread & thread(void)
Get the current running thread.
void yield(void)
Yield execution to the next ready thread.
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:1963
void exit(void *exit_ptr=nullptr)
Terminate the current running thread.
Definition os-thread.h:2080
result_t flags_clear(flags::mask_t mask, flags::mask_t *oflags=nullptr)
Clear thread event flags.
Definition os-thread.h:2037
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:2028
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:1946
int * __errno(void)
Implementation of the library __errno() function.
Definition os-thread.h:2095
uint32_t result_t
Type of values returned by RTOS functions.
Definition os-decls.h:110
System namespace.
A namespace for functions applying to the current thread.
void os_rtos_idle_actions(void)
Definition os-idle.cpp:76
Thread priorities.
Definition os-thread.h:279
static constexpr uint32_t range
Priorities pre-scaler.
Definition os-thread.h:294
@ running
Has the CPU and runs.
Definition os-thread.h:382
@ destroyed
Terminated and resources (like stack) released.
Definition os-thread.h:394
@ initializing
Used to check reused threads.
Definition os-thread.h:398
@ terminated
No longer usable, but resources not yet released.
Definition os-thread.h:390
@ ready
Present in the READY list and competing for CPU.
Definition os-thread.h:378
@ undefined
Used to catch uninitialised threads.
Definition os-thread.h:374
@ suspended
Not present in the READY list, waiting for an event.
Definition os-thread.h:386