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