1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_system/config.h"
16 #include "pw_thread/thread.h"
17
18 // For now, pw_system:async only supports FreeRTOS or standard library threads.
19 //
20 // This file will be rewritten once the SEED-0128 generic thread creation APIs
21 // are available. Details of the threads owned by pw_system should be an
22 // internal implementation detail. If configuration is necessary, it can be
23 // exposed through regular config options, rather than requiring users to
24 // implement functions.
25
26 #if __has_include("FreeRTOS.h")
27
28 #include "FreeRTOS.h"
29 #include "pw_thread_freertos/options.h"
30 #include "task.h"
31
32 namespace pw::system {
33 namespace {
34
ToWords(size_t bytes)35 constexpr size_t ToWords(size_t bytes) {
36 return (bytes + sizeof(StackType_t) - 1) / sizeof(StackType_t);
37 }
38
39 } // namespace
40
StartScheduler()41 [[noreturn]] void StartScheduler() {
42 vTaskStartScheduler();
43 PW_UNREACHABLE;
44 }
45
46 // Low to high priorities.
47 enum class ThreadPriority : UBaseType_t {
48 kDispatcher = tskIDLE_PRIORITY + 1,
49 // TODO(amontanez): These should ideally be at different priority levels, but
50 // there's synchronization issues when they are.
51 kWorkQueue = kDispatcher,
52 kLog = kDispatcher,
53 kRpc = kDispatcher,
54 kTransfer = kDispatcher,
55 kNumPriorities,
56 };
57
58 static_assert(static_cast<UBaseType_t>(ThreadPriority::kNumPriorities) <=
59 configMAX_PRIORITIES);
60
LogThreadOptions()61 const thread::Options& LogThreadOptions() {
62 static thread::freertos::StaticContextWithStack<ToWords(
63 kLogThreadStackSizeBytes)>
64 context;
65 static constexpr auto options =
66 pw::thread::freertos::Options()
67 .set_name("LogThread")
68 .set_static_context(context)
69 .set_priority(static_cast<UBaseType_t>(ThreadPriority::kLog));
70 return options;
71 }
72
RpcThreadOptions()73 const thread::Options& RpcThreadOptions() {
74 static thread::freertos::StaticContextWithStack<ToWords(
75 kRpcThreadStackSizeBytes)>
76 context;
77 static constexpr auto options =
78 pw::thread::freertos::Options()
79 .set_name("RpcThread")
80 .set_static_context(context)
81 .set_priority(static_cast<UBaseType_t>(ThreadPriority::kRpc));
82 return options;
83 }
84
TransferThreadOptions()85 const thread::Options& TransferThreadOptions() {
86 static thread::freertos::StaticContextWithStack<ToWords(
87 kTransferThreadStackSizeBytes)>
88 context;
89 static constexpr auto options =
90 pw::thread::freertos::Options()
91 .set_name("TransferThread")
92 .set_static_context(context)
93 .set_priority(static_cast<UBaseType_t>(ThreadPriority::kTransfer));
94 return options;
95 }
96
DispatcherThreadOptions()97 const thread::Options& DispatcherThreadOptions() {
98 static thread::freertos::StaticContextWithStack<ToWords(
99 kDispatcherThreadStackSizeBytes)>
100 context;
101 static constexpr auto options =
102 pw::thread::freertos::Options()
103 .set_name("DispatcherThread")
104 .set_static_context(context)
105 .set_priority(static_cast<UBaseType_t>(ThreadPriority::kDispatcher));
106 return options;
107 }
108
WorkQueueThreadOptions()109 const thread::Options& WorkQueueThreadOptions() {
110 static thread::freertos::StaticContextWithStack<ToWords(
111 kWorkQueueThreadStackSizeBytes)>
112 context;
113 static constexpr auto options =
114 pw::thread::freertos::Options()
115 .set_name("WorkQueueThread")
116 .set_static_context(context)
117 .set_priority(static_cast<UBaseType_t>(ThreadPriority::kWorkQueue));
118 return options;
119 }
120
121 } // namespace pw::system
122
123 #else // STL
124
125 #include <chrono>
126 #include <thread>
127
128 #include "pw_thread_stl/options.h"
129
130 namespace pw::system {
131 namespace {
132
133 thread::stl::Options stl_thread_options;
134
135 } // namespace
136
StartScheduler()137 [[noreturn]] void StartScheduler() {
138 while (true) {
139 std::this_thread::sleep_for(std::chrono::system_clock::duration::max());
140 }
141 }
142
LogThreadOptions()143 const thread::Options& LogThreadOptions() { return stl_thread_options; }
144
RpcThreadOptions()145 const thread::Options& RpcThreadOptions() { return stl_thread_options; }
146
TransferThreadOptions()147 const thread::Options& TransferThreadOptions() { return stl_thread_options; }
148
DispatcherThreadOptions()149 const thread::Options& DispatcherThreadOptions() { return stl_thread_options; }
150
WorkQueueThreadOptions()151 const thread::Options& WorkQueueThreadOptions() { return stl_thread_options; }
152
153 } // namespace pw::system
154
155 #endif // __has_include("FreeRTOS.h")
156