µ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++ project (https://micro-os-plus.github.io/).
3 * Copyright (c) 2016-2025 Liviu Ionescu. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software
6 * for any purpose is hereby granted, under the terms of the MIT license.
7 *
8 * If a copy of the license was not distributed with this file, it can
9 * be obtained from https://opensource.org/licenses/mit.
10 */
11
12#ifndef CMSIS_PLUS_RTOS_OS_THREAD_H_
13#define CMSIS_PLUS_RTOS_OS_THREAD_H_
14
15// ----------------------------------------------------------------------------
16
17#if defined(__cplusplus)
18
19// ----------------------------------------------------------------------------
20
21#if defined(OS_USE_OS_APP_CONFIG_H)
22#include <cmsis-plus/os-app-config.h>
23#endif
24
28
29#if !defined(__ARM_EABI__)
30#include <memory>
31#endif
32
33// ----------------------------------------------------------------------------
34
35#pragma GCC diagnostic push
36#if defined(__clang__)
37#pragma clang diagnostic ignored "-Wc++98-compat"
38#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
39#endif
40
41// ----------------------------------------------------------------------------
42
47namespace
48{
49 // Anonymous definition required for the next forward definition.
50 using _func_args_t = void*;
51} // namespace
52
53void
55
56#pragma GCC diagnostic push
57#if defined(__clang__)
58#pragma clang diagnostic ignored "-Wc++98-compat"
59#endif
63#pragma GCC diagnostic pop
64
65namespace os
66{
67 namespace rtos
68 {
69 // ------------------------------------------------------------------------
70
71 namespace this_thread
72 {
79 thread&
80 thread (void);
81
86 rtos::thread*
87 _thread (void);
88
100 void
101 yield (void);
102
110 void
111 suspend (void);
112
120 [[noreturn]] void
121 exit (void* exit_ptr = nullptr);
122
138 flags_wait (flags::mask_t mask, flags::mask_t* oflags = nullptr,
140
155 flags_try_wait (flags::mask_t mask, flags::mask_t* oflags = nullptr,
156 flags::mode_t mode
158
179 flags::mask_t* oflags = nullptr,
180 flags::mode_t mode
182
193 flags_clear (flags::mask_t mask, flags::mask_t* oflags = nullptr);
194
208
209#pragma GCC diagnostic push
210#if defined(__clang__)
211#pragma clang diagnostic ignored "-Wreserved-identifier"
212#endif
217 int*
218 __errno (void);
219#pragma GCC diagnostic pop
220
221 } /* namespace this_thread */
222
223 // Forward definitions required by thread friends.
224 namespace scheduler
225 {
226
227 } /* namespace scheduler */
228
229 // ========================================================================
230
231#pragma GCC diagnostic push
232#if defined(__clang__)
233#pragma clang diagnostic ignored "-Wpadded"
234#elif defined(__GNUC__)
235#pragma GCC diagnostic ignored "-Wpadded"
236#endif
237
244#pragma GCC diagnostic push
245#if defined(__clang__)
246#elif defined(__GNUC__)
247#pragma GCC diagnostic ignored "-Wsuggest-final-methods"
248#pragma GCC diagnostic ignored "-Wsuggest-final-types"
249#endif
251 {
252 public:
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
271 using priority_t = uint8_t;
272
282 struct priority
283 {
299 static constexpr uint32_t range = 4;
300
305 enum : priority_t
306 {
310 none = 0,
311
315 idle = (1 << range),
316
320 lowest = (2 << range),
321
322 low = (2 << range),
323
325
329 normal = (6 << range),
330
332
333 high = (10 << range),
334
335 realtime = (12 << range),
336
340 highest = (((13 + 1) << range) - 1),
341
345 isr = (((14 + 1) << range) - 1),
346
350 error = (((15 + 1) << range) - 1)
351 };
352 }; /* struct priority */
353
357 using state_t = uint8_t;
358
368 struct state
369 {
373 enum : state_t
374 {
378 undefined = 0, //
382 ready = 1, //
386 running = 2, //
390 suspended = 3, //
398 destroyed = 5, //
402 initializing = 6 //
403 };
404 /* enum */
405 }; /* struct state */
406
414 using func_args_t = _func_args_t;
415
423 using func_t = void* (*)(func_args_t args);
424
425 // ======================================================================
426
432 class stack
433 {
434 public:
442 using element_t = os::rtos::port::stack::element_t;
443
452 = os::rtos::port::stack::allocation_element_t;
453
454 static const element_t magic = os::rtos::port::stack::magic;
455
464 stack ();
465
470 // The rule of five.
471 stack (const stack&) = delete;
472 stack (stack&&) = delete;
473 stack&
474 operator= (const stack&)
475 = delete;
476 stack&
477 operator= (stack&&)
478 = delete;
479
487 ~stack () = default;
488
493 public:
506 void
507 clear (void);
508
518 void
519 set (stack::element_t* address, std::size_t size_bytes);
520
528 void
530
538 bottom (void);
539
547 top (void);
548
555 std::size_t
556 size (void);
557
565 bool
566 check_bottom_magic (void);
567
575 bool
576 check_top_magic (void);
577
584 std::size_t
585 available (void);
586
591 public:
603 static std::size_t
604 min_size (void);
605
611 static std::size_t
612 min_size (std::size_t size_bytes);
613
620 static std::size_t
621 default_size (void);
622
628 static std::size_t
629 default_size (std::size_t size_bytes);
630
635 protected:
640 friend class rtos::thread;
641
642 stack::element_t* bottom_address_;
643 std::size_t size_bytes_;
644
645 static std::size_t min_size_bytes_;
646 static std::size_t default_size_bytes_;
647
652 }; /* class stack */
653
654 // ======================================================================
661 {
662 public:
671 context ();
672
677 // The rule of five.
678 context (const context&) = delete;
679 context (context&&) = delete;
680 context&
681 operator= (const context&)
682 = delete;
683 context&
684 operator= (context&&)
685 = delete;
686
694 ~context () = default;
695
700 public:
713 stack (void);
714
719 protected:
729 friend class rtos::thread;
730 friend class rtos::port::thread;
731 friend void
733 friend void
735
736#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
737
738 friend class port::context;
739
740 friend port::stack::element_t*
741 port::scheduler::switch_stacks (port::stack::element_t* sp);
742
743#endif
752 protected:
765 thread::stack stack_;
766
767#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
768
772 port::thread_context_t port_;
773
774#endif
775
784 }; /* class context */
785
786 // ======================================================================
787#pragma GCC diagnostic push
788#if defined(__clang__)
789#pragma clang diagnostic ignored "-Wpadded"
790#elif defined(__GNUC__)
791#pragma GCC diagnostic ignored "-Wpadded"
792#endif
793
800 {
801 public:
812 constexpr attributes ();
813
814 // The rule of five.
815 attributes (const attributes&) = default;
816 attributes (attributes&&) = default;
819 = default;
822 = default;
823
827 ~attributes () = default;
828
833 public:
839 // Public members; no accessors and mutators required.
840 // Warning: must match the type & order of the C file header.
847 void* th_stack_address = nullptr;
848
861 std::size_t th_stack_size_bytes = 0;
862
874
876
877 // Add more attributes here.
878
883 }; /* class attributes */
884
885#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
886 || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
887
894 {
895 public:
906 statistics () = default;
907
912 // The rule of five.
913 statistics (const statistics&) = delete;
914 statistics (statistics&&) = delete;
916 operator= (const statistics&)
917 = delete;
919 operator= (statistics&&)
920 = delete;
921
929 ~statistics () = default;
930
935 public:
941#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
942
951 context_switches (void);
952
953#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
954
955#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
956
964 cpu_cycles (void);
965
966#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
967
975 void
976 clear (void);
977
982 protected:
987 friend void
988 rtos::scheduler::internal_switch_threads (void);
989
990#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
991 rtos::statistics::counter_t context_switches_ = 0;
992#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
993
994#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
995 rtos::statistics::duration_t cpu_cycles_ = 0;
996#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
997
1001 };
1002
1003#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) || \
1004 defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
1005
1006#pragma GCC diagnostic pop
1007
1012
1013 // ======================================================================
1014
1019
1033 thread (func_t function, func_args_t args,
1034 const attributes& attr = initializer,
1035 const allocator_type& allocator = allocator_type ());
1036
1046 thread (const char* name, func_t function, func_args_t args,
1047 const attributes& attr = initializer,
1048 const allocator_type& allocator = allocator_type ());
1049
1050 protected:
1055 // Internal constructors, used from templates.
1056 thread ();
1057 thread (const char* name);
1058
1063 public:
1068 // The rule of five.
1069 thread (const thread&) = delete;
1070 thread (thread&&) = delete;
1071 thread&
1072 operator= (const thread&)
1073 = delete;
1074 thread&
1075 operator= (thread&&)
1076 = delete;
1077
1085 virtual ~thread ();
1086
1101 bool
1102 operator== (const thread& rhs) const;
1103
1108 public:
1114 static bool
1115 is_constructed (const thread& thread);
1116
1129 result_t
1130 cancel (void);
1131
1139 result_t
1140 detach (void);
1141
1149 result_t
1150 join (void** exit_ptr = nullptr);
1151
1152 // Accessors & mutators.
1153
1162 result_t
1163 priority (priority_t prio);
1164
1173 result_t
1175
1183 priority (void);
1184
1192 priority_inherited (void);
1193
1194#if 0
1195 // ???
1196 result_t
1197 set_cancel_state (int, int*);
1198 result_t
1199 set_cancel_type (int, int*);
1200
1201 result_t
1202 get_sched_param (int*, struct sched_param*);
1203 result_t
1204 set_sched_param (int, const struct sched_param*);
1205
1206 //void test_cancel(void);
1207#endif
1208
1209 // TODO: study how to integrate signals and POSIX cancellation.
1217 bool
1218 interrupted (void);
1219
1225 bool
1226 interrupt (bool interrupt = true);
1227
1234 state_t
1235 state (void) const;
1236
1244 void
1245 resume (void);
1246
1253 void*
1254 function_args (void) const;
1255
1256#if defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) || defined(__DOXYGEN__)
1257
1264 os_thread_user_storage_t*
1265 user_storage (void);
1266
1267#endif /* defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) */
1268
1278 result_t
1279 flags_raise (flags::mask_t mask, flags::mask_t* oflags = nullptr);
1280
1281#if defined(OS_INCLUDE_RTOS_THREAD_PUBLIC_FLAGS_CLEAR)
1282
1283 // This is a kludge required to support CMSIS RTOS V1
1284 // public osSignalClear().
1285 result_t
1286 flags_clear (flags::mask_t mask, flags::mask_t* oflags);
1287
1288#endif
1289
1296 result_t
1297 kill (void);
1298
1305 /* class */ thread::stack&
1306 stack (void);
1307
1308#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
1309 || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
1310
1311 /* class */ thread::statistics&
1312 statistics (void);
1313
1314#endif
1315
1320 protected:
1330 friend class mutex;
1331
1332 friend void
1333 this_thread::suspend (void);
1334
1335 friend void
1336 this_thread::exit (void* exit_ptr);
1337
1338 friend result_t
1340 flags::mode_t mode);
1341
1342 friend result_t
1344 flags::mode_t mode);
1345 friend result_t
1347 clock::duration_t timeout,
1348 flags::mask_t* oflags,
1349 flags::mode_t mode);
1350
1351 friend result_t
1353
1354 friend flags::mask_t
1356
1357 friend int*
1358 this_thread::__errno (void);
1359
1360 friend void
1361 scheduler::internal_link_node (internal::waiting_threads_list& list,
1363
1364 friend void
1365 scheduler::internal_unlink_node (internal::waiting_thread_node& node);
1366
1367 friend void
1368 scheduler::internal_link_node (
1371 internal::clock_timestamps_list& timeout_list,
1372 internal::timeout_thread_node& timeout_node);
1373
1374 friend void
1375 scheduler::internal_unlink_node (
1377 internal::timeout_thread_node& timeout_node);
1378
1379 friend void
1380 scheduler::internal_switch_threads (void);
1381
1382 friend void
1384
1385 friend void
1387
1388 friend port::stack::element_t*
1389 port::scheduler::switch_stacks (port::stack::element_t* sp);
1390
1391 friend void ::os_rtos_idle_actions (void);
1392
1393 friend class internal::ready_threads_list;
1394 friend class internal::thread_children_list;
1395 friend class internal::waiting_threads_list;
1398
1399 friend class clock;
1400 friend class condition_variable;
1401 /* friend class mutex; */
1402
1411 protected:
1429 void
1430 internal_construct_ (func_t function, func_args_t args,
1431 const attributes& attr, void* stack_address,
1432 std::size_t stack_size_bytes);
1433
1441 void
1442 internal_suspend_ (void);
1443
1450 [[noreturn]]
1451 void
1452 internal_exit_ (void* exit_ptr = nullptr);
1453
1460 [[noreturn]]
1461 static void
1462 internal_invoke_with_exit_ (thread* thread);
1463
1478 result_t
1479 internal_flags_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1480 flags::mode_t mode);
1481
1495 result_t
1496 internal_flags_try_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1497 flags::mode_t mode);
1498
1517 result_t
1518 internal_flags_timed_wait_ (flags::mask_t mask,
1519 clock::duration_t timeout,
1520 flags::mask_t* oflags, flags::mode_t mode);
1521
1533 bool
1534 internal_try_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1535 flags::mode_t mode);
1536
1546 result_t
1547 internal_flags_clear_ (flags::mask_t mask, flags::mask_t* oflags);
1548
1560 internal_flags_get_ (flags::mask_t mask, flags::mode_t mode);
1561
1569 virtual void
1570 internal_destroy_ (void);
1571
1578 void
1579 internal_relink_running_ (void);
1580
1587 void
1588 internal_check_stack_ (void);
1589
1598 protected:
1608 // TODO: make it fully intrusive with computed offset.
1609 internal::waiting_thread_node ready_node_{ *this };
1610
1611 func_t func_ = nullptr;
1612 func_args_t func_args_ = nullptr;
1613 void* func_result_ = nullptr;
1614
1615 // Pointer to parent, or null for top/detached thread.
1616 thread* parent_ = nullptr;
1617
1618 public:
1619 // Intrusive node used to link this thread to parent list.
1620 utils::double_list_links child_links_;
1621
1622 using threads_list
1624 &thread::child_links_>;
1625
1626 // List of children threads. Force a clear.
1627 threads_list children_{ true };
1628
1629 // List of mutexes that this thread owns.
1630 utils::double_list mutexes_;
1631
1632 protected:
1633 // Thread waiting to join.
1634 thread* joiner_ = nullptr;
1635
1636 // Pointer to waiting node (stored on stack)
1637 internal::waiting_thread_node* waiting_node_ = nullptr;
1638
1639 // Pointer to timeout node (stored on stack)
1640 internal::timeout_thread_node* clock_node_ = nullptr;
1641
1645 clock* clock_ = nullptr;
1646
1650 const void* allocator_ = nullptr;
1651
1652 stack::element_t* allocated_stack_address_ = nullptr;
1653
1654 std::size_t allocated_stack_size_elements_ = 0;
1655
1656 // TODO: Add a list, to properly process robustness.
1657 std::size_t volatile acquired_mutexes_ = 0;
1658
1659 // The thread state is set:
1660 // - running - in ready_threads_list::unlink_head()
1661 // - ready - in ready_threads_list::link()
1662 // - waiting - in clock::internal_wait_until(),
1663 // scheduler::internal_link_node()
1664 // thread::_timed_flags_wait()
1665 // - terminated - in state::internal_exit_()
1666 // - destroyed - in thread::internal_destroy_()
1667 // DO NOT initialise here, it is used to check for reuse.
1668 state_t volatile state_; // = state::initializing;
1669
1670 // There are two values used as thread priority. The main one is
1671 // assigned via `priority(int)`, and is stored in `prio_assigned_`.
1672 // This value is normally used by the scheduler.
1673 // However, to prevent priority inversion, mutexes might temporarily
1674 // boost priorities via `priority_inherited(int)`; this second
1675 // value is stored in `prio_inherited_`.
1676
1677 // POSIX: While a thread is holding a mutex which has been
1678 // initialised with the mutex::protocol::inherit or
1679 // mutex::protocol::protect protocol attributes, it shall
1680 // not be subject to being moved to the tail of the scheduling
1681 // queue at its priority in the event that its original
1682 // priority is changed, such as by a POSIX call to sched_setparam().
1683 priority_t volatile prio_assigned_ = priority::none;
1684 priority_t volatile prio_inherited_ = priority::none;
1685
1686 bool volatile interrupted_ = false;
1687
1688 internal::event_flags event_flags_;
1689
1690#if defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) || defined(__DOXYGEN__)
1691 os_thread_user_storage_t user_storage_;
1692#endif /* defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) */
1693
1694#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
1695
1696 class statistics statistics_;
1697
1698#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
1699
1700 // Add other internal data
1701
1702 // Implementation
1703#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1704 friend class port::thread;
1705 os_thread_port_data_t port_;
1706#endif
1707
1708 // Better be the last one!
1709 context context_;
1710
1718 };
1719 /* class thread */
1720#pragma GCC diagnostic pop
1721
1729 template <typename Allocator = memory::allocator<void*>>
1731 {
1732 public:
1736 using allocator_type = Allocator;
1737
1751 thread_allocated (func_t function, func_args_t args,
1752 const attributes& attr = initializer,
1753 const allocator_type& allocator = allocator_type ());
1754
1764 thread_allocated (const char* name, func_t function, func_args_t args,
1765 const attributes& attr = initializer,
1766 const allocator_type& allocator = allocator_type ());
1767
1772 // The rule of five.
1773 thread_allocated (const thread_allocated&) = delete;
1776 operator= (const thread_allocated&)
1777 = delete;
1779 operator= (thread_allocated&&)
1780 = delete;
1781
1789 virtual ~thread_allocated () override;
1790
1804 virtual void
1805 internal_destroy_ (void) override;
1806
1814 };
1815
1823 template <std::size_t N = port::stack::default_size_bytes>
1825 {
1826 public:
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&)
1865 = delete;
1867 operator= (thread_inclusive&&)
1868 = delete;
1869
1877 virtual ~thread_inclusive () override;
1878
1883 private:
1888 stack::allocation_element_t
1889 stack_[(stack_size_bytes + sizeof (stack::allocation_element_t) - 1)
1890 / sizeof (stack::allocation_element_t)];
1891
1895 };
1896
1897#pragma GCC diagnostic pop
1898
1899 } /* namespace rtos */
1900} /* namespace os */
1901
1902// ===== Inline & template implementations ====================================
1903
1904namespace os
1905{
1906 namespace rtos
1907 {
1908 namespace this_thread
1909 {
1925 inline void
1926 suspend (void)
1927 {
1928 this_thread::thread ().internal_suspend_ ();
1929 }
1930
1952 inline result_t
1954 flags::mode_t mode)
1955 {
1956 return this_thread::thread ().internal_flags_wait_ (mask, oflags,
1957 mode);
1958 }
1959
1971 inline result_t
1973 flags::mode_t mode)
1974 {
1975 return this_thread::thread ().internal_flags_try_wait_ (mask, oflags,
1976 mode);
1977 }
1978
2017 inline result_t
2019 flags::mask_t* oflags, flags::mode_t mode)
2020 {
2021 return this_thread::thread ().internal_flags_timed_wait_ (
2022 mask, timeout, oflags, mode);
2023 }
2024
2036 inline flags::mask_t
2038 {
2039 return this_thread::thread ().internal_flags_get_ (mask, mode);
2040 }
2041
2045 inline result_t
2047 {
2048 return this_thread::thread ().internal_flags_clear_ (mask, oflags);
2049 }
2050
2091 inline void
2092 exit (void* exit_ptr)
2093 {
2094 this_thread::thread ().internal_exit_ (exit_ptr);
2095 }
2096
2105 inline int* __attribute__ ((always_inline))
2106 __errno (void)
2107 {
2108 return &this_thread::thread ().errno_;
2109 }
2110
2111 } /* namespace this_thread */
2112
2114 {
2115 }
2116
2117 // ========================================================================
2118
2123 {
2124 clear ();
2125 }
2126
2130 inline void
2132 {
2133 bottom_address_ = nullptr;
2134 size_bytes_ = 0;
2135 }
2136
2140 inline void
2141 thread::stack::set (stack::element_t* address, std::size_t size_bytes)
2142 {
2143 assert (size_bytes >= min_size_bytes_);
2144 bottom_address_ = address;
2145 size_bytes_ = size_bytes;
2146 }
2147
2153 {
2154 return bottom_address_;
2155 }
2156
2162 {
2163#pragma GCC diagnostic push
2164#if defined(__clang__)
2165#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
2166#endif
2167 return bottom_address_ + (size_bytes_ / sizeof (element_t));
2168#pragma GCC diagnostic pop
2169 }
2170
2174 inline std::size_t
2176 {
2177 return size_bytes_;
2178 }
2179
2183 inline bool
2185 {
2186 return *bottom () == stack::magic;
2187 }
2188
2192 inline bool
2194 {
2195 return *top () == stack::magic;
2196 }
2197
2201 inline std::size_t
2203 {
2204 return min_size_bytes_;
2205 }
2206
2210 inline std::size_t
2211 thread::stack::min_size (std::size_t size_bytes)
2212 {
2213 std::size_t tmp = min_size_bytes_;
2214 min_size_bytes_ = size_bytes;
2215 return tmp;
2216 }
2217
2221 inline std::size_t
2223 {
2224 return default_size_bytes_;
2225 }
2226
2230 inline std::size_t
2231 thread::stack::default_size (std::size_t size_bytes)
2232 {
2233 assert (size_bytes != 0);
2234 assert (size_bytes >= min_size_bytes_);
2235
2236 std::size_t tmp = default_size_bytes_;
2237 default_size_bytes_ = size_bytes;
2238 return tmp;
2239 }
2240
2241 // ========================================================================
2242
2247 {
2248 }
2249
2253 inline class thread::stack&
2255 {
2256 return stack_;
2257 }
2258
2259 // ========================================================================
2260
2261#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
2262
2279 {
2280 return context_switches_;
2281 }
2282
2283#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
2284
2285#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
2286
2300 {
2301 return cpu_cycles_;
2302 }
2303
2304#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
2305
2306#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
2307 || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
2308
2321 inline void
2323 {
2324#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
2325 context_switches_ = 0;
2326#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
2327
2328#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
2329 cpu_cycles_ = 0;
2330#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
2331 }
2332
2333#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) \
2334 || defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
2335
2336 // ========================================================================
2337
2345 inline bool
2346 thread::operator== (const thread& rhs) const
2347 {
2348 return this == &rhs;
2349 }
2350
2354 inline thread::state_t
2355 thread::state (void) const
2356 {
2357 return state_;
2358 }
2359
2363 inline void*
2365 {
2366 return func_args_;
2367 }
2368
2372 inline bool
2374 {
2375 return interrupted_;
2376 }
2377
2378#if defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) || defined(__DOXYGEN__)
2379
2397 inline os_thread_user_storage_t*
2399 {
2400 return &user_storage_;
2401 }
2402
2403#endif /* defined(OS_INCLUDE_RTOS_CUSTOM_THREAD_USER_STORAGE) */
2404
2405#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
2406
2411 // Runs during context switches, on the
2412 // scheduler timer interrupt context, for the thread being
2413 // switched out.
2414 inline void
2415 thread::internal_relink_running_ (void)
2416 {
2417 if (state_ == state::running)
2418 {
2419 // If the current thread is running, add it to the
2420 // ready list, so that it will be resumed later.
2421 internal::waiting_thread_node& crt_node = ready_node_;
2422 if (crt_node.next () == nullptr)
2423 {
2424 rtos::scheduler::ready_threads_list_.link (crt_node);
2425 // Ready state set in above link().
2426 }
2427
2428 // Simple test to verify that the old thread
2429 // did not underflow the stack.
2430 if (!stack ().check_bottom_magic ())
2431 {
2432 // The `\n` is intentional, to make the message more readable,
2433 // since it can occur inside another message.
2434 trace::printf ("\n%s() @%p %s\n", __func__, this, name ());
2435 assert (stack ().check_bottom_magic ());
2436 abort ();
2437 }
2438 }
2439 }
2440
2445#endif
2446
2450 inline class thread::stack&
2452 {
2453 return context_.stack_;
2454 }
2455
2456#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
2457
2461 inline class thread::statistics&
2463 {
2464 return statistics_;
2465 }
2466
2467#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
2468
2469#if defined(OS_INCLUDE_RTOS_THREAD_PUBLIC_FLAGS_CLEAR)
2470
2471 inline result_t
2472 thread::flags_clear (flags::mask_t mask, flags::mask_t* oflags)
2473 {
2474 return internal_flags_clear_ (mask, oflags);
2475 }
2476
2477#endif
2478
2479 // ========================================================================
2480
2525 template <typename Allocator>
2527 func_t function, func_args_t args, const attributes& attr,
2528 const allocator_type& allocator)
2529 : thread_allocated{ nullptr, function, args, attr, allocator }
2530 {
2531 }
2532
2577 template <typename Allocator>
2579 const char* name, func_t function, func_args_t args,
2580 const attributes& attr, const allocator_type& allocator)
2581 : thread{ name }
2582 {
2583#if defined(OS_TRACE_RTOS_THREAD)
2584 trace::printf ("%s @%p %s\n", __func__, this, this->name ());
2585#endif
2586 if (attr.th_stack_address != nullptr
2587 && attr.th_stack_size_bytes > stack::min_size ())
2588 {
2589 internal_construct_ (function, args, attr, nullptr, 0);
2590 }
2591 else
2592 {
2593 allocator_ = &allocator;
2594
2595 if (attr.th_stack_size_bytes > stack::min_size ())
2596 {
2597 allocated_stack_size_elements_
2598 = (attr.th_stack_size_bytes
2599 + sizeof (typename allocator_type::value_type) - 1)
2600 / sizeof (typename allocator_type::value_type);
2601 }
2602 else
2603 {
2604 allocated_stack_size_elements_
2605 = (stack::default_size ()
2606 + sizeof (typename allocator_type::value_type) - 1)
2607 / sizeof (typename allocator_type::value_type);
2608 }
2609
2610 // The reinterpret_cast<> is required since the allocator
2611 // uses allocation_element_t, which is usually larger.
2612 allocated_stack_address_ = reinterpret_cast<stack::element_t*> (
2613 (const_cast<allocator_type&> (allocator))
2614 .allocate (allocated_stack_size_elements_));
2615
2616 assert (allocated_stack_address_ != nullptr);
2617
2618 internal_construct_ (
2619 function, args, attr, allocated_stack_address_,
2620 allocated_stack_size_elements_
2621 * sizeof (typename allocator_type::value_type));
2622 }
2623 }
2624
2629 template <typename Allocator>
2630 void
2632 {
2633#if defined(OS_TRACE_RTOS_THREAD)
2634 trace::printf ("thread_allocated::%s() @%p %s\n", __func__, this,
2635 name ());
2636#endif
2637
2638 if (allocated_stack_address_ != nullptr)
2639 {
2640 internal_check_stack_ ();
2641
2642 typedef
2643 typename std::allocator_traits<allocator_type>::pointer pointer;
2644
2645#pragma GCC diagnostic push
2646#pragma GCC diagnostic ignored "-Wcast-align"
2647 static_cast<allocator_type*> (const_cast<void*> (allocator_))
2648 ->deallocate (
2649 reinterpret_cast<pointer> (allocated_stack_address_),
2650 allocated_stack_size_elements_);
2651#pragma GCC diagnostic pop
2652
2653 allocated_stack_address_ = nullptr;
2654 }
2655
2656 thread::internal_destroy_ ();
2657 }
2658
2676 template <typename Allocator>
2678 {
2679#if defined(OS_TRACE_RTOS_THREAD)
2680 trace::printf ("%s @%p %s\n", __func__, this, name ());
2681#endif
2682 }
2683
2684 // ========================================================================
2685
2735 template <std::size_t N>
2737 func_args_t args,
2738 const attributes& attr)
2739 : thread_inclusive<N>{ nullptr, function, args, attr }
2740 {
2741 }
2742
2792 template <std::size_t N>
2794 func_args_t args,
2795 const attributes& attr)
2796 : thread{ name }
2797 {
2798#if defined(OS_TRACE_RTOS_THREAD)
2799 trace::printf ("%s @%p %s\n", __func__, this, this->name ());
2800#endif
2801 internal_construct_ (function, args, attr, &stack_, stack_size_bytes);
2802 }
2803
2815 template <std::size_t N>
2817 {
2818#if defined(OS_TRACE_RTOS_THREAD)
2819 trace::printf ("%s @%p %s\n", __func__, this, name ());
2820#endif
2821 }
2822
2823 } /* namespace rtos */
2824} /* namespace os */
2825
2826#pragma GCC diagnostic pop
2827
2828// ----------------------------------------------------------------------------
2829
2830#endif /* __cplusplus */
2831
2832// ----------------------------------------------------------------------------
2833
2834#endif /* CMSIS_PLUS_RTOS_OS_THREAD_H_ */
Generic clock.
Definition os-clocks.h:61
POSIX compliant condition variable.
Definition os-condvar.h:45
Base class for attributes.
Definition os-decls.h:559
Ordered list of time stamp nodes.
Definition os-lists.h:666
Base class for named system objects.
Definition os-decls.h:443
const char * name(void) const
Get object name.
Definition os-decls.h:753
Priority ordered list of threads waiting too run.
Definition os-lists.h:459
List of children threads.
Definition os-lists.h:393
Double linked list node, with time stamp and thread.
Definition os-lists.h:220
Double linked list node, with thread reference.
Definition os-lists.h:59
Priority ordered list of threads.
Definition os-lists.h:543
Standard allocator based on the RTOS system default memory manager.
Definition os-memory.h:538
POSIX compliant mutex.
Definition os-mutex.h:52
Thread attributes.
Definition os-thread.h:800
~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:861
priority_t th_priority
Thread initial priority.
Definition os-thread.h:873
constexpr attributes()
Construct a thread attributes object instance.
Definition os-thread.h:2113
void * th_stack_address
Address of the user defined storage for the thread stack.
Definition os-thread.h:847
attributes & operator=(const attributes &)=default
attributes(attributes &&)=default
attributes(const attributes &)=default
context()
Construct a thread context object instance.
Definition os-thread.h:2246
thread::stack & stack(void)
Get the associated stack.
Definition os-thread.h:2254
~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:2193
stack()
Construct a thread stack object instance.
Definition os-thread.h:2122
std::size_t size(void)
Get the stack size.
Definition os-thread.h:2175
os::rtos::port::stack::element_t element_t
Type of a stack element.
Definition os-thread.h:442
stack::element_t * bottom(void)
Get the stack lowest reserved address.
Definition os-thread.h:2152
bool check_bottom_magic(void)
Check if bottom magic word is still there.
Definition os-thread.h:2184
static std::size_t default_size(void)
Get the default stack size.
Definition os-thread.h:2222
static std::size_t min_size(void)
Get the min stack size.
Definition os-thread.h:2202
os::rtos::port::stack::allocation_element_t allocation_element_t
Type of a stack allocation element.
Definition os-thread.h:452
void clear(void)
Clear the stack pointer and size.
Definition os-thread.h:2131
std::size_t available(void)
Compute how much available stack remains.
static const element_t magic
Definition os-thread.h:454
stack::element_t * top(void)
Get the top stack address.
Definition os-thread.h:2161
void set(stack::element_t *address, std::size_t size_bytes)
Set the stack address and size.
Definition os-thread.h:2141
Thread statistics.
Definition os-thread.h:894
rtos::statistics::counter_t context_switches(void)
Get the number of thread context switches.
Definition os-thread.h:2278
rtos::statistics::duration_t cpu_cycles(void)
Get the thread execution time.
Definition os-thread.h:2299
statistics()=default
Construct a thread attributes object instance.
void clear(void)
Clear the thread statistic counters.
Definition os-thread.h:2322
~statistics()=default
Destruct the thread attributes object instance.
Template of a POSIX compliant thread with allocator.
Definition os-thread.h:1731
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:2526
virtual ~thread_allocated() override
Destruct the thread object instance.
Definition os-thread.h:2677
Allocator allocator_type
Standard allocator type definition.
Definition os-thread.h:1736
Template of a POSIX compliant thread with local stack.
Definition os-thread.h:1825
thread_inclusive(func_t function, func_args_t args, const attributes &attr=initializer)
Construct a thread object instance.
Definition os-thread.h:2736
virtual ~thread_inclusive() override
Destruct the thread object instance.
Definition os-thread.h:2816
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:251
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:2364
uint8_t state_t
Type of variables holding thread states.
Definition os-thread.h:357
os_thread_user_storage_t * user_storage(void)
Get the user storage.
Definition os-thread.h:2398
void resume(void)
Resume the thread.
static const attributes initializer
Default thread initialiser.
Definition os-thread.h:1011
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:2373
result_t detach(void)
Detach a thread.
result_t cancel(void)
Cancel thread execution.
void *(*)(func_args_t args) func_t
Type of thread function.
Definition os-thread.h:423
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:414
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:2346
Circular double linked list of nodes.
Definition lists.h:488
List of intrusive nodes.
Definition lists.h:690
Standard thread.
void abort(void)
Definition exit.c:43
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:59
clock_t clock(void)
port::clock::duration_t duration_t
Type of variables holding clock durations.
Definition os-clocks.h:78
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:295
@ clear
Ask for flags to be cleared after read.
Definition os-decls.h:305
uint32_t mode_t
Type of variables holding flags modes.
Definition os-decls.h:277
uint32_t mask_t
Type of variables holding flags masks.
Definition os-decls.h:266
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:220
uint64_t counter_t
Type of variables holding context switches counters.
Definition os-decls.h:215
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:2018
void suspend(void)
Suspend the current running thread to wait for an event.
Definition os-thread.h:1926
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:1972
void exit(void *exit_ptr=nullptr)
Terminate the current running thread.
Definition os-thread.h:2092
result_t flags_clear(flags::mask_t mask, flags::mask_t *oflags=nullptr)
Clear thread event flags.
Definition os-thread.h:2046
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:2037
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:1953
int * __errno(void)
Implementation of the library __errno() function.
Definition os-thread.h:2106
uint32_t result_t
Type of values returned by RTOS functions.
Definition os-decls.h:95
System namespace.
A namespace for functions applying to the current thread.
void os_rtos_idle_actions(void)
Definition os-idle.cpp:63
Thread priorities.
Definition os-thread.h:283
static constexpr uint32_t range
Priorities pre-scaler.
Definition os-thread.h:299
@ running
Has the CPU and runs.
Definition os-thread.h:386
@ destroyed
Terminated and resources (like stack) released.
Definition os-thread.h:398
@ initializing
Used to check reused threads.
Definition os-thread.h:402
@ terminated
No longer usable, but resources not yet released.
Definition os-thread.h:394
@ ready
Present in the READY list and competing for CPU.
Definition os-thread.h:382
@ undefined
Used to catch uninitialised threads.
Definition os-thread.h:378
@ suspended
Not present in the READY list, waiting for an event.
Definition os-thread.h:390