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