aboutsummaryrefslogtreecommitdiff
path: root/pw_thread/thread_facade_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'pw_thread/thread_facade_test.cc')
-rw-r--r--pw_thread/thread_facade_test.cc167
1 files changed, 167 insertions, 0 deletions
diff --git a/pw_thread/thread_facade_test.cc b/pw_thread/thread_facade_test.cc
new file mode 100644
index 000000000..008e2cacd
--- /dev/null
+++ b/pw_thread/thread_facade_test.cc
@@ -0,0 +1,167 @@
+// Copyright 2021 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 "gtest/gtest.h"
+#include "pw_sync/binary_semaphore.h"
+#include "pw_thread/id.h"
+#include "pw_thread/test_threads.h"
+#include "pw_thread/thread.h"
+
+using pw::thread::test::TestOptionsThread0;
+using pw::thread::test::TestOptionsThread1;
+using pw::thread::test::WaitUntilDetachedThreadsCleanedUp;
+
+namespace pw::thread {
+namespace {
+
+TEST(Thread, DefaultIds) {
+ Thread not_executing_thread;
+ EXPECT_EQ(not_executing_thread.get_id(), Id());
+}
+
+static void ReleaseBinarySemaphore(void* arg) {
+ static_cast<sync::BinarySemaphore*>(arg)->release();
+}
+
+#if PW_THREAD_JOINING_ENABLED
+TEST(Thread, Join) {
+ Thread thread;
+ EXPECT_FALSE(thread.joinable());
+ sync::BinarySemaphore thread_ran_sem;
+ thread =
+ Thread(TestOptionsThread0(), ReleaseBinarySemaphore, &thread_ran_sem);
+ EXPECT_TRUE(thread.joinable());
+ thread.join();
+ EXPECT_EQ(thread.get_id(), Id());
+ EXPECT_TRUE(thread_ran_sem.try_acquire());
+}
+#endif // PW_THREAD_JOINING_ENABLED
+
+TEST(Thread, Detach) {
+ Thread thread;
+ sync::BinarySemaphore thread_ran_sem;
+ thread =
+ Thread(TestOptionsThread0(), ReleaseBinarySemaphore, &thread_ran_sem);
+ EXPECT_NE(thread.get_id(), Id());
+ EXPECT_TRUE(thread.joinable());
+ thread.detach();
+ EXPECT_EQ(thread.get_id(), Id());
+ EXPECT_FALSE(thread.joinable());
+ thread_ran_sem.acquire();
+
+ WaitUntilDetachedThreadsCleanedUp();
+}
+
+TEST(Thread, SwapWithoutExecution) {
+ Thread thread_0;
+ Thread thread_1;
+
+ // Make sure we can swap threads which are not associated with any execution.
+ thread_0.swap(thread_1);
+}
+
+TEST(Thread, SwapWithOneExecuting) {
+ Thread thread_0;
+ EXPECT_EQ(thread_0.get_id(), Id());
+
+ sync::BinarySemaphore thread_ran_sem;
+ Thread thread_1(
+ TestOptionsThread1(), ReleaseBinarySemaphore, &thread_ran_sem);
+
+ EXPECT_NE(thread_1.get_id(), Id());
+
+ thread_0.swap(thread_1);
+ EXPECT_NE(thread_0.get_id(), Id());
+ EXPECT_EQ(thread_1.get_id(), Id());
+
+ thread_0.detach();
+ EXPECT_EQ(thread_0.get_id(), Id());
+
+ thread_ran_sem.acquire();
+ WaitUntilDetachedThreadsCleanedUp();
+}
+
+TEST(Thread, SwapWithTwoExecuting) {
+ sync::BinarySemaphore thread_a_ran_sem;
+ Thread thread_0(
+ TestOptionsThread0(), ReleaseBinarySemaphore, &thread_a_ran_sem);
+ sync::BinarySemaphore thread_b_ran_sem;
+ Thread thread_1(
+ TestOptionsThread1(), ReleaseBinarySemaphore, &thread_b_ran_sem);
+ const Id thread_a_id = thread_0.get_id();
+ EXPECT_NE(thread_a_id, Id());
+ const Id thread_b_id = thread_1.get_id();
+ EXPECT_NE(thread_b_id, Id());
+ EXPECT_NE(thread_a_id, thread_b_id);
+
+ thread_0.swap(thread_1);
+ EXPECT_EQ(thread_1.get_id(), thread_a_id);
+ EXPECT_EQ(thread_0.get_id(), thread_b_id);
+
+ thread_0.detach();
+ EXPECT_EQ(thread_0.get_id(), Id());
+ thread_1.detach();
+ EXPECT_EQ(thread_1.get_id(), Id());
+
+ thread_a_ran_sem.acquire();
+ thread_b_ran_sem.acquire();
+ WaitUntilDetachedThreadsCleanedUp();
+}
+
+TEST(Thread, MoveOperator) {
+ Thread thread_0;
+ EXPECT_EQ(thread_0.get_id(), Id());
+
+ sync::BinarySemaphore thread_ran_sem;
+ Thread thread_1(
+ TestOptionsThread1(), ReleaseBinarySemaphore, &thread_ran_sem);
+ EXPECT_NE(thread_1.get_id(), Id());
+
+ thread_0 = std::move(thread_1);
+ EXPECT_NE(thread_0.get_id(), Id());
+#ifndef __clang_analyzer__
+ EXPECT_EQ(thread_1.get_id(), Id());
+#endif // ignore use-after-move
+
+ thread_0.detach();
+ EXPECT_EQ(thread_0.get_id(), Id());
+
+ thread_ran_sem.acquire();
+ WaitUntilDetachedThreadsCleanedUp();
+}
+
+class SemaphoreReleaser : public ThreadCore {
+ public:
+ pw::sync::BinarySemaphore& semaphore() { return semaphore_; }
+
+ private:
+ void Run() override { semaphore_.release(); }
+
+ sync::BinarySemaphore semaphore_;
+};
+
+TEST(Thread, ThreadCore) {
+ SemaphoreReleaser semaphore_releaser;
+ Thread thread(TestOptionsThread0(), semaphore_releaser);
+ EXPECT_NE(thread.get_id(), Id());
+ EXPECT_TRUE(thread.joinable());
+ thread.detach();
+ EXPECT_EQ(thread.get_id(), Id());
+ EXPECT_FALSE(thread.joinable());
+ semaphore_releaser.semaphore().acquire();
+
+ WaitUntilDetachedThreadsCleanedUp();
+}
+} // namespace
+} // namespace pw::thread