xref: /aosp_15_r20/external/pigweed/pw_thread_threadx/test_threads.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2021 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 <chrono>
16 
17 #include "pw_assert/check.h"
18 #include "pw_chrono/system_clock.h"
19 #include "pw_log/log.h"
20 #include "pw_thread/non_portable_test_thread_options.h"
21 #include "pw_thread/sleep.h"
22 #include "pw_thread_threadx/context.h"
23 #include "pw_thread_threadx/options.h"
24 
25 namespace pw::thread::test {
26 namespace {
27 
28 std::array<threadx::ContextWithStack<>, 2> thread_contexts;
29 
30 }  // namespace
31 
TestOptionsThread0()32 const Options& TestOptionsThread0() {
33   static constexpr threadx::Options thread_0_options =
34       threadx::Options()
35           .set_name("pw::TestThread0")
36           .set_context(thread_contexts[0]);
37   return thread_0_options;
38 }
39 
TestOptionsThread1()40 const Options& TestOptionsThread1() {
41   static constexpr threadx::Options thread_1_options =
42       threadx::Options()
43           .set_name("pw::TestThread1")
44           .set_context(thread_contexts[1]);
45   return thread_1_options;
46 }
47 
WaitUntilDetachedThreadsCleanedUp()48 void WaitUntilDetachedThreadsCleanedUp() {
49   // ThreadX does not permit the running thread to delete itself, which means
50   // we have to do this to re-use a TCB as otherwise we will be leaking stale
51   // references in the kernel.
52   for (auto& context : thread_contexts) {
53     if (context.tcb().tx_thread_id != TX_THREAD_ID) {
54       // The TCB was either not used or was already deleted. Note that
55       // tx_thread_terminate does NOT clear this state by design.
56       continue;
57     }
58 
59     // If the thread was created but has not been deleted, it means that the
60     // thread was detached before it finished. Wait until it is completed.
61     while (context.tcb().tx_thread_state != TX_COMPLETED) {
62       pw::this_thread::sleep_for(
63           chrono::SystemClock::for_at_least(std::chrono::milliseconds(1)));
64     }
65 
66     const UINT result = tx_thread_delete(&context.tcb());
67     PW_CHECK_UINT_EQ(TX_SUCCESS, result, "Failed to delete thread");
68   }
69 }
70 
71 }  // namespace pw::thread::test
72