1 /*
2  * Copyright (C) 2017 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/ThreadBase.h"
20 #include "utils/TimeUtils.h"
21 
22 #include <chrono>
23 #include "unistd.h"
24 
25 using namespace android;
26 using namespace android::uirenderer;
27 
thread()28 static ThreadBase& thread() {
29     class TestThread : public ThreadBase, public virtual RefBase {};
30     static sp<TestThread> thread = []() -> auto {
31         sp<TestThread> ret{new TestThread};
32         ret->start("TestThread");
33         return ret;
34     }
35     ();
36     return *thread;
37 }
38 
queue()39 static WorkQueue& queue() {
40     return thread().queue();
41 }
42 
TEST(ThreadBase,post)43 TEST(ThreadBase, post) {
44     std::atomic_bool ran(false);
45     queue().post([&ran]() { ran = true; });
46     for (int i = 0; !ran && i < 1000; i++) {
47         usleep(1);
48     }
49     ASSERT_TRUE(ran) << "Failed to flip atomic after 1 second";
50 }
51 
TEST(ThreadBase,postDelay)52 TEST(ThreadBase, postDelay) {
53     using clock = WorkQueue::clock;
54 
55     std::promise<nsecs_t> ranAtPromise;
56     auto queuedAt = clock::now();
57     queue().postDelayed(100_us, [&]() { ranAtPromise.set_value(clock::now()); });
58     auto ranAt = ranAtPromise.get_future().get();
59     auto ranAfter = ranAt - queuedAt;
60     ASSERT_TRUE(ranAfter > 90_us) << "Ran after " << ns2us(ranAfter) << "us <= 90us";
61 }
62 
TEST(ThreadBase,runSync)63 TEST(ThreadBase, runSync) {
64     pid_t thisTid = gettid();
65     pid_t otherTid = thisTid;
66 
67     auto result = queue().runSync([&otherTid]() -> auto {
68         otherTid = gettid();
69         return 42;
70     });
71 
72     ASSERT_EQ(42, result);
73     ASSERT_NE(thisTid, otherTid);
74 }
75 
TEST(ThreadBase,async)76 TEST(ThreadBase, async) {
77     pid_t thisTid = gettid();
78     pid_t thisPid = getpid();
79 
80     auto otherTid = queue().async([]() -> auto { return gettid(); });
81     auto otherPid = queue().async([]() -> auto { return getpid(); });
82     auto result = queue().async([]() -> auto { return 42; });
83 
84     ASSERT_NE(thisTid, otherTid.get());
85     ASSERT_EQ(thisPid, otherPid.get());
86     ASSERT_EQ(42, result.get());
87 }
88 
TEST(ThreadBase,lifecyclePerf)89 TEST(ThreadBase, lifecyclePerf) {
90     struct EventCount {
91         std::atomic_int construct{0};
92         std::atomic_int destruct{0};
93         std::atomic_int copy{0};
94         std::atomic_int move{0};
95     };
96 
97     struct Counter {
98         explicit Counter(EventCount* count) : mCount(count) { mCount->construct++; }
99 
100         Counter(const Counter& other) : mCount(other.mCount) {
101             if (mCount) mCount->copy++;
102         }
103 
104         Counter(Counter&& other) : mCount(other.mCount) {
105             other.mCount = nullptr;
106             if (mCount) mCount->move++;
107         }
108 
109         Counter& operator=(const Counter& other) {
110             mCount = other.mCount;
111             if (mCount) mCount->copy++;
112             return *this;
113         }
114 
115         Counter& operator=(Counter&& other) {
116             mCount = other.mCount;
117             other.mCount = nullptr;
118             if (mCount) mCount->move++;
119             return *this;
120         }
121 
122         ~Counter() {
123             if (mCount) mCount->destruct++;
124         }
125 
126         EventCount* mCount;
127     };
128 
129     EventCount count;
130     {
131         Counter counter{&count};
132         queue().runSync([c = std::move(counter)](){});
133     }
134     ASSERT_EQ(1, count.construct.load());
135     ASSERT_EQ(1, count.destruct.load());
136     ASSERT_EQ(0, count.copy.load());
137     ASSERT_LE(1, count.move.load());
138 }
139 
lifecycleTestHelper(const sp<VirtualLightRefBase> & test)140 int lifecycleTestHelper(const sp<VirtualLightRefBase>& test) {
141     return queue().runSync([t = test]()->int { return t->getStrongCount(); });
142 }
143 
TEST(ThreadBase,lifecycle)144 TEST(ThreadBase, lifecycle) {
145     sp<VirtualLightRefBase> dummyObject{new VirtualLightRefBase};
146     ASSERT_EQ(1, dummyObject->getStrongCount());
147     ASSERT_EQ(2, queue().runSync([dummyObject]() -> int { return dummyObject->getStrongCount(); }));
148     ASSERT_EQ(1, dummyObject->getStrongCount());
149     ASSERT_EQ(2, lifecycleTestHelper(dummyObject));
150     ASSERT_EQ(1, dummyObject->getStrongCount());
151 }
152