µ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-2023 Liviu Ionescu. All rights reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software
7 * for any purpose is hereby granted, under the terms of the MIT license.
8 *
9 * If a copy of the license was not distributed with this file, it can
10 * be obtained from https://opensource.org/licenses/mit/.
11 */
12
13#ifndef CMSIS_PLUS_RTOS_OS_THREAD_H_
14#define CMSIS_PLUS_RTOS_OS_THREAD_H_
15
16// ----------------------------------------------------------------------------
17
18#if defined(__cplusplus)
19
20// ----------------------------------------------------------------------------
21
22#if defined(OS_USE_OS_APP_CONFIG_H)
23#include <cmsis-plus/os-app-config.h>
24#endif
25
29
30#if !defined(__ARM_EABI__)
31#include <memory>
32#endif
33
34// ----------------------------------------------------------------------------
35
36#pragma GCC diagnostic push
37#if defined(__clang__)
38#pragma clang diagnostic ignored "-Wc++98-compat"
39#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
40#endif
41
42// ----------------------------------------------------------------------------
43
48namespace
49{
50 // Anonymous definition required for the next forward definition.
51 using _func_args_t = void*;
52}
53
54void
56
57#pragma GCC diagnostic push
58#if defined(__clang__)
59#pragma clang diagnostic ignored "-Wc++98-compat"
60#endif
64#pragma GCC diagnostic pop
65
66namespace os
67{
68 namespace rtos
69 {
70 // ------------------------------------------------------------------------
71
72 namespace this_thread
73 {
80 thread&
81 thread (void);
82
87 rtos::thread*
88 _thread (void);
89
101 void
102 yield (void);
103
111 void
112 suspend (void);
113
121 [[noreturn]] void
122 exit (void* exit_ptr = nullptr);
123
139 flags_wait (flags::mask_t mask, flags::mask_t* oflags = nullptr,
141
157 flags::mask_t mask, flags::mask_t* oflags = nullptr,
159
179 flags::mask_t mask, clock::duration_t timeout, flags::mask_t* oflags =
180 nullptr,
182
193 flags_clear (flags::mask_t mask, flags::mask_t* oflags = nullptr);
194
207
208#pragma GCC diagnostic push
209#if defined(__clang__)
210#pragma clang diagnostic ignored "-Wreserved-identifier"
211#endif
216 int*
217 __errno (void);
218#pragma GCC diagnostic pop
219
220 } /* namespace this_thread */
221
222 // Forward definitions required by thread friends.
223 namespace scheduler
224 {
225
226 } /* namespace scheduler */
227
228 // ========================================================================
229
230#pragma GCC diagnostic push
231#if defined(__clang__)
232#pragma clang diagnostic ignored "-Wpadded"
233#elif defined(__GNUC__)
234#pragma GCC diagnostic ignored "-Wpadded"
235#endif
236
243#pragma GCC diagnostic push
244#if defined(__clang__)
245#elif defined(__GNUC__)
246#pragma GCC diagnostic ignored "-Wsuggest-final-methods"
247#pragma GCC diagnostic ignored "-Wsuggest-final-types"
248#endif
250 {
251 public:
252
253 // Must be the very first, for easy access and to keep the
254 // tiny thread used during initialisations to a minimum size.
255 int errno_ = 0;
256
257 public:
258
259 // ======================================================================
260
271 using priority_t = uint8_t;
272
281 struct priority
282 {
297 static constexpr uint32_t range = 4;
298
303 enum
304 : priority_t
305 {
309 none = 0,
310
314 idle = (1 << range),
315
319 lowest = (2 << range),
320
321 low = (2 << range),
322
324
328 normal = (6 << range),
329
331
332 high = (10 << range),
333
334 realtime = (12 << range),
335
339 highest = (((13 + 1) << range) - 1),
340
344 isr = (((14 + 1) << range) - 1),
345
349 error = (((15 + 1) << range) - 1)
350 };
351 }; /* struct priority */
352
356 using state_t = uint8_t;
357
366 struct state
367 {
371 enum
372 : state_t
373 {
377 undefined = 0, //
381 ready = 1, //
385 running = 2, //
389 suspended = 3, //
397 destroyed = 5, //
401 initializing = 6 //
402 };
403 /* enum */
404 }; /* struct state */
405
412 using func_args_t = _func_args_t;
413
420 using func_t = void* (*) (func_args_t args);
421
422 // ======================================================================
423
429 class stack
430 {
431 public:
432
439 using element_t = os::rtos::port::stack::element_t;
440
447 using allocation_element_t = os::rtos::port::stack::allocation_element_t;
448
449 static const element_t magic = os::rtos::port::stack::magic;
450
459 stack ();
460
465 // The rule of five.
466 stack (const stack&) = delete;
467 stack (stack&&) = delete;
468 stack&
469 operator= (const stack&) = delete;
470 stack&
471 operator= (stack&&) = delete;
472
480 ~stack () = default;
481
486 public:
487
500 void
501 clear (void);
502
512 void
513 set (stack::element_t* address, std::size_t size_bytes);
514
522 void
524
532 bottom (void);
533
541 top (void);
542
549 std::size_t
550 size (void);
551
559 bool
560 check_bottom_magic (void);
561
569 bool
570 check_top_magic (void);
571
578 std::size_t
579 available (void);
580
585 public:
586
598 static std::size_t
599 min_size (void);
600
606 static std::size_t
607 min_size (std::size_t size_bytes);
608
615 static std::size_t
616 default_size (void);
617
623 static std::size_t
624 default_size (std::size_t size_bytes);
625
630 protected:
631
636 friend class rtos::thread;
637
638 stack::element_t* bottom_address_;
639 std::size_t size_bytes_;
640
641 static std::size_t min_size_bytes_;
642 static std::size_t default_size_bytes_;
643
648 }; /* class stack */
649
650 // ======================================================================
657 {
658 public:
659
668 context ();
669
674 // The rule of five.
675 context (const context&) = delete;
676 context (context&&) = delete;
677 context&
678 operator= (const context&) = delete;
679 context&
680 operator= (context&&) = delete;
681
689 ~context () = default;
690
695 public:
696
709 stack (void);
710
715 protected:
716
726 friend class rtos::thread;
727 friend class rtos::port::thread;
728 friend void
730 friend void
732
733#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
734
735 friend class port::context;
736
737 friend port::stack::element_t*
738 port::scheduler::switch_stacks (port::stack::element_t* sp);
739
740#endif
749 protected:
750
763 thread::stack stack_;
764
765#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
766
770 port::thread_context_t port_;
771
772#endif
773
782 }; /* class context */
783
784 // ======================================================================
785#pragma GCC diagnostic push
786#if defined(__clang__)
787#pragma clang diagnostic ignored "-Wpadded"
788#elif defined(__GNUC__)
789#pragma GCC diagnostic ignored "-Wpadded"
790#endif
791
798 {
799 public:
800
811 constexpr
812 attributes ();
813
814 // The rule of five.
815 attributes (const attributes&) = default;
816 attributes (attributes&&) = default;
818 operator= (const attributes&) = default;
820 operator= (attributes&&) = default;
821
825 ~attributes () = default;
826
831 public:
832
838 // Public members; no accessors and mutators required.
839 // Warning: must match the type & order of the C file header.
845 void* th_stack_address = nullptr;
846
858 std::size_t th_stack_size_bytes = 0;
859
870
872
873 // Add more attributes here.
874
879 }; /* class attributes */
880
881#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
882 || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
883
890 {
891 public:
902 statistics () = default;
903
908 // The rule of five.
909 statistics (const statistics&) = delete;
910 statistics (statistics&&) = delete;
912 operator= (const statistics&) = delete;
914 operator= (statistics&&) = delete;
915
923 ~statistics () = default;
924
929 public:
930
936#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
937
946 context_switches (void);
947
948#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
949
950#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
951
959 cpu_cycles (void);
960
961#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
962
970 void
971 clear (void);
972
977 protected:
978
983 friend void
984 rtos::scheduler::internal_switch_threads (void);
985
986#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
987 rtos::statistics::counter_t context_switches_ = 0;
988#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
989
990#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
991 rtos::statistics::duration_t cpu_cycles_ = 0;
992#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
993
998 };
999
1000#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
1001
1002#pragma GCC diagnostic pop
1003
1008
1009 // ======================================================================
1010
1015
1028 thread (func_t function, func_args_t args, const attributes& attr =
1030 const allocator_type& allocator = allocator_type ());
1031
1040 thread (const char* name, func_t function, func_args_t args,
1041 const attributes& attr = initializer,
1042 const allocator_type& allocator = allocator_type ());
1043
1044 protected:
1045
1050 // Internal constructors, used from templates.
1051 thread ();
1052 thread (const char* name);
1053
1058 public:
1059
1064 // The rule of five.
1065 thread (const thread&) = delete;
1066 thread (thread&&) = delete;
1067 thread&
1068 operator= (const thread&) = delete;
1069 thread&
1070 operator= (thread&&) = delete;
1071
1079 virtual
1080 ~thread ();
1081
1096 bool
1097 operator== (const thread& rhs) const;
1098
1103 public:
1104
1110 static bool
1112
1125 result_t
1126 cancel (void);
1127
1135 result_t
1136 detach (void);
1137
1144 result_t
1145 join (void** exit_ptr = nullptr);
1146
1147 // Accessors & mutators.
1148
1157 result_t
1158 priority (priority_t prio);
1159
1168 result_t
1170
1178 priority (void);
1179
1187 priority_inherited (void);
1188
1189#if 0
1190 // ???
1191 result_t
1192 set_cancel_state (int, int*);
1193 result_t
1194 set_cancel_type (int, int*);
1195
1196 result_t
1197 get_sched_param (int*, struct sched_param*);
1198 result_t
1199 set_sched_param (int, const struct sched_param*);
1200
1201 //void test_cancel(void);
1202#endif
1203
1204 // TODO: study how to integrate signals and POSIX cancellation.
1212 bool
1213 interrupted (void);
1214
1220 bool
1221 interrupt (bool interrupt = true);
1222
1229 state_t
1230 state (void) const;
1231
1239 void
1240 resume (void);
1241
1248 void*
1249 function_args (void) const;
1250
1251#if defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) || defined(__DOXYGEN__)
1252
1259 os_thread_user_storage_t*
1260 user_storage (void);
1261
1262#endif /* defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) */
1263
1273 result_t
1274 flags_raise (flags::mask_t mask, flags::mask_t* oflags = nullptr);
1275
1276#if defined(OS_INCLUDE_RTOS_THREAD_PUBLIC_FLAGS_CLEAR)
1277
1278 // This is a kludge required to support CMSIS RTOS V1
1279 // public osSignalClear().
1280 result_t
1281 flags_clear (flags::mask_t mask, flags::mask_t* oflags);
1282
1283#endif
1284
1291 result_t
1292 kill (void);
1293
1300 /* class */ thread::stack&
1301 stack (void);
1302
1303#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
1304 || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
1305
1306 /* class */ thread::statistics&
1307 statistics (void);
1308
1309#endif
1310
1315 protected:
1316
1326 friend class mutex;
1327
1328 friend void
1329 this_thread::suspend (void);
1330
1331 friend void
1332 this_thread::exit (void* exit_ptr);
1333
1334 friend result_t
1336 flags::mode_t mode);
1337
1338 friend result_t
1340 flags::mode_t mode);
1341 friend result_t
1343 clock::duration_t timeout,
1344 flags::mask_t* oflags, flags::mode_t mode);
1345
1346 friend result_t
1348
1349 friend flags::mask_t
1351
1352 friend int*
1353 this_thread::__errno (void);
1354
1355 friend void
1356 scheduler::internal_link_node (internal::waiting_threads_list& list,
1358
1359 friend void
1360 scheduler::internal_unlink_node (internal::waiting_thread_node& node);
1361
1362 friend void
1363 scheduler::internal_link_node (
1366 internal::clock_timestamps_list& timeout_list,
1367 internal::timeout_thread_node& timeout_node);
1368
1369 friend void
1370 scheduler::internal_unlink_node (
1372 internal::timeout_thread_node& timeout_node);
1373
1374 friend void
1375 scheduler::internal_switch_threads (void);
1376
1377 friend void
1379
1380 friend void
1382
1383 friend port::stack::element_t*
1384 port::scheduler::switch_stacks (port::stack::element_t* sp);
1385
1386 friend void
1387 ::os_rtos_idle_actions (void);
1388
1389 friend class internal::ready_threads_list;
1390 friend class internal::thread_children_list;
1391 friend class internal::waiting_threads_list;
1394
1395 friend class clock;
1396 friend class condition_variable;
1397 /* friend class mutex; */
1398
1407 protected:
1408
1426 void
1427 internal_construct_ (func_t function, func_args_t args,
1428 const attributes& attr, void* stack_address,
1429 std::size_t stack_size_bytes);
1430
1438 void
1439 internal_suspend_ (void);
1440
1447 [[noreturn]]
1448 void
1449 internal_exit_ (void* exit_ptr = nullptr);
1450
1457 [[noreturn]]
1458 static void
1459 internal_invoke_with_exit_ (thread* thread);
1460
1475 result_t
1476 internal_flags_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1477 flags::mode_t mode);
1478
1492 result_t
1493 internal_flags_try_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1494 flags::mode_t mode);
1495
1513 result_t
1514 internal_flags_timed_wait_ (flags::mask_t mask, clock::duration_t timeout,
1515 flags::mask_t* oflags, flags::mode_t mode);
1516
1528 bool
1529 internal_try_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1530 flags::mode_t mode);
1531
1541 result_t
1542 internal_flags_clear_ (flags::mask_t mask, flags::mask_t* oflags);
1543
1554 internal_flags_get_ (flags::mask_t mask, flags::mode_t mode);
1555
1563 virtual void
1564 internal_destroy_ (void);
1565
1572 void
1573 internal_relink_running_ (void);
1574
1581 void
1582 internal_check_stack_ (void);
1583
1592 protected:
1593
1603 // TODO: make it fully intrusive with computed offset.
1605 { *this };
1606
1607 func_t func_ = nullptr;
1608 func_args_t func_args_ = nullptr;
1609 void* func_result_ = nullptr;
1610
1611 // Pointer to parent, or null for top/detached thread.
1612 thread* parent_ = nullptr;
1613
1614 public:
1615
1616 // Intrusive node used to link this thread to parent list.
1617 utils::double_list_links child_links_;
1618
1619 using threads_list = utils::intrusive_list<
1620 thread, utils::double_list_links, &thread::child_links_>;
1621
1622 // List of children threads. Force a clear.
1623 threads_list children_
1624 { true };
1625
1626 // List of mutexes that this thread owns.
1627 utils::double_list mutexes_;
1628
1629 protected:
1630
1631 // Thread waiting to join.
1632 thread* joiner_ = nullptr;
1633
1634 // Pointer to waiting node (stored on stack)
1635 internal::waiting_thread_node* waiting_node_ = nullptr;
1636
1637 // Pointer to timeout node (stored on stack)
1638 internal::timeout_thread_node* clock_node_ = nullptr;
1639
1643 clock* clock_ = nullptr;
1644
1648 const void* allocator_ = nullptr;
1649
1650 stack::element_t* allocated_stack_address_ = nullptr;
1651
1652 std::size_t allocated_stack_size_elements_ = 0;
1653
1654 // TODO: Add a list, to properly process robustness.
1655 std::size_t volatile acquired_mutexes_ = 0;
1656
1657 // The thread state is set:
1658 // - running - in ready_threads_list::unlink_head()
1659 // - ready - in ready_threads_list::link()
1660 // - waiting - in clock::internal_wait_until(),
1661 // scheduler::internal_link_node()
1662 // thread::_timed_flags_wait()
1663 // - terminated - in state::internal_exit_()
1664 // - destroyed - in thread::internal_destroy_()
1665 // DO NOT initialise here, it is used to check for reuse.
1666 state_t volatile state_; // = state::initializing;
1667
1668 // There are two values used as thread priority. The main one is
1669 // assigned via `priority(int)`, and is stored in `prio_assigned_`.
1670 // This value is normally used by the scheduler.
1671 // However, to prevent priority inversion, mutexes might temporarily
1672 // boost priorities via `priority_inherited(int)`; this second
1673 // value is stored in `prio_inherited_`.
1674
1675 // POSIX: While a thread is holding a mutex which has been
1676 // initialised with the mutex::protocol::inherit or
1677 // mutex::protocol::protect protocol attributes, it shall
1678 // not be subject to being moved to the tail of the scheduling
1679 // queue at its priority in the event that its original
1680 // priority is changed, such as by a POSIX call to sched_setparam().
1681 priority_t volatile prio_assigned_ = priority::none;
1682 priority_t volatile prio_inherited_ = priority::none;
1683
1684 bool volatile interrupted_ = false;
1685
1686 internal::event_flags event_flags_;
1687
1688#if defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) || defined(__DOXYGEN__)
1689 os_thread_user_storage_t user_storage_;
1690#endif /* defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) */
1691
1692#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
1693
1694 class statistics statistics_;
1695
1696#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
1697
1698 // Add other internal data
1699
1700 // Implementation
1701#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1702 friend class port::thread;
1703 os_thread_port_data_t port_;
1704#endif
1705
1706 // Better be the last one!
1707 context context_;
1708
1716 };
1717 /* class thread */
1718#pragma GCC diagnostic pop
1719
1727 template<typename Allocator = memory::allocator<void*>>
1729 {
1730 public:
1731
1735 using allocator_type = Allocator;
1736
1750 thread_allocated (func_t function, func_args_t args,
1751 const attributes& attr = initializer,
1752 const allocator_type& allocator = allocator_type ());
1753
1763 thread_allocated (const char* name, func_t function, func_args_t args,
1764 const attributes& attr = initializer,
1765 const allocator_type& allocator = allocator_type ());
1766
1771 // The rule of five.
1772 thread_allocated (const thread_allocated&) = delete;
1775 operator= (const thread_allocated&) = delete;
1777 operator= (thread_allocated&&) = delete;
1778
1786 virtual
1787 ~thread_allocated () override;
1788
1802 virtual void
1803 internal_destroy_ (void) override;
1804
1813 };
1814
1822 template<std::size_t N = port::stack::default_size_bytes>
1824 {
1825 public:
1826
1830 static const std::size_t stack_size_bytes = N;
1831
1843 thread_inclusive (func_t function, func_args_t args,
1844 const attributes& attr = initializer);
1845
1853 thread_inclusive (const char* name, func_t function, func_args_t args,
1854 const attributes& attr = initializer);
1855
1860 // The rule of five.
1861 thread_inclusive (const thread_inclusive&) = delete;
1864 operator= (const thread_inclusive&) = delete;
1866 operator= (thread_inclusive&&) = delete;
1867
1875 virtual
1876 ~thread_inclusive () override;
1877
1882 private:
1883
1888 stack::allocation_element_t stack_[(stack_size_bytes
1889 + sizeof(stack::allocation_element_t) - 1)
1890 / sizeof(stack::allocation_element_t)];
1891
1896 };
1897
1898#pragma GCC diagnostic pop
1899
1900 } /* namespace rtos */
1901} /* namespace os */
1902
1903// ===== Inline & template implementations ====================================
1904
1905namespace os
1906{
1907 namespace rtos
1908 {
1909 namespace this_thread
1910 {
1926 inline void
1927 suspend (void)
1928 {
1929 this_thread::thread ().internal_suspend_ ();
1930 }
1931
1953 inline result_t
1955 {
1956 return this_thread::thread ().internal_flags_wait_ (mask, oflags, mode);
1957 }
1958
1970 inline result_t
1972 flags::mode_t mode)
1973 {
1974 return this_thread::thread ().internal_flags_try_wait_ (mask, oflags,
1975 mode);
1976 }
1977
2016 inline result_t
2018 flags::mask_t* oflags, flags::mode_t mode)
2019 {
2020 return this_thread::thread ().internal_flags_timed_wait_ (mask, timeout,
2021 oflags, mode);
2022 }
2023
2035 inline flags::mask_t
2037 {
2038 return this_thread::thread ().internal_flags_get_ (mask, mode);
2039 }
2040
2044 inline result_t
2046 {
2047 return this_thread::thread ().internal_flags_clear_ (mask, oflags);
2048 }
2049
2087 inline void
2088 exit (void* exit_ptr)
2089 {
2090 this_thread::thread ().internal_exit_ (exit_ptr);
2091 }
2092
2101 inline int*
2102 __attribute__ ((always_inline))
2103 __errno (void)
2104 {
2105 return &this_thread::thread ().errno_;
2106 }
2107
2108 } /* namespace this_thread */
2109
2110 constexpr
2112 {
2113 }
2114
2115 // ======================================================================
2116
2120 inline
2122 {
2123 clear ();
2124 }
2125
2129 inline void
2131 {
2132 bottom_address_ = nullptr;
2133 size_bytes_ = 0;
2134 }
2135
2139 inline void
2140 thread::stack::set (stack::element_t* address, std::size_t size_bytes)
2141 {
2142 assert (size_bytes >= min_size_bytes_);
2143 bottom_address_ = address;
2144 size_bytes_ = size_bytes;
2145 }
2146
2152 {
2153 return bottom_address_;
2154 }
2155
2161 {
2162 return bottom_address_ + (size_bytes_ / sizeof(element_t));
2163 }
2164
2168 inline std::size_t
2170 {
2171 return size_bytes_;
2172 }
2173
2177 inline bool
2179 {
2180 return *bottom () == stack::magic;
2181 }
2182
2186 inline bool
2188 {
2189 return *top () == stack::magic;
2190 }
2191
2195 inline std::size_t
2197 {
2198 return min_size_bytes_;
2199 }
2200
2204 inline std::size_t
2205 thread::stack::min_size (std::size_t size_bytes)
2206 {
2207 std::size_t tmp = min_size_bytes_;
2208 min_size_bytes_ = size_bytes;
2209 return tmp;
2210 }
2211
2215 inline std::size_t
2217 {
2218 return default_size_bytes_;
2219 }
2220
2224 inline std::size_t
2225 thread::stack::default_size (std::size_t size_bytes)
2226 {
2227 assert (size_bytes != 0);
2228 assert (size_bytes >= min_size_bytes_);
2229
2230 std::size_t tmp = default_size_bytes_;
2231 default_size_bytes_ = size_bytes;
2232 return tmp;
2233 }
2234
2235 // ========================================================================
2236
2240 inline
2242 {
2243 }
2244
2248 inline class thread::stack&
2250 {
2251 return stack_;
2252 }
2253
2254 // ========================================================================
2255
2256#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
2257
2274 {
2275 return context_switches_;
2276 }
2277
2278#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
2279
2280#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
2281
2295 {
2296 return cpu_cycles_;
2297 }
2298
2299#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
2300
2301#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
2302 || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
2303
2316 inline void
2318#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
2319 context_switches_ = 0;
2320#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
2321
2322#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
2323 cpu_cycles_ = 0;
2324#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
2325 }
2326
2327#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
2328 || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
2329
2330 // ========================================================================
2331
2339 inline bool
2340 thread::operator== (const thread& rhs) const
2341 {
2342 return this == &rhs;
2343 }
2344
2348 inline thread::state_t
2349 thread::state (void) const
2350 {
2351 return state_;
2352 }
2353
2357 inline void*
2359 {
2360 return func_args_;
2361 }
2362
2366 inline bool
2368 {
2369 return interrupted_;
2370 }
2371
2372#if defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) || defined(__DOXYGEN__)
2373
2391 inline os_thread_user_storage_t*
2393 {
2394 return &user_storage_;
2395 }
2396
2397#endif /* defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) */
2398
2399#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
2400
2405 // Runs during context switches, on the
2406 // scheduler timer interrupt context, for the thread being
2407 // switched out.
2408 inline void
2409 thread::internal_relink_running_ (void)
2410 {
2411 if (state_ == state::running)
2412 {
2413 // If the current thread is running, add it to the
2414 // ready list, so that it will be resumed later.
2415 internal::waiting_thread_node& crt_node = ready_node_;
2416 if (crt_node.next () == nullptr)
2417 {
2418 rtos::scheduler::ready_threads_list_.link (crt_node);
2419 // Ready state set in above link().
2420 }
2421
2422 // Simple test to verify that the old thread
2423 // did not underflow the stack.
2424 if (!stack ().check_bottom_magic ())
2425 {
2426 // The `\n` is intentional, to make the message more readable,
2427 // since it can occur inside another message.
2428 trace::printf("\n%s() @%p %s\n", __func__, this, name ());
2429 assert (stack ().check_bottom_magic ());
2430 abort ();
2431 }
2432 }
2433 }
2434
2439#endif
2440
2444 inline class thread::stack&
2446 {
2447 return context_.stack_;
2448 }
2449
2450#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
2451
2455 inline class thread::statistics&
2457 {
2458 return statistics_;
2459 }
2460
2461#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
2462
2463#if defined(OS_INCLUDE_RTOS_THREAD_PUBLIC_FLAGS_CLEAR)
2464
2465 inline result_t
2466 thread::flags_clear (flags::mask_t mask, flags::mask_t* oflags)
2467 {
2468 return internal_flags_clear_ (mask, oflags);
2469 }
2470
2471#endif
2472
2473 // ========================================================================
2474
2516 template<typename Allocator>
2517 inline
2519 func_t function, func_args_t args, const attributes& attr,
2520 const allocator_type& allocator) :
2522 { nullptr, function, args, attr, allocator }
2523 {
2524 }
2525
2567 template<typename Allocator>
2569 const char* name, func_t function, func_args_t args,
2570 const attributes& attr, const allocator_type& allocator) :
2571 thread
2572 { name }
2573 {
2574#if defined(OS_TRACE_RTOS_THREAD)
2575 trace::printf ("%s @%p %s\n", __func__, this, this->name ());
2576#endif
2577 if (attr.th_stack_address != nullptr
2578 && attr.th_stack_size_bytes > stack::min_size ())
2579 {
2580 internal_construct_ (function, args, attr, nullptr, 0);
2581 }
2582 else
2583 {
2584 allocator_ = &allocator;
2585
2586 if (attr.th_stack_size_bytes > stack::min_size ())
2587 {
2588 allocated_stack_size_elements_ = (attr.th_stack_size_bytes
2589 + sizeof(typename allocator_type::value_type) - 1)
2590 / sizeof(typename allocator_type::value_type);
2591 }
2592 else
2593 {
2594 allocated_stack_size_elements_ = (stack::default_size ()
2595 + sizeof(typename allocator_type::value_type) - 1)
2596 / sizeof(typename allocator_type::value_type);
2597 }
2598
2599 // The reinterpret_cast<> is required since the allocator
2600 // uses allocation_element_t, which is usually larger.
2601 allocated_stack_address_ =
2602 reinterpret_cast<stack::element_t*> ((const_cast<allocator_type&> (allocator)).allocate (
2603 allocated_stack_size_elements_));
2604
2605 assert (allocated_stack_address_ != nullptr);
2606
2607 internal_construct_ (
2608 function,
2609 args,
2610 attr,
2611 allocated_stack_address_,
2612 allocated_stack_size_elements_
2613 * sizeof(typename allocator_type::value_type));
2614 }
2615 }
2616
2621 template<typename Allocator>
2622 void
2623 thread_allocated<Allocator>::internal_destroy_ (void)
2624 {
2625#if defined(OS_TRACE_RTOS_THREAD)
2626 trace::printf ("thread_allocated::%s() @%p %s\n", __func__, this,
2627 name ());
2628#endif
2629
2630 if (allocated_stack_address_ != nullptr)
2631 {
2632 internal_check_stack_ ();
2633
2634 typedef typename std::allocator_traits<allocator_type>::pointer pointer;
2635
2636#pragma GCC diagnostic push
2637#pragma GCC diagnostic ignored "-Wcast-align"
2638 static_cast<allocator_type*> (const_cast<void*> (allocator_))->deallocate (
2639 reinterpret_cast<pointer> (allocated_stack_address_),
2640 allocated_stack_size_elements_);
2641#pragma GCC diagnostic pop
2642
2643 allocated_stack_address_ = nullptr;
2644 }
2645
2646 thread::internal_destroy_ ();
2647 }
2648
2666 template<typename Allocator>
2668 {
2669#if defined(OS_TRACE_RTOS_THREAD)
2670 trace::printf ("%s @%p %s\n", __func__, this, name ());
2671#endif
2672 }
2673
2674 // ========================================================================
2675
2722 template<std::size_t N>
2723 inline
2725 const attributes& attr) :
2727 { nullptr, function, args, attr }
2728 {
2729 }
2730
2777 template<std::size_t N>
2779 func_args_t args,
2780 const attributes& attr) :
2781 thread
2782 { name }
2783 {
2784#if defined(OS_TRACE_RTOS_THREAD)
2785 trace::printf ("%s @%p %s\n", __func__, this, this->name ());
2786#endif
2787 internal_construct_ (function, args, attr, &stack_, stack_size_bytes);
2788 }
2789
2801 template<std::size_t N>
2803 {
2804#if defined(OS_TRACE_RTOS_THREAD)
2805 trace::printf ("%s @%p %s\n", __func__, this, name ());
2806#endif
2807 }
2808
2809 } /* namespace rtos */
2810} /* namespace os */
2811
2812#pragma GCC diagnostic pop
2813
2814// ----------------------------------------------------------------------------
2815
2816#endif /* __cplusplus */
2817
2818// ----------------------------------------------------------------------------
2819
2820#endif /* CMSIS_PLUS_RTOS_OS_THREAD_H_ */
Generic clock.
Definition os-clocks.h:59
POSIX compliant condition variable.
Definition os-condvar.h:46
Base class for attributes.
Definition os-decls.h:563
Ordered list of time stamp nodes.
Definition os-lists.h:671
Base class for named system objects.
Definition os-decls.h:445
const char * name(void) const
Get object name.
Definition os-decls.h:759
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:223
Double linked list node, with thread reference.
Definition os-lists.h:60
Priority ordered list of threads.
Definition os-lists.h:550
Standard allocator based on the RTOS system default memory manager.
Definition os-memory.h:540
POSIX compliant mutex.
Definition os-mutex.h:53
Thread attributes.
Definition os-thread.h:798
~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:858
priority_t th_priority
Thread initial priority.
Definition os-thread.h:869
constexpr attributes()
Construct a thread attributes object instance.
Definition os-thread.h:2111
void * th_stack_address
Address of the user defined storage for the thread stack.
Definition os-thread.h:845
attributes & operator=(const attributes &)=default
attributes(attributes &&)=default
attributes(const attributes &)=default
context()
Construct a thread context object instance.
Definition os-thread.h:2241
thread::stack & stack(void)
Get the associated stack.
Definition os-thread.h:2249
~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:2187
stack()
Construct a thread stack object instance.
Definition os-thread.h:2121
std::size_t size(void)
Get the stack size.
Definition os-thread.h:2169
os::rtos::port::stack::element_t element_t
Type of a stack element.
Definition os-thread.h:439
stack::element_t * bottom(void)
Get the stack lowest reserved address.
Definition os-thread.h:2151
bool check_bottom_magic(void)
Check if bottom magic word is still there.
Definition os-thread.h:2178
static std::size_t default_size(void)
Get the default stack size.
Definition os-thread.h:2216
static std::size_t min_size(void)
Get the min stack size.
Definition os-thread.h:2196
os::rtos::port::stack::allocation_element_t allocation_element_t
Type of a stack allocation element.
Definition os-thread.h:447
void clear(void)
Clear the stack pointer and size.
Definition os-thread.h:2130
std::size_t available(void)
Compute how much available stack remains.
static const element_t magic
Definition os-thread.h:449
stack::element_t * top(void)
Get the top stack address.
Definition os-thread.h:2160
void set(stack::element_t *address, std::size_t size_bytes)
Set the stack address and size.
Definition os-thread.h:2140
Thread statistics.
Definition os-thread.h:890
rtos::statistics::counter_t context_switches(void)
Get the number of thread context switches.
Definition os-thread.h:2273
rtos::statistics::duration_t cpu_cycles(void)
Get the thread execution time.
Definition os-thread.h:2294
statistics()=default
Construct a thread attributes object instance.
void clear(void)
Clear the thread statistic counters.
Definition os-thread.h:2317
~statistics()=default
Destruct the thread attributes object instance.
Template of a POSIX compliant thread with allocator.
Definition os-thread.h:1729
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:2518
virtual ~thread_allocated() override
Destruct the thread object instance.
Definition os-thread.h:2667
Allocator allocator_type
Standard allocator type definition.
Definition os-thread.h:1735
Template of a POSIX compliant thread with local stack.
Definition os-thread.h:1824
thread_inclusive(func_t function, func_args_t args, const attributes &attr=initializer)
Construct a thread object instance.
Definition os-thread.h:2724
virtual ~thread_inclusive() override
Destruct the thread object instance.
Definition os-thread.h:2802
static const std::size_t stack_size_bytes
Local constant based on template definition.
Definition os-thread.h:1830
POSIX compliant thread, using the default RTOS allocator.
Definition os-thread.h:250
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:2358
uint8_t state_t
Type of variables holding thread states.
Definition os-thread.h:356
void *(*)(func_args_t args) func_t
Type of thread function.
Definition os-thread.h:420
os_thread_user_storage_t * user_storage(void)
Get the user storage.
Definition os-thread.h:2392
void resume(void)
Resume the thread.
static const attributes initializer
Default thread initialiser.
Definition os-thread.h:1007
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:2367
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:412
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:2340
Circular double linked list of nodes.
Definition lists.h:497
List of intrusive nodes.
Definition lists.h:705
Standard thread.
void abort(void)
Definition exit.c:45
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:60
clock_t clock(void)
port::clock::duration_t duration_t
Type of variables holding clock durations.
Definition os-clocks.h:76
allocator_stateless_default_resource< T > allocator
Type of allocator used by the system objects. Must be stateless.
Definition os-types.h:54
uint8_t priority_t
Type of variables holding thread priorities.
Definition os-thread.h:271
@ all
Return when all flags are set.
Definition os-decls.h:293
@ clear
Ask for flags to be cleared after read.
Definition os-decls.h:303
uint32_t mode_t
Type of variables holding flags modes.
Definition os-decls.h:275
uint32_t mask_t
Type of variables holding flags masks.
Definition os-decls.h:265
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:222
uint64_t counter_t
Type of variables holding context switches counters.
Definition os-decls.h:217
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:2017
void suspend(void)
Suspend the current running thread to wait for an event.
Definition os-thread.h:1927
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:1971
void exit(void *exit_ptr=nullptr)
Terminate the current running thread.
Definition os-thread.h:2088
result_t flags_clear(flags::mask_t mask, flags::mask_t *oflags=nullptr)
Clear thread event flags.
Definition os-thread.h:2045
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:2036
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:1954
int * __errno(void)
Implementation of the library __errno() function.
Definition os-thread.h:2103
uint32_t result_t
Type of values returned by RTOS functions.
Definition os-decls.h:96
System namespace.
A namespace for functions applying to the current thread.
void os_rtos_idle_actions(void)
Definition os-idle.cpp:66
Thread priorities.
Definition os-thread.h:282
static constexpr uint32_t range
Priorities pre-scaler.
Definition os-thread.h:297
@ running
Has the CPU and runs.
Definition os-thread.h:385
@ destroyed
Terminated and resources (like stack) released.
Definition os-thread.h:397
@ initializing
Used to check reused threads.
Definition os-thread.h:401
@ terminated
No longer usable, but resources not yet released.
Definition os-thread.h:393
@ ready
Present in the READY list and competing for CPU.
Definition os-thread.h:381
@ undefined
Used to catch uninitialised threads.
Definition os-thread.h:377
@ suspended
Not present in the READY list, waiting for an event.
Definition os-thread.h:389