xref: /aosp_15_r20/external/pigweed/pw_thread_freertos/thread_iteration.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 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_thread/thread_iteration.h"
16 
17 #include <cstddef>
18 #include <string_view>
19 
20 #include "FreeRTOS.h"
21 #include "pw_span/span.h"
22 #include "pw_status/status.h"
23 #include "pw_thread/thread_info.h"
24 #include "pw_thread_freertos/freertos_tsktcb.h"
25 #include "pw_thread_freertos/util.h"
26 #include "pw_thread_freertos_private/thread_iteration.h"
27 
28 namespace pw::thread {
29 namespace freertos {
30 
StackInfoCollector(TaskHandle_t current_thread,const pw::thread::ThreadCallback & cb)31 bool StackInfoCollector(TaskHandle_t current_thread,
32                         const pw::thread::ThreadCallback& cb) {
33   const tskTCB& tcb = *reinterpret_cast<tskTCB*>(current_thread);
34   ThreadInfo thread_info;
35 
36   span<const std::byte> current_name =
37       as_bytes(span(std::string_view(tcb.pcTaskName)));
38   thread_info.set_thread_name(current_name);
39 
40   thread_info.set_stack_pointer(reinterpret_cast<uintptr_t>(tcb.pxTopOfStack));
41 
42   // Current thread stack bounds.
43   thread_info.set_stack_low_addr(reinterpret_cast<uintptr_t>(tcb.pxStack));
44 #if configRECORD_STACK_HIGH_ADDRESS
45   thread_info.set_stack_high_addr(
46       reinterpret_cast<uintptr_t>(tcb.pxEndOfStack));
47 #if INCLUDE_uxTaskGetStackHighWaterMark
48 // Walk through the stack from start to end to measure the current peak
49 // using high-water marked stack data.
50 #if (portSTACK_GROWTH > 0)
51   thread_info.set_stack_peak_addr(
52       thread_info.stack_high_addr().value() -
53       (sizeof(StackType_t) * uxTaskGetStackHighWaterMark(current_thread)));
54 #else
55   thread_info.set_stack_peak_addr(
56       thread_info.stack_low_addr().value() +
57       (sizeof(StackType_t) * uxTaskGetStackHighWaterMark(current_thread)));
58 #endif  // portSTACK_GROWTH > 0
59 #endif  // INCLUDE_uxTaskGetStackHighWaterMark
60 #endif  // configRECORD_STACK_HIGH_ADDRESS
61 
62   return cb(thread_info);
63 }
64 
65 }  // namespace freertos
66 
67 // This will disable the scheduler.
ForEachThread(const pw::thread::ThreadCallback & cb)68 Status ForEachThread(const pw::thread::ThreadCallback& cb) {
69   pw::thread::freertos::ThreadCallback adapter_cb =
70       [&cb](TaskHandle_t current_thread, eTaskState) -> bool {
71     return freertos::StackInfoCollector(current_thread, cb);
72   };
73   // Suspend scheduler.
74   vTaskSuspendAll();
75   Status status = pw::thread::freertos::ForEachThread(adapter_cb);
76   // Resume scheduler.
77   xTaskResumeAll();
78   return status;
79 }
80 
81 }  // namespace pw::thread
82