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)31bool 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)68Status 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