-
Notifications
You must be signed in to change notification settings - Fork 77
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pw_thread_freertos: Thread iteration API implementation
Change-Id: I6444c3e19b5fb25831b2263d5cb560e4ac217108 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/105161 Commit-Queue: Medha Kini <[email protected]> Reviewed-by: Armando Montanez <[email protected]>
- Loading branch information
Medha Kini
authored and
CQ Bot Account
committed
Aug 20, 2022
1 parent
fe1681d
commit d055225
Showing
6 changed files
with
282 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright 2022 The Pigweed Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
// use this file except in compliance with the License. You may obtain a copy of | ||
// the License at | ||
// | ||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
// License for the specific language governing permissions and limitations under | ||
// the License. | ||
// #include "pw_thread_freertos/thread_iteration.h" | ||
|
||
#include "pw_thread/thread_iteration.h" | ||
|
||
#include <cstddef> | ||
#include <string_view> | ||
|
||
#include "FreeRTOS.h" | ||
#include "pw_span/span.h" | ||
#include "pw_status/status.h" | ||
#include "pw_thread/thread_info.h" | ||
#include "pw_thread_backend/freertos_tsktcb.h" | ||
#include "pw_thread_freertos/util.h" | ||
|
||
namespace pw::thread { | ||
namespace { | ||
|
||
bool StackInfoCollector(TaskHandle_t current_thread, | ||
const pw::thread::ThreadCallback& cb) { | ||
const tskTCB& tcb = *reinterpret_cast<tskTCB*>(current_thread); | ||
ThreadInfo thread_info; | ||
|
||
#if configRECORD_STACK_HIGH_ADDRESS | ||
span<const std::byte> current_name = | ||
as_bytes(span(std::string_view(tcb.pcTaskName))); | ||
thread_info.set_thread_name(current_name); | ||
|
||
// Current thread stack bounds. | ||
thread_info.set_stack_low_addr(reinterpret_cast<uintptr_t>(tcb.pxStack)); | ||
thread_info.set_stack_high_addr( | ||
reinterpret_cast<uintptr_t>(tcb.pxEndOfStack)); | ||
#if INCLUDE_uxTaskGetStackHighWaterMark | ||
// Walk through the stack from start to end to measure the current peak | ||
// using high-water marked stack data. | ||
thread_info.set_stack_peak_addr(uxTaskGetStackHighWaterMark(thread)); | ||
#endif // INCLUDE_uxTaskGetStackHighWaterMark | ||
#endif // configRECORD_STACK_HIGH_ADDRESS | ||
|
||
return cb(thread_info); | ||
} | ||
|
||
} // namespace | ||
|
||
// This will disable the scheduler. | ||
Status ForEachThread(const pw::thread::ThreadCallback& cb) { | ||
pw::thread::freertos::ThreadCallback adapter_cb = | ||
[&cb](TaskHandle_t current_thread, eTaskState) { | ||
return StackInfoCollector(current_thread, cb); | ||
}; | ||
// Suspend scheduler. | ||
vTaskSuspendAll(); | ||
Status status = pw::thread::freertos::ForEachThread(adapter_cb); | ||
// Resume scheduler. | ||
xTaskResumeAll(); | ||
return status; | ||
} | ||
|
||
} // namespace pw::thread |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// Copyright 2022 The Pigweed Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
// use this file except in compliance with the License. You may obtain a copy of | ||
// the License at | ||
// | ||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
// License for the specific language governing permissions and limitations under | ||
// the License. | ||
|
||
#include "pw_thread/thread_iteration.h" | ||
|
||
#include <cstddef> | ||
#include <string_view> | ||
|
||
#include "gtest/gtest.h" | ||
#include "pw_span/span.h" | ||
#include "pw_string/util.h" | ||
#include "pw_sync/thread_notification.h" | ||
#include "pw_thread/test_threads.h" | ||
#include "pw_thread/thread.h" | ||
#include "pw_thread/thread_info.h" | ||
|
||
namespace pw::thread::freertos { | ||
namespace { | ||
|
||
sync::ThreadNotification lock_start; | ||
sync::ThreadNotification lock_end; | ||
|
||
void ForkedThreadEntry(void*) { | ||
// Release start lock to allow test thread to continue execution. | ||
lock_start.release(); | ||
while (true) { | ||
// Return only when end lock released by test thread. | ||
if (lock_end.try_acquire()) { | ||
return; | ||
} | ||
} | ||
} | ||
|
||
// Tests thread iteration API by: | ||
// - Forking a test thread. | ||
// - Using iteration API to iterate over all running threads. | ||
// - Compares name of forked thread and current thread. | ||
// - Confirms thread exists and is iterated over. | ||
TEST(ThreadIteration, ForkOneThread) { | ||
const auto& options = *static_cast<const pw::thread::freertos::Options*>( | ||
&thread::test::TestOptionsThread0()); | ||
thread::Thread t(options, ForkedThreadEntry); | ||
|
||
// Blocked until thread t releases start lock. | ||
lock_start.acquire(); | ||
|
||
struct { | ||
bool thread_exists; | ||
span<const std::byte> name; | ||
} temp_struct; | ||
|
||
temp_struct.thread_exists = false; | ||
// Max permissible length of task name including null byte. | ||
static constexpr size_t buffer_size = configMAX_TASK_NAME_LEN; | ||
|
||
std::string_view string(string::ClampedCString(options.name(), buffer_size)); | ||
temp_struct.name = as_bytes(span(string)); | ||
|
||
// Callback that confirms forked thread is checked by the iterator. | ||
auto cb = [&temp_struct](const ThreadInfo& thread_info) { | ||
// Compare sizes accounting for null byte. | ||
if (thread_info.thread_name().has_value()) { | ||
for (size_t i = 0; i < thread_info.thread_name().value().size(); i++) { | ||
// Compare character by character of span. | ||
if ((unsigned char)thread_info.thread_name().value().data()[i] != | ||
(unsigned char)temp_struct.name.data()[i]) { | ||
return true; | ||
} | ||
} | ||
temp_struct.thread_exists = true; | ||
} | ||
// Signal to stop iteration. | ||
return false; | ||
}; | ||
|
||
thread::ForEachThread(cb); | ||
|
||
// Signal to forked thread that execution is complete. | ||
lock_end.release(); | ||
|
||
// Clean up the test thread context. | ||
#if PW_THREAD_JOINING_ENABLED | ||
t.join(); | ||
#else | ||
t.detach(); | ||
thread::test::WaitUntilDetachedThreadsCleanedUp(); | ||
#endif // PW_THREAD_JOINING_ENABLED | ||
|
||
EXPECT_TRUE(temp_struct.thread_exists); | ||
} | ||
|
||
} // namespace | ||
} // namespace pw::thread::freertos |