blob: 0e8f0a462e8a060c37b7dcab7a2c656df7f17c2b [file] [log] [blame]
Jack Hec27d2572018-07-25 12:02:22 -07001/*
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 */
Jakub Pawlowski67f5f372018-07-23 10:00:25 -070016#include "message_loop_thread.h"
Jack Hec27d2572018-07-25 12:02:22 -070017
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>
Jack Hec27d2572018-07-25 12:02:22 -070026#include <sys/capability.h>
27#include <syscall.h>
28
Jack Hec27d2572018-07-25 12:02:22 -070029using bluetooth::common::MessageLoopThread;
30
31/**
32 * Unit tests to verify MessageLoopThread. Must have CAP_SYS_NICE capability.
33 */
34class MessageLoopThreadTest : public ::testing::Test {
35 public:
36 void ShouldNotHappen() { FAIL() << "Should not happen"; }
37
Jack Hef607f2d2018-08-24 17:14:10 -070038 void GetThreadId(std::promise<base::PlatformThreadId> thread_id_promise) {
39 thread_id_promise.set_value(base::PlatformThread::CurrentId());
Jack Hec27d2572018-07-25 12:02:22 -070040 }
41
Jack Hef607f2d2018-08-24 17:14:10 -070042 void GetLinuxTid(std::promise<pid_t> tid_promise) {
43 tid_promise.set_value(static_cast<pid_t>(syscall(SYS_gettid)));
Jack Hec27d2572018-07-25 12:02:22 -070044 }
45
Jack Hef607f2d2018-08-24 17:14:10 -070046 void GetName(std::promise<std::string> name_promise) {
Jack Hec27d2572018-07-25 12:02:22 -070047 char my_name[256];
48 pthread_getname_np(pthread_self(), my_name, sizeof(my_name));
Jack Hef607f2d2018-08-24 17:14:10 -070049 name_promise.set_value(my_name);
Jack Hec27d2572018-07-25 12:02:22 -070050 }
51
Jack Hef607f2d2018-08-24 17:14:10 -070052 void GetSchedulingPolicyAndPriority(int* scheduling_policy,
53 int* schedule_priority,
54 std::promise<void> execution_promise) {
Jack Hec27d2572018-07-25 12:02:22 -070055 *scheduling_policy = sched_getscheduler(0);
56 struct sched_param param = {};
57 ASSERT_EQ(sched_getparam(0, &param), 0);
58 *schedule_priority = param.sched_priority;
Jack Hef607f2d2018-08-24 17:14:10 -070059 execution_promise.set_value();
Jack Hec27d2572018-07-25 12:02:22 -070060 }
61
Hansong Zhang438b08c2018-08-14 14:29:23 -070062 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
Jack Hec27d2572018-07-25 12:02:22 -070067 protected:
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
Hansong Zhang438b08c2018-08-14 14:29:23 -070084TEST_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
Jack Hec27d2572018-07-25 12:02:22 -070094TEST_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
104TEST_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
112TEST_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
118TEST_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
126TEST_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
136TEST_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);
Jack Hef607f2d2018-08-24 17:14:10 -0700141 std::promise<std::string> name_promise;
142 std::future<std::string> name_future = name_promise.get_future();
Jack Hec27d2572018-07-25 12:02:22 -0700143 message_loop_thread.DoInThread(
144 FROM_HERE,
Jack Hef607f2d2018-08-24 17:14:10 -0700145 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);
Jack Hec27d2572018-07-25 12:02:22 -0700149 ASSERT_EQ(name, message_loop_thread.GetName());
150}
151
152TEST_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);
Jack Hef607f2d2018-08-24 17:14:10 -0700158 std::promise<base::PlatformThreadId> thread_id_promise;
159 std::future<base::PlatformThreadId> thread_id_future =
160 thread_id_promise.get_future();
Jack Hec27d2572018-07-25 12:02:22 -0700161 message_loop_thread.DoInThread(
162 FROM_HERE,
Jack Hef607f2d2018-08-24 17:14:10 -0700163 base::BindOnce(&MessageLoopThreadTest::GetThreadId,
164 base::Unretained(this), std::move(thread_id_promise)));
165 base::PlatformThreadId my_thread_id = thread_id_future.get();
Jack Hec27d2572018-07-25 12:02:22 -0700166 ASSERT_EQ(thread_id, my_thread_id);
167}
168
169TEST_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
175TEST_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 }
Jack Hef607f2d2018-08-24 17:14:10 -0700194 std::promise<void> execution_promise;
195 std::future<void> execution_future = execution_promise.get_future();
Jack Hec27d2572018-07-25 12:02:22 -0700196 int scheduling_policy = -1;
197 int scheduling_priority = -1;
198 message_loop_thread.DoInThread(
199 FROM_HERE,
Jack Hef607f2d2018-08-24 17:14:10 -0700200 base::BindOnce(&MessageLoopThreadTest::GetSchedulingPolicyAndPriority,
201 base::Unretained(this), &scheduling_policy,
202 &scheduling_priority, std::move(execution_promise)));
203 execution_future.wait();
Jack Hec27d2572018-07-25 12:02:22 -0700204 ASSERT_EQ(scheduling_policy, SCHED_FIFO);
205 // Internal implementation verified here
206 ASSERT_EQ(scheduling_priority, 1);
Jack Hef607f2d2018-08-24 17:14:10 -0700207 std::promise<pid_t> tid_promise;
208 std::future<pid_t> tid_future = tid_promise.get_future();
Jack Hec27d2572018-07-25 12:02:22 -0700209 message_loop_thread.DoInThread(
210 FROM_HERE,
Jack Hef607f2d2018-08-24 17:14:10 -0700211 base::BindOnce(&MessageLoopThreadTest::GetLinuxTid,
212 base::Unretained(this), std::move(tid_promise)));
213 pid_t linux_tid = tid_future.get();
Jack Hec27d2572018-07-25 12:02:22 -0700214 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, &param), 0);
218 // Internal implementation verified here
219 ASSERT_EQ(param.sched_priority, 1);
220}
221
222TEST_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
228TEST_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
235TEST_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
244TEST_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());
Jack Hef607f2d2018-08-24 17:14:10 -0700263}
Hansong Zhang438b08c2018-08-14 14:29:23 -0700264
265// Verify the message loop thread will shutdown after callback finishes
266TEST_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}
Hansong Zhangd7831402018-09-29 14:23:31 -0700281
282// Verify the message loop thread will shutdown after callback finishes
283TEST_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
295TEST_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
305TEST_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
314TEST_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
323TEST_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}