1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <gtest/gtest.h>
18
19 #include "thread/CommonPool.h"
20
21 #include <array>
22 #include <condition_variable>
23 #include <set>
24 #include <thread>
25 #include "unistd.h"
26
27 using namespace android;
28 using namespace android::uirenderer;
29
TEST(CommonPool,post)30 TEST(CommonPool, post) {
31 std::atomic_bool ran(false);
32 CommonPool::post([&ran] { ran = true; });
33 for (int i = 0; !ran && i < 1000; i++) {
34 usleep(1);
35 }
36 EXPECT_TRUE(ran) << "Failed to flip atomic after 1 second";
37 }
38
39 // test currently relies on timings, which
40 // makes it flaky. Disable for now
TEST(DISABLED_CommonPool,threadCount)41 TEST(DISABLED_CommonPool, threadCount) {
42 std::set<pid_t> threads;
43 std::array<std::future<pid_t>, 64> futures;
44 for (int i = 0; i < futures.size(); i++) {
45 futures[i] = CommonPool::async([] {
46 usleep(10);
47 return gettid();
48 });
49 }
50 for (auto& f : futures) {
51 threads.insert(f.get());
52 }
53 EXPECT_EQ(threads.size(), CommonPool::THREAD_COUNT);
54 EXPECT_EQ(0, threads.count(gettid()));
55 }
56
TEST(CommonPool,singleThread)57 TEST(CommonPool, singleThread) {
58 std::mutex mutex;
59 std::condition_variable fence;
60 bool isProcessing = false;
61 bool queuedSecond = false;
62
63 auto f1 = CommonPool::async([&] {
64 {
65 std::unique_lock lock{mutex};
66 isProcessing = true;
67 fence.notify_all();
68 while (!queuedSecond) {
69 fence.wait(lock);
70 }
71 }
72 return gettid();
73 });
74
75 {
76 std::unique_lock lock{mutex};
77 while (!isProcessing) {
78 fence.wait(lock);
79 }
80 }
81
82 auto f2 = CommonPool::async([] {
83 return gettid();
84 });
85
86 {
87 std::unique_lock lock{mutex};
88 queuedSecond = true;
89 fence.notify_all();
90 }
91
92 auto tid1 = f1.get();
93 auto tid2 = f2.get();
94 EXPECT_EQ(tid1, tid2);
95 EXPECT_NE(gettid(), tid1);
96 }
97
98 // Test currently relies on timings
99 // which makes it flaky, disable for now
TEST(DISABLED_CommonPool,fullQueue)100 TEST(DISABLED_CommonPool, fullQueue) {
101 std::mutex lock;
102 std::condition_variable fence;
103 bool signaled = false;
104 static constexpr auto QUEUE_COUNT = CommonPool::THREAD_COUNT + CommonPool::QUEUE_SIZE + 10;
105 std::atomic_int queuedCount{0};
106 std::array<std::future<void>, QUEUE_COUNT> futures;
107
108 std::thread queueThread{[&] {
109 for (int i = 0; i < QUEUE_COUNT; i++) {
110 futures[i] = CommonPool::async([&] {
111 std::unique_lock _lock{lock};
112 while (!signaled) {
113 fence.wait(_lock);
114 }
115 });
116 queuedCount++;
117 }
118 }};
119
120 int previous;
121 do {
122 previous = queuedCount.load();
123 usleep(10000);
124 } while (previous != queuedCount.load());
125
126 EXPECT_GT(queuedCount.load(), CommonPool::QUEUE_SIZE);
127 EXPECT_LT(queuedCount.load(), QUEUE_COUNT);
128
129 {
130 std::unique_lock _lock{lock};
131 signaled = true;
132 fence.notify_all();
133 }
134
135 queueThread.join();
136 EXPECT_EQ(queuedCount.load(), QUEUE_COUNT);
137
138 // Ensure all our tasks are finished before return as they have references to the stack
139 for (auto& f : futures) {
140 f.get();
141 }
142 }
143
144 class ObjectTracker {
145 static std::atomic_int sGlobalCount;
146
147 public:
ObjectTracker()148 ObjectTracker() {
149 sGlobalCount++;
150 }
ObjectTracker(const ObjectTracker &)151 ObjectTracker(const ObjectTracker&) {
152 sGlobalCount++;
153 }
ObjectTracker(ObjectTracker &&)154 ObjectTracker(ObjectTracker&&) {
155 sGlobalCount++;
156 }
~ObjectTracker()157 ~ObjectTracker() {
158 sGlobalCount--;
159 }
160
count()161 static int count() { return sGlobalCount.load(); }
162 };
163
164 std::atomic_int ObjectTracker::sGlobalCount{0};
165
TEST(CommonPool,asyncLifecycleCheck)166 TEST(CommonPool, asyncLifecycleCheck) {
167 ASSERT_EQ(0, ObjectTracker::count());
168 {
169 ObjectTracker obj;
170 ASSERT_EQ(1, ObjectTracker::count());
171 EXPECT_LT(1, CommonPool::async([obj] { return ObjectTracker::count(); }).get());
172 }
173 CommonPool::waitForIdle();
174 ASSERT_EQ(0, ObjectTracker::count());
175 }
176
TEST(CommonPool,syncLifecycleCheck)177 TEST(CommonPool, syncLifecycleCheck) {
178 ASSERT_EQ(0, ObjectTracker::count());
179 {
180 ObjectTracker obj;
181 ASSERT_EQ(1, ObjectTracker::count());
182 EXPECT_LT(1, CommonPool::runSync([obj] { return ObjectTracker::count(); }));
183 }
184 CommonPool::waitForIdle();
185 ASSERT_EQ(0, ObjectTracker::count());
186 }
187