1 /*
2 * Copyright 2018 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 #include "message_loop_thread.h"
17
18 #include <condition_variable>
19 #include <memory>
20 #include <mutex>
21
22 #include <gtest/gtest.h>
23
24 #include <base/bind.h>
25 #include <base/threading/platform_thread.h>
26 #include <sys/capability.h>
27 #include <syscall.h>
28
29 using bluetooth::common::MessageLoopThread;
30
31 /**
32 * Unit tests to verify MessageLoopThread. Must have CAP_SYS_NICE capability.
33 */
34 class MessageLoopThreadTest : public ::testing::Test {
35 public:
ShouldNotHappen()36 void ShouldNotHappen() { FAIL() << "Should not happen"; }
37
GetThreadId(std::promise<base::PlatformThreadId> thread_id_promise)38 void GetThreadId(std::promise<base::PlatformThreadId> thread_id_promise) {
39 thread_id_promise.set_value(base::PlatformThread::CurrentId());
40 }
41
GetLinuxTid(std::promise<pid_t> tid_promise)42 void GetLinuxTid(std::promise<pid_t> tid_promise) {
43 tid_promise.set_value(static_cast<pid_t>(syscall(SYS_gettid)));
44 }
45
GetName(std::promise<std::string> name_promise)46 void GetName(std::promise<std::string> name_promise) {
47 char my_name[256];
48 pthread_getname_np(pthread_self(), my_name, sizeof(my_name));
49 name_promise.set_value(my_name);
50 }
51
GetSchedulingPolicyAndPriority(int * scheduling_policy,int * schedule_priority,std::promise<void> execution_promise)52 void GetSchedulingPolicyAndPriority(int* scheduling_policy,
53 int* schedule_priority,
54 std::promise<void> execution_promise) {
55 *scheduling_policy = sched_getscheduler(0);
56 struct sched_param param = {};
57 ASSERT_EQ(sched_getparam(0, ¶m), 0);
58 *schedule_priority = param.sched_priority;
59 execution_promise.set_value();
60 }
61
SleepAndGetName(std::promise<std::string> name_promise,int sleep_ms)62 void SleepAndGetName(std::promise<std::string> name_promise, int sleep_ms) {
63 std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
64 GetName(std::move(name_promise));
65 }
66
67 protected:
CanSetCurrentThreadPriority()68 static bool CanSetCurrentThreadPriority() {
69 struct __user_cap_header_struct linux_user_header = {
70 .version = _LINUX_CAPABILITY_VERSION_3};
71 struct __user_cap_data_struct linux_user_data = {};
72 if (capget(&linux_user_header, &linux_user_data) != 0) {
73 LOG(ERROR) << "Failed to get capability for current thread, error: "
74 << strerror(errno);
75 // Log record in XML
76 RecordProperty("MessageLoopThreadTestCannotGetCapabilityReason",
77 strerror(errno));
78 return false;
79 }
80 return ((linux_user_data.permitted >> CAP_SYS_NICE) & 0x1) != 0;
81 }
82 };
83
TEST_F(MessageLoopThreadTest,get_weak_ptr)84 TEST_F(MessageLoopThreadTest, get_weak_ptr) {
85 base::WeakPtr<MessageLoopThread> message_loop_thread_ptr;
86 {
87 MessageLoopThread message_loop_thread("test_thread");
88 message_loop_thread_ptr = message_loop_thread.GetWeakPtr();
89 ASSERT_NE(message_loop_thread_ptr, nullptr);
90 }
91 ASSERT_EQ(message_loop_thread_ptr, nullptr);
92 }
93
TEST_F(MessageLoopThreadTest,test_running_thread)94 TEST_F(MessageLoopThreadTest, test_running_thread) {
95 MessageLoopThread message_loop_thread("test_thread");
96 message_loop_thread.StartUp();
97 ASSERT_GE(message_loop_thread.GetThreadId(), 0);
98 ASSERT_TRUE(message_loop_thread.IsRunning());
99 message_loop_thread.ShutDown();
100 ASSERT_LT(message_loop_thread.GetThreadId(), 0);
101 ASSERT_FALSE(message_loop_thread.IsRunning());
102 }
103
TEST_F(MessageLoopThreadTest,test_not_self)104 TEST_F(MessageLoopThreadTest, test_not_self) {
105 MessageLoopThread message_loop_thread("test_thread");
106 message_loop_thread.StartUp();
107 ASSERT_GE(message_loop_thread.GetThreadId(), 0);
108 ASSERT_NE(message_loop_thread.GetThreadId(),
109 base::PlatformThread::CurrentId());
110 }
111
TEST_F(MessageLoopThreadTest,test_shutdown_without_start)112 TEST_F(MessageLoopThreadTest, test_shutdown_without_start) {
113 MessageLoopThread message_loop_thread("test_thread");
114 message_loop_thread.ShutDown();
115 ASSERT_LT(message_loop_thread.GetThreadId(), 0);
116 }
117
TEST_F(MessageLoopThreadTest,test_do_in_thread_before_start)118 TEST_F(MessageLoopThreadTest, test_do_in_thread_before_start) {
119 std::string name = "test_thread";
120 MessageLoopThread message_loop_thread(name);
121 ASSERT_FALSE(message_loop_thread.DoInThread(
122 FROM_HERE, base::Bind(&MessageLoopThreadTest::ShouldNotHappen,
123 base::Unretained(this))));
124 }
125
TEST_F(MessageLoopThreadTest,test_do_in_thread_after_shutdown)126 TEST_F(MessageLoopThreadTest, test_do_in_thread_after_shutdown) {
127 std::string name = "test_thread";
128 MessageLoopThread message_loop_thread(name);
129 message_loop_thread.StartUp();
130 message_loop_thread.ShutDown();
131 ASSERT_FALSE(message_loop_thread.DoInThread(
132 FROM_HERE, base::Bind(&MessageLoopThreadTest::ShouldNotHappen,
133 base::Unretained(this))));
134 }
135
TEST_F(MessageLoopThreadTest,test_name)136 TEST_F(MessageLoopThreadTest, test_name) {
137 std::string name = "test_thread";
138 MessageLoopThread message_loop_thread(name);
139 message_loop_thread.StartUp();
140 ASSERT_GE(message_loop_thread.GetThreadId(), 0);
141 std::promise<std::string> name_promise;
142 std::future<std::string> name_future = name_promise.get_future();
143 message_loop_thread.DoInThread(
144 FROM_HERE,
145 base::BindOnce(&MessageLoopThreadTest::GetName, base::Unretained(this),
146 std::move(name_promise)));
147 std::string my_name = name_future.get();
148 ASSERT_EQ(name, my_name);
149 ASSERT_EQ(name, message_loop_thread.GetName());
150 }
151
TEST_F(MessageLoopThreadTest,test_thread_id)152 TEST_F(MessageLoopThreadTest, test_thread_id) {
153 std::string name = "test_thread";
154 MessageLoopThread message_loop_thread(name);
155 message_loop_thread.StartUp();
156 base::PlatformThreadId thread_id = message_loop_thread.GetThreadId();
157 ASSERT_GE(thread_id, 0);
158 std::promise<base::PlatformThreadId> thread_id_promise;
159 std::future<base::PlatformThreadId> thread_id_future =
160 thread_id_promise.get_future();
161 message_loop_thread.DoInThread(
162 FROM_HERE,
163 base::BindOnce(&MessageLoopThreadTest::GetThreadId,
164 base::Unretained(this), std::move(thread_id_promise)));
165 base::PlatformThreadId my_thread_id = thread_id_future.get();
166 ASSERT_EQ(thread_id, my_thread_id);
167 }
168
TEST_F(MessageLoopThreadTest,test_set_realtime_priority_fail_before_start)169 TEST_F(MessageLoopThreadTest, test_set_realtime_priority_fail_before_start) {
170 std::string name = "test_thread";
171 MessageLoopThread message_loop_thread(name);
172 ASSERT_FALSE(message_loop_thread.EnableRealTimeScheduling());
173 }
174
TEST_F(MessageLoopThreadTest,test_set_realtime_priority_success)175 TEST_F(MessageLoopThreadTest, test_set_realtime_priority_success) {
176 std::string name = "test_thread";
177 MessageLoopThread message_loop_thread(name);
178 message_loop_thread.StartUp();
179 bool ret = message_loop_thread.EnableRealTimeScheduling();
180 if (!ret) {
181 if (CanSetCurrentThreadPriority()) {
182 FAIL() << "Cannot set real time priority even though we have permission";
183 } else {
184 LOG(WARNING) << "Allowing EnableRealTimeScheduling to fail because we"
185 " don't have CAP_SYS_NICE capability";
186 // Log record in XML
187 RecordProperty("MessageLoopThreadTestConditionalSuccess",
188 "Mark test as success even though EnableRealTimeScheduling"
189 " failed because we don't have CAP_SYS_NICE capability");
190 // Quit early since further verification is no longer needed
191 return;
192 }
193 }
194 std::promise<void> execution_promise;
195 std::future<void> execution_future = execution_promise.get_future();
196 int scheduling_policy = -1;
197 int scheduling_priority = -1;
198 message_loop_thread.DoInThread(
199 FROM_HERE,
200 base::BindOnce(&MessageLoopThreadTest::GetSchedulingPolicyAndPriority,
201 base::Unretained(this), &scheduling_policy,
202 &scheduling_priority, std::move(execution_promise)));
203 execution_future.wait();
204 ASSERT_EQ(scheduling_policy, SCHED_FIFO);
205 // Internal implementation verified here
206 ASSERT_EQ(scheduling_priority, 1);
207 std::promise<pid_t> tid_promise;
208 std::future<pid_t> tid_future = tid_promise.get_future();
209 message_loop_thread.DoInThread(
210 FROM_HERE,
211 base::BindOnce(&MessageLoopThreadTest::GetLinuxTid,
212 base::Unretained(this), std::move(tid_promise)));
213 pid_t linux_tid = tid_future.get();
214 ASSERT_GT(linux_tid, 0);
215 ASSERT_EQ(sched_getscheduler(linux_tid), SCHED_FIFO);
216 struct sched_param param = {};
217 ASSERT_EQ(sched_getparam(linux_tid, ¶m), 0);
218 // Internal implementation verified here
219 ASSERT_EQ(param.sched_priority, 1);
220 }
221
TEST_F(MessageLoopThreadTest,test_message_loop_null_before_start)222 TEST_F(MessageLoopThreadTest, test_message_loop_null_before_start) {
223 std::string name = "test_thread";
224 MessageLoopThread message_loop_thread(name);
225 ASSERT_EQ(message_loop_thread.message_loop(), nullptr);
226 }
227
TEST_F(MessageLoopThreadTest,test_message_loop_not_null_start)228 TEST_F(MessageLoopThreadTest, test_message_loop_not_null_start) {
229 std::string name = "test_thread";
230 MessageLoopThread message_loop_thread(name);
231 message_loop_thread.StartUp();
232 ASSERT_NE(message_loop_thread.message_loop(), nullptr);
233 }
234
TEST_F(MessageLoopThreadTest,test_message_loop_null_after_stop)235 TEST_F(MessageLoopThreadTest, test_message_loop_null_after_stop) {
236 std::string name = "test_thread";
237 MessageLoopThread message_loop_thread(name);
238 message_loop_thread.StartUp();
239 ASSERT_NE(message_loop_thread.message_loop(), nullptr);
240 message_loop_thread.ShutDown();
241 ASSERT_EQ(message_loop_thread.message_loop(), nullptr);
242 }
243
TEST_F(MessageLoopThreadTest,test_to_string_method)244 TEST_F(MessageLoopThreadTest, test_to_string_method) {
245 std::string name = "test_thread";
246 MessageLoopThread message_loop_thread(name);
247 std::string thread_string_before_start = message_loop_thread.ToString();
248 ASSERT_FALSE(thread_string_before_start.empty());
249 LOG(INFO) << "Before start: " << message_loop_thread;
250 message_loop_thread.StartUp();
251 std::string thread_string_running = message_loop_thread.ToString();
252 ASSERT_FALSE(thread_string_running.empty());
253 LOG(INFO) << "Running: " << message_loop_thread;
254 // String representation should look different when thread is not running
255 ASSERT_STRNE(thread_string_running.c_str(),
256 thread_string_before_start.c_str());
257 message_loop_thread.ShutDown();
258 std::string thread_string_after_shutdown = message_loop_thread.ToString();
259 LOG(INFO) << "After shutdown: " << message_loop_thread;
260 // String representation should look the same when thread is not running
261 ASSERT_STREQ(thread_string_after_shutdown.c_str(),
262 thread_string_before_start.c_str());
263 }
264
265 // Verify the message loop thread will shutdown after callback finishes
TEST_F(MessageLoopThreadTest,shut_down_while_in_callback)266 TEST_F(MessageLoopThreadTest, shut_down_while_in_callback) {
267 std::string name = "test_thread";
268 MessageLoopThread message_loop_thread(name);
269 message_loop_thread.StartUp();
270 std::promise<std::string> name_promise;
271 std::future<std::string> name_future = name_promise.get_future();
272 uint32_t delay_ms = 5;
273 message_loop_thread.DoInThread(
274 FROM_HERE, base::BindOnce(&MessageLoopThreadTest::SleepAndGetName,
275 base::Unretained(this), std::move(name_promise),
276 delay_ms));
277 message_loop_thread.ShutDown();
278 std::string my_name = name_future.get();
279 ASSERT_EQ(name, my_name);
280 }
281
282 // Verify the message loop thread will shutdown after callback finishes
TEST_F(MessageLoopThreadTest,shut_down_while_in_callback_check_lock)283 TEST_F(MessageLoopThreadTest, shut_down_while_in_callback_check_lock) {
284 std::string name = "test_thread";
285 MessageLoopThread message_loop_thread(name);
286 message_loop_thread.StartUp();
287 message_loop_thread.DoInThread(
288 FROM_HERE,
289 base::BindOnce([](MessageLoopThread* thread) { thread->IsRunning(); },
290 &message_loop_thread));
291 message_loop_thread.ShutDown();
292 }
293
294 // Verify multiple threads try shutdown, no deadlock/crash
TEST_F(MessageLoopThreadTest,shut_down_multi_thread)295 TEST_F(MessageLoopThreadTest, shut_down_multi_thread) {
296 std::string name = "test_thread";
297 MessageLoopThread message_loop_thread(name);
298 message_loop_thread.StartUp();
299 auto thread = std::thread(&MessageLoopThread::ShutDown, &message_loop_thread);
300 message_loop_thread.ShutDown();
301 thread.join();
302 }
303
304 // Verify multiple threads try startup, no deadlock/crash
TEST_F(MessageLoopThreadTest,start_up_multi_thread)305 TEST_F(MessageLoopThreadTest, start_up_multi_thread) {
306 std::string name = "test_thread";
307 MessageLoopThread message_loop_thread(name);
308 message_loop_thread.StartUp();
309 auto thread = std::thread(&MessageLoopThread::StartUp, &message_loop_thread);
310 thread.join();
311 }
312
313 // Verify multiple threads try startup/shutdown, no deadlock/crash
TEST_F(MessageLoopThreadTest,start_up_shut_down_multi_thread)314 TEST_F(MessageLoopThreadTest, start_up_shut_down_multi_thread) {
315 std::string name = "test_thread";
316 MessageLoopThread message_loop_thread(name);
317 message_loop_thread.StartUp();
318 auto thread = std::thread(&MessageLoopThread::ShutDown, &message_loop_thread);
319 thread.join();
320 }
321
322 // Verify multiple threads try shutdown/startup, no deadlock/crash
TEST_F(MessageLoopThreadTest,shut_down_start_up_multi_thread)323 TEST_F(MessageLoopThreadTest, shut_down_start_up_multi_thread) {
324 std::string name = "test_thread";
325 MessageLoopThread message_loop_thread(name);
326 message_loop_thread.StartUp();
327 message_loop_thread.ShutDown();
328 auto thread = std::thread(&MessageLoopThread::StartUp, &message_loop_thread);
329 thread.join();
330 }
331