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_compilation_testing/negative_compilation.h"
16 #include "pw_polyfill/language_feature_macros.h"
17 #include "pw_thread/thread.h"
18 #include "pw_unit_test/framework.h"
19
20 namespace {
21
22 #if PW_THREAD_GENERIC_CREATION_IS_SUPPORTED
23 #if PW_THREAD_JOINING_ENABLED
24
25 constexpr pw::ThreadAttrs kThread0 = pw::ThreadAttrs().set_stack_size_bytes(0);
26 constexpr pw::ThreadAttrs kThread1023 =
27 pw::ThreadAttrs().set_name("hello world").set_stack_size_bytes(1023);
28 constexpr pw::ThreadAttrs kThread1024 =
29 pw::ThreadAttrs(kThread1023).set_stack_size_bytes(1024);
30 [[maybe_unused]] constexpr pw::ThreadAttrs kThread1025 =
31 pw::ThreadAttrs(kThread1024).set_stack_size_bytes(1025);
32
33 PW_CONSTINIT pw::ThreadStack<0> stack_0;
34 PW_CONSTINIT pw::ThreadStack<1024> stack_1024;
35
36 [[maybe_unused]] PW_CONSTINIT pw::ThreadContext<> must_be_constinit_1;
37 [[maybe_unused]] PW_CONSTINIT pw::ThreadContext<1024> must_be_constinit_2;
38
39 constexpr pw::ThreadAttrs kThreadExternalMin =
40 pw::ThreadAttrs().set_stack(stack_0);
41 constexpr pw::ThreadAttrs kThreadExternal =
42 pw::ThreadAttrs().set_stack(stack_1024);
43
44 class ThreadCreationTest : public ::testing::Test {
45 public:
~ThreadCreationTest()46 ~ThreadCreationTest() override {
47 EXPECT_EQ(expected_thread_runs_, thread_runs_);
48 }
49
TestThread()50 auto TestThread() {
51 expected_thread_runs_ += 1;
52 return [this] { thread_runs_ += 1; };
53 }
54
55 private:
56 int expected_thread_runs_ = 0;
57 int thread_runs_ = 0;
58 };
59
TEST_F(ThreadCreationTest,ThreadContext)60 TEST_F(ThreadCreationTest, ThreadContext) {
61 pw::ThreadContext<1024> context;
62
63 pw::Thread(context, kThread1024, TestThread()).join();
64
65 pw::Thread(pw::GetThreadOptions<kThread1023>(context), TestThread()).join();
66 pw::Thread(pw::GetThreadOptions(context, kThread1023), TestThread()).join();
67
68 pw::Thread(pw::GetThreadOptions<kThread1024>(context), TestThread()).join();
69 pw::Thread(pw::GetThreadOptions(context, kThread1024), TestThread()).join();
70
71 #if PW_NC_TEST(StackTooSmall_TemplateArgument)
72 PW_NC_EXPECT(
73 "ThreadContext stack is too small for the requested ThreadAttrs");
74 pw::Thread(pw::GetThreadOptions<kThread1025>(context), TestThread()).join();
75 #elif PW_NC_TEST(StackTooSmall_FunctionArgument)
76 PW_NC_EXPECT(
77 "PW_ASSERT\(kContextStackSizeBytes >= "
78 "attributes.stack_size_bytes\(\)\);");
79 [[maybe_unused]] constexpr auto options =
80 pw::GetThreadOptions(context, kThread1025);
81 #endif // PW_NC_TEST
82 }
83
TEST_F(ThreadCreationTest,ThreadContextExternalStack)84 TEST_F(ThreadCreationTest, ThreadContextExternalStack) {
85 pw::ThreadContext<> context;
86
87 pw::Thread(context, kThreadExternal, TestThread()).join();
88
89 pw::Thread(pw::GetThreadOptions<kThreadExternal>(context), TestThread())
90 .join();
91 pw::Thread(pw::GetThreadOptions(context, kThreadExternal), TestThread())
92 .join();
93
94 #if PW_NC_TEST(NoStack)
95 PW_NC_EXPECT("No stack was provided!");
96 std::ignore = pw::GetThreadOptions<kThread1024>(context);
97 #endif // PW_NC_TEST
98 }
99
TEST_F(ThreadCreationTest,ThreadContextWithStackButAttrsWithExternallyAllocatedStack)100 TEST_F(ThreadCreationTest,
101 ThreadContextWithStackButAttrsWithExternallyAllocatedStack) {
102 pw::ThreadContext<1024> context;
103
104 pw::Thread(pw::GetThreadOptions<kThreadExternal>(context), TestThread())
105 .join();
106
107 pw::Thread(pw::GetThreadOptions(context, kThreadExternal), TestThread())
108 .join();
109 }
110
TEST_F(ThreadCreationTest,ThreadContextMinimumSizedExternalStack)111 TEST_F(ThreadCreationTest, ThreadContextMinimumSizedExternalStack) {
112 pw::ThreadContext<> context;
113
114 pw::Thread(context, kThreadExternalMin, TestThread()).join();
115
116 pw::Thread(pw::GetThreadOptions<kThreadExternalMin>(context), TestThread())
117 .join();
118 pw::Thread(pw::GetThreadOptions(context, kThreadExternalMin), TestThread())
119 .join();
120 }
121
TEST_F(ThreadCreationTest,ThreadContextFor)122 TEST_F(ThreadCreationTest, ThreadContextFor) {
123 pw::ThreadContextFor<kThread1024> context;
124
125 pw::Thread(context, TestThread()).join();
126
127 pw::Thread(pw::GetThreadOptions(context), TestThread()).join();
128 }
129
TEST_F(ThreadCreationTest,ThreadContextForExternalStack)130 TEST_F(ThreadCreationTest, ThreadContextForExternalStack) {
131 pw::ThreadContextFor<kThreadExternal> context;
132
133 pw::Thread(context, TestThread()).join();
134
135 pw::Thread(pw::GetThreadOptions(context), TestThread()).join();
136 }
137
TEST_F(ThreadCreationTest,ThreadContextForMinimumSizedStack)138 TEST_F(ThreadCreationTest, ThreadContextForMinimumSizedStack) {
139 pw::ThreadContextFor<kThread0> context;
140
141 pw::Thread(context, TestThread()).join();
142
143 pw::Thread(pw::GetThreadOptions(context), TestThread()).join();
144 }
145
146 #endif // PW_THREAD_JOINING_ENABLED
147
148 #else // thread creation is not supported
149
150 [[maybe_unused]] constexpr pw::ThreadAttrs kAttrs;
151
152 #if PW_NC_TEST(CreationUnsupported_ThreadContext)
153 PW_NC_EXPECT("Generic thread creation is not yet supported");
154 pw::ThreadContext<> context;
155 #elif PW_NC_TEST(CreationUnsupported_ThreadContextFor)
156 PW_NC_EXPECT("Generic thread creation is not yet supported");
157 pw::ThreadContextFor<kAttrs> context_for_attrs;
158 #elif PW_NC_TEST(CreationUnsupported_ThreadStack)
159 PW_NC_EXPECT("Generic thread creation is not yet supported");
160 pw::ThreadStack<1000> stack;
161 #endif // PW_NC_TEST
162
163 #endif // PW_THREAD_GENERIC_CREATION_IS_SUPPORTED
164
165 } // namespace
166