• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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