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
57 // Disabled since this is flaky. This isn't a necessarily useful functional test, so being
58 // disabled isn't that significant. However it may be good to resurrect this somehow.
TEST(CommonPool,DISABLED_singleThread)59 TEST(CommonPool, DISABLED_singleThread) {
60 std::mutex mutex;
61 std::condition_variable fence;
62 bool isProcessing = false;
63 bool queuedSecond = false;
64
65 auto f1 = CommonPool::async([&] {
66 {
67 std::unique_lock lock{mutex};
68 isProcessing = true;
69 fence.notify_all();
70 while (!queuedSecond) {
71 fence.wait(lock);
72 }
73 }
74 return gettid();
75 });
76
77 {
78 std::unique_lock lock{mutex};
79 while (!isProcessing) {
80 fence.wait(lock);
81 }
82 }
83
84 auto f2 = CommonPool::async([] {
85 return gettid();
86 });
87
88 {
89 std::unique_lock lock{mutex};
90 queuedSecond = true;
91 fence.notify_all();
92 }
93
94 auto tid1 = f1.get();
95 auto tid2 = f2.get();
96 EXPECT_EQ(tid1, tid2);
97 EXPECT_NE(gettid(), tid1);
98 }
99
100 // Test currently relies on timings
101 // which makes it flaky, disable for now
TEST(DISABLED_CommonPool,fullQueue)102 TEST(DISABLED_CommonPool, fullQueue) {
103 std::mutex lock;
104 std::condition_variable fence;
105 bool signaled = false;
106 static constexpr auto QUEUE_COUNT = CommonPool::THREAD_COUNT + CommonPool::QUEUE_SIZE + 10;
107 std::atomic_int queuedCount{0};
108 std::array<std::future<void>, QUEUE_COUNT> futures;
109
110 std::thread queueThread{[&] {
111 for (int i = 0; i < QUEUE_COUNT; i++) {
112 futures[i] = CommonPool::async([&] {
113 std::unique_lock _lock{lock};
114 while (!signaled) {
115 fence.wait(_lock);
116 }
117 });
118 queuedCount++;
119 }
120 }};
121
122 int previous;
123 do {
124 previous = queuedCount.load();
125 usleep(10000);
126 } while (previous != queuedCount.load());
127
128 EXPECT_GT(queuedCount.load(), CommonPool::QUEUE_SIZE);
129 EXPECT_LT(queuedCount.load(), QUEUE_COUNT);
130
131 {
132 std::unique_lock _lock{lock};
133 signaled = true;
134 fence.notify_all();
135 }
136
137 queueThread.join();
138 EXPECT_EQ(queuedCount.load(), QUEUE_COUNT);
139
140 // Ensure all our tasks are finished before return as they have references to the stack
141 for (auto& f : futures) {
142 f.get();
143 }
144 }
145
146 class ObjectTracker {
147 static std::atomic_int sGlobalCount;
148
149 public:
ObjectTracker()150 ObjectTracker() {
151 sGlobalCount++;
152 }
ObjectTracker(const ObjectTracker &)153 ObjectTracker(const ObjectTracker&) {
154 sGlobalCount++;
155 }
ObjectTracker(ObjectTracker &&)156 ObjectTracker(ObjectTracker&&) {
157 sGlobalCount++;
158 }
~ObjectTracker()159 ~ObjectTracker() {
160 sGlobalCount--;
161 }
162
count()163 static int count() { return sGlobalCount.load(); }
164 };
165
166 std::atomic_int ObjectTracker::sGlobalCount{0};
167
TEST(CommonPool,asyncLifecycleCheck)168 TEST(CommonPool, asyncLifecycleCheck) {
169 ASSERT_EQ(0, ObjectTracker::count());
170 {
171 ObjectTracker obj;
172 ASSERT_EQ(1, ObjectTracker::count());
173 EXPECT_LT(1, CommonPool::async([obj] { return ObjectTracker::count(); }).get());
174 }
175 CommonPool::waitForIdle();
176 ASSERT_EQ(0, ObjectTracker::count());
177 }
178
TEST(CommonPool,syncLifecycleCheck)179 TEST(CommonPool, syncLifecycleCheck) {
180 ASSERT_EQ(0, ObjectTracker::count());
181 {
182 ObjectTracker obj;
183 ASSERT_EQ(1, ObjectTracker::count());
184 EXPECT_LT(1, CommonPool::runSync([obj] { return ObjectTracker::count(); }));
185 }
186 CommonPool::waitForIdle();
187 ASSERT_EQ(0, ObjectTracker::count());
188 }
189