• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "RecurrentTimer.h"
18 
19 #include <android-base/thread_annotations.h>
20 #include <gtest/gtest.h>
21 
22 #include <chrono>
23 #include <memory>
24 #include <mutex>
25 
26 namespace android {
27 namespace hardware {
28 namespace automotive {
29 namespace vehicle {
30 
31 class RecurrentTimerTest : public testing::Test {
32   public:
getCallback(size_t token)33     std::shared_ptr<RecurrentTimer::Callback> getCallback(size_t token) {
34         return std::make_shared<RecurrentTimer::Callback>([this, token] {
35             std::scoped_lock<std::mutex> lockGuard(mLock);
36 
37             mCallbacks.push_back(token);
38         });
39     }
40 
getCalledCallbacks()41     std::vector<size_t> getCalledCallbacks() {
42         std::scoped_lock<std::mutex> lockGuard(mLock);
43         return mCallbacks;
44     }
45 
clearCalledCallbacks()46     void clearCalledCallbacks() {
47         std::scoped_lock<std::mutex> lockGuard(mLock);
48         mCallbacks.clear();
49     }
50 
countTimerCallbackQueue(RecurrentTimer * timer)51     size_t countTimerCallbackQueue(RecurrentTimer* timer) {
52         std::scoped_lock<std::mutex> lockGuard(timer->mLock);
53         return timer->mCallbackQueue.size();
54     }
55 
56   private:
57     std::mutex mLock;
58     std::vector<size_t> mCallbacks GUARDED_BY(mLock);
59 };
60 
TEST_F(RecurrentTimerTest,testRegisterCallback)61 TEST_F(RecurrentTimerTest, testRegisterCallback) {
62     RecurrentTimer timer;
63     // 0.1s
64     int64_t interval = 100000000;
65 
66     auto action = getCallback(0);
67     timer.registerTimerCallback(interval, action);
68 
69     std::this_thread::sleep_for(std::chrono::seconds(1));
70 
71     timer.unregisterTimerCallback(action);
72 
73     // Theoretically trigger 10 times, but check for at least 9 times to be stable.
74     ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
75 }
76 
TEST_F(RecurrentTimerTest,testRegisterUnregisterRegister)77 TEST_F(RecurrentTimerTest, testRegisterUnregisterRegister) {
78     RecurrentTimer timer;
79     // 0.1s
80     int64_t interval = 100000000;
81 
82     auto action = getCallback(0);
83     timer.registerTimerCallback(interval, action);
84 
85     std::this_thread::sleep_for(std::chrono::milliseconds(200));
86 
87     timer.unregisterTimerCallback(action);
88 
89     std::this_thread::sleep_for(std::chrono::milliseconds(200));
90 
91     clearCalledCallbacks();
92 
93     timer.registerTimerCallback(interval, action);
94 
95     std::this_thread::sleep_for(std::chrono::seconds(1));
96 
97     // Theoretically trigger 10 times, but check for at least 9 times to be stable.
98     ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
99 }
100 
TEST_F(RecurrentTimerTest,testDestroyTimerWithCallback)101 TEST_F(RecurrentTimerTest, testDestroyTimerWithCallback) {
102     std::unique_ptr<RecurrentTimer> timer = std::make_unique<RecurrentTimer>();
103     // 0.1s
104     int64_t interval = 100000000;
105 
106     auto action = getCallback(0);
107     timer->registerTimerCallback(interval, action);
108 
109     std::this_thread::sleep_for(std::chrono::milliseconds(200));
110 
111     timer.reset();
112 
113     clearCalledCallbacks();
114 
115     std::this_thread::sleep_for(std::chrono::milliseconds(200));
116 
117     ASSERT_TRUE(getCalledCallbacks().empty());
118 }
119 
TEST_F(RecurrentTimerTest,testRegisterMultipleCallbacks)120 TEST_F(RecurrentTimerTest, testRegisterMultipleCallbacks) {
121     RecurrentTimer timer;
122     // 0.1s
123     int64_t interval1 = 100000000;
124     auto action1 = getCallback(1);
125     timer.registerTimerCallback(interval1, action1);
126     // 0.05s
127     int64_t interval2 = 50000000;
128     auto action2 = getCallback(2);
129     timer.registerTimerCallback(interval2, action2);
130     // 0.03s
131     int64_t interval3 = 30000000;
132     auto action3 = getCallback(3);
133     timer.registerTimerCallback(interval3, action3);
134 
135     std::this_thread::sleep_for(std::chrono::seconds(1));
136 
137     timer.unregisterTimerCallback(action1);
138     timer.unregisterTimerCallback(action2);
139     timer.unregisterTimerCallback(action3);
140 
141     size_t action1Count = 0;
142     size_t action2Count = 0;
143     size_t action3Count = 0;
144     for (size_t token : getCalledCallbacks()) {
145         if (token == 1) {
146             action1Count++;
147         }
148         if (token == 2) {
149             action2Count++;
150         }
151         if (token == 3) {
152             action3Count++;
153         }
154     }
155     // Theoretically trigger 10 times, but check for at least 9 times to be stable.
156     ASSERT_GE(action1Count, static_cast<size_t>(9));
157     // Theoretically trigger 20 times, but check for at least 15 times to be stable.
158     ASSERT_GE(action2Count, static_cast<size_t>(15));
159     // Theoretically trigger 33 times, but check for at least 25 times to be stable.
160     ASSERT_GE(action3Count, static_cast<size_t>(25));
161 }
162 
TEST_F(RecurrentTimerTest,testRegisterSameCallbackMultipleTimes)163 TEST_F(RecurrentTimerTest, testRegisterSameCallbackMultipleTimes) {
164     RecurrentTimer timer;
165     // 0.02s
166     int64_t interval1 = 20000000;
167     // 0.01s
168     int64_t interval2 = 10000000;
169 
170     auto action = getCallback(0);
171     for (int i = 0; i < 10; i++) {
172         timer.registerTimerCallback(interval1, action);
173         timer.registerTimerCallback(interval2, action);
174     }
175 
176     clearCalledCallbacks();
177 
178     std::this_thread::sleep_for(std::chrono::milliseconds(100));
179 
180     // Theoretically trigger 10 times, but check for at least 9 times to be stable.
181     ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
182 
183     timer.unregisterTimerCallback(action);
184 
185     // Make sure there is no item in the callback queue.
186     ASSERT_EQ(countTimerCallbackQueue(&timer), static_cast<size_t>(0));
187 }
188 
TEST_F(RecurrentTimerTest,testRegisterCallbackMultipleTimesNoDeadLock)189 TEST_F(RecurrentTimerTest, testRegisterCallbackMultipleTimesNoDeadLock) {
190     // We want to avoid the following situation:
191     // Caller holds a lock while calling registerTimerCallback, registerTimerCallback will try
192     // to obtain an internal lock inside timer.
193     // Meanwhile an recurrent action happens with timer holding an internal lock. The action
194     // tries to obtain the lock currently hold by the caller.
195     // The solution is that while calling recurrent actions, timer must not hold the internal lock.
196 
197     std::unique_ptr<RecurrentTimer> timer = std::make_unique<RecurrentTimer>();
198     std::mutex lock;
199     for (size_t i = 0; i < 1000; i++) {
200         std::scoped_lock<std::mutex> lockGuard(lock);
201         auto action = std::make_shared<RecurrentTimer::Callback>([&lock] {
202             // While calling this function, the timer must not hold lock in order not to dead
203             // lock.
204             std::scoped_lock<std::mutex> lockGuard(lock);
205         });
206         // 10ms
207         int64_t interval = 10'000'000;
208         timer->registerTimerCallback(interval, action);
209         // Sleep for a little while to let the recurrent actions begin.
210         std::this_thread::sleep_for(std::chrono::milliseconds(1));
211     }
212     // Make sure we stop the timer before we destroy lock.
213     timer.reset();
214 }
215 
216 }  // namespace vehicle
217 }  // namespace automotive
218 }  // namespace hardware
219 }  // namespace android
220