1 /*
2 * Copyright (C) 2023 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 <audio_utils/mutex.h>
18 #include <gtest/gtest.h>
19
20 #include <thread>
21
22 using namespace std::chrono_literals;
23
24 // Currently tests mutex priority-inheritance (or not) based on flag
25 // adb shell setprop \
26 // persist.device_config.aconfig_flags.media_audio.\
27 // com.android.media.audio.flags.mutex_priority_inheritance true
28 //
29 // TODO(b/209491695) enable both PI/non-PI mutex tests regardless of flag.
30
31 namespace android {
32
33 namespace audio_locks {
34
35 // Audio capabilities are typically assigned a partial order -
36 // but to furnish a proof of deadlock free audio, we create a global order
37 // (which isn't unique, just used to prove deadlock free access).
38
39 // Clang thread-safety can assigns capabilities to mutex-like objects.
40 // Here we use pointers to audio_utils::mutex*, they can be nullptr (never allocated)
41 // because they are used solely as a capability declaration, not as a mutex
42 // instance.
43 //
44 // In this example, we have 4 capabilities, labeled cap1, cap2, cap3, cap4.
45 // We'll show later in the IContainer.h example how we assign
46 // capabilities to actual mutexes.
47
48 // Add highest priority here
49 inline audio_utils::mutex* cap1;
50 inline audio_utils::mutex* cap2 ACQUIRED_AFTER(cap1);
51 inline audio_utils::mutex* cap3 ACQUIRED_AFTER(cap2);
52 inline audio_utils::mutex* cap4 ACQUIRED_AFTER(cap3);
53 // Add lowest priority here
54
55 // Now ACQUIRED_AFTER() isn't implemented (yet) in Clang Thread-Safety.
56 // As a solution, we define priority exclusion for lock acquisition.
57 // if you lock at a capability n, then you cannot hold
58 // locks at a lower capability (n+1, n+2, ...) otherwise
59 // there is lock inversion.
60
61 #define EXCLUDES_BELOW_4 // no capability below 4.
62 #define EXCLUDES_4 EXCLUDES(cap4) EXCLUDES_BELOW_4
63
64 #define EXCLUDES_BELOW_3 EXCLUDES_4
65 #define EXCLUDES_3 EXCLUDES(cap3) EXCLUDES_BELOW_3
66
67 #define EXCLUDES_BELOW_2 EXCLUDES_3
68 #define EXCLUDES_2 EXCLUDES(cap2) EXCLUDES_BELOW_2
69
70 #define EXCLUDES_BELOW_1 EXCLUDES_2
71 #define EXCLUDES_1 EXCLUDES(cap1) EXCLUDES_BELOW_1
72
73 #define EXCLUDES_ALL EXCLUDES_1
74
75 } // namespace audio_locks
76
77 using namespace audio_locks;
78 // -----------------------------------------
79
80 // Example IContainer.h
81 //
82 // This is a Container interface with multiple exposed mutexes.
83 // Since the capabilities file audio_locks.h is global,
84 // this interface can be used in projects outside of the implementing
85 // project.
86
87 // Here RETURN_CAPABILITY is used to assign a capability to a mutex.
88
89 class IContainer {
90 public:
91 virtual ~IContainer() = default;
92
93 // This is an example of returning many mutexes for test purposes.
94 // In AudioFlinger interfaces, we may return mutexes for locking
95 // AudioFlinger_Mutex, AudioFlinger_ClientMutex, ThreadBase_Mutex, etc. for interface methods.
96 //
97 // We do not allow access to the mutex when holding a mutex of lower priority, so
98 // we use EXCLUDES_....
99 virtual audio_utils::mutex& mutex1() const RETURN_CAPABILITY(cap1) EXCLUDES_BELOW_1 = 0;
100 virtual audio_utils::mutex& mutex2() const RETURN_CAPABILITY(cap2) EXCLUDES_BELOW_2 = 0;
101 virtual audio_utils::mutex& mutex3() const RETURN_CAPABILITY(cap3) EXCLUDES_BELOW_3 = 0;
102
103 // acquires capability 1, can't hold cap1 or lower level locks
104 virtual int value1() const EXCLUDES_1 = 0;
105
106 virtual int value1_l() const REQUIRES(cap1) = 0;
107 virtual int value2_l() const REQUIRES(cap2) = 0;
108 virtual int value3_l() const REQUIRES(cap3) = 0;
109
110 virtual int combo12_l() const REQUIRES(cap1) EXCLUDES_2 = 0;
111
112 // As value1, value2, value3 access requires cap1, cap2, cap3 individually,
113 // combo123_lll() requires all three.
114 virtual int combo123_lll() const REQUIRES(cap1, cap2, cap3) = 0;
115
116 // We cannot use any of mutex1, mutex2, mutex3, as they are acquired
117 // within the combo123() method.
118 // If we happen to know EXCLUDES_1 > EXCLUDES2 > EXCLUDES_3
119 // we could just use EXCLUDES_1. We include all 3 here.
120 virtual int combo123() const EXCLUDES_1 EXCLUDES_2 EXCLUDES_3 = 0;
121 };
122
123 // -----------------------------------------
124 //
125 // Example Container.cpp
126 //
127 // The container implemented the IContainer interface.
128 //
129 // We see here how the RETURN_CAPABILITY() is used to assign capability to mutexes.
130
131 class Container : public IContainer {
132 public:
133 // Here we implement the mutexes that has the global capabilities.
mutex1() const134 audio_utils::mutex& mutex1() const override RETURN_CAPABILITY(cap1) EXCLUDES_BELOW_1 {
135 return mMutex1;
136 }
137
mutex2() const138 audio_utils::mutex& mutex2() const override RETURN_CAPABILITY(cap2) EXCLUDES_BELOW_2 {
139 return mMutex2;
140 }
141
mutex3() const142 audio_utils::mutex& mutex3() const override RETURN_CAPABILITY(cap3) EXCLUDES_BELOW_3 {
143 return mMutex3;
144 }
145
146 // We use EXCLUDES_1 (which is prevents cap1 and all lesser priority mutexes)
147 // EXCLUDES(cap1) is not sufficient because if we acquire cap1,
148 // we ALSO can't hold lower level locks.
value1() const149 int value1() const override EXCLUDES_1 {
150
151 // Locking is through mutex1() to get the proper capability.
152 audio_utils::lock_guard l(mutex1());
153 return value1_l();
154 }
value1_l() const155 int value1_l() const override REQUIRES(cap1) {
156 return v1_;
157 }
value2_l() const158 int value2_l() const override REQUIRES(cap2) {
159 return v2_;
160 }
value3_l() const161 int value3_l() const override REQUIRES(cap3) {
162 return v3_;
163 }
164
165 // This requires cap1, acquires cap2.
combo12_l() const166 int combo12_l() const override REQUIRES(cap1) EXCLUDES_2 {
167
168 // Fails return value1_l() + value2_l() + value3_l();
169 audio_utils::lock_guard l(mutex2());
170 return value1_l() + value2_l();
171 }
172
173 #if 0
174 // fails!
175 int combo123_lll() REQUIRES(cap1, cap2, cap2) {
176 return value1_l() + value2_l() + value3_l();
177 }
178 #endif
179
180 // We can use REQUIRES(cap1, cap2, cap3)
181 // or REQUIRES(cap1, cap2, mutex3())
182 //
183 // The REQUIRES expression must be valid as the first line in the function body.
184 // This means that if the expression has visibility issues (accesses
185 // a private base class member from a derived class, etc.) it won't work.
186 // Quick test: Does a decltype(expr) work as the first line?
187 // If not, then REQUIRES(expr) won't either.
188 //
combo123_lll() const189 int combo123_lll() const override REQUIRES(cap1, cap2, mutex3()) {
190 return value1_l() + value2_l() + value3_l();
191 }
192
193 #if 1
194 // In this example, the 3 exclusions are needed because we acquire
195 // 3 locks. If we happen to know EXCLUDES_1 > EXCLUDES2 > EXCLUDES_3
196 // we could just use EXCLUDES_1. We include all 3 here.
combo123() const197 int combo123() const override EXCLUDES_1 EXCLUDES_2 EXCLUDES_3 {
198 audio_utils::lock_guard l1(mutex1());
199 audio_utils::lock_guard l2(mutex2());
200 audio_utils::lock_guard l3(mutex3());
201
202 return value1_l() + value2_l() + value3_l();
203 }
204
205 #else
206 // THIS FAILS
combo123() const207 int combo123() const override EXCLUDES_1 EXCLUDES_2 EXCLUDES_3 {
208 audio_utils::lock_guard l2(mutex2());
209 audio_utils::lock_guard l1(mutex1()); // 2 is acquired before 1.
210 audio_utils::lock_guard l3(mutex3());
211
212 return value1_l() + value2_l() + value3_l();
213 }
214 #endif
215
216 private:
217 // The actual implementation mutexes are never directly exposed.
218 mutable audio_utils::mutex mMutex1;
219 mutable audio_utils::mutex mMutex2;
220 mutable audio_utils::mutex mMutex3;
221
222 int v1_ GUARDED_BY(cap1) = 1;
223 int v2_ GUARDED_BY(mutex2()) = 2;
224 int v3_ GUARDED_BY(cap3) = 3;
225 };
226
TEST(audio_mutex_tests,Container)227 TEST(audio_mutex_tests, Container) {
228 Container c;
229
230 EXPECT_EQ(1, c.value1()); // success
231
232 #if 0
233 // fails
234 {
235 audio_utils::lock_guard(c.mutex1());
236 EXPECT_EQ(3, c.combo12_l());
237 }
238 #endif
239
240 {
241 audio_utils::lock_guard l(c.mutex1());
242 EXPECT_EQ(3, c.combo12_l()); // success
243 }
244 }
245
246 // Test access through the IContainer interface -
247 // see that mutex checking is done without knowledge of
248 // the actual implementation.
249
TEST(audio_mutex_tests,Interface)250 TEST(audio_mutex_tests, Interface) {
251 Container c;
252 IContainer *i = static_cast<IContainer*>(&c);
253
254 EXPECT_EQ(1, i->value1()); // success
255
256 #if 0
257 // fails
258 {
259 audio_utils::lock_guard(c.mutex1());
260 EXPECT_EQ(3, c.combo12_l());
261 }
262 #endif
263
264 {
265 audio_utils::lock_guard l(i->mutex1());
266 EXPECT_EQ(3, i->combo12_l()); // success
267 }
268
269 ALOGD("%s: %s", __func__, audio_utils::mutex::all_stats_to_string().c_str());
270 }
271
TEST(audio_mutex_tests,Stack)272 TEST(audio_mutex_tests, Stack) {
273 android::audio_utils::atomic_stack<int, int, 2> as;
274
275 // set up stack
276 EXPECT_EQ(0UL, as.size());
277 as.push(1, 10);
278 EXPECT_EQ(1UL, as.size());
279 as.push(2, 20);
280 EXPECT_EQ(2UL, as.size());
281
282 // 3rd item exceeds the stack capacity.
283 as.push(3, 30);
284 // 2 items tracked (subset)
285 EXPECT_EQ(2UL, as.size());
286 // 3 items total.
287 EXPECT_EQ(3UL, as.true_size());
288
289 const auto& bot = as.bottom();
290 const auto& top = as.top();
291
292 // these are the 2 items tracked:
293 EXPECT_EQ(1, bot.first.load());
294 EXPECT_EQ(10, bot.second.load());
295
296 EXPECT_EQ(3, top.first.load());
297 EXPECT_EQ(30, top.second.load());
298
299 // remove the bottom item.
300 EXPECT_EQ(true, as.remove(1));
301 EXPECT_EQ(1UL, as.size());
302 EXPECT_EQ(2UL, as.true_size());
303
304 // now remove the "virtual" item.
305 // (actually any non-existing item value works).
306 EXPECT_EQ(true, as.remove(2));
307 EXPECT_EQ(1UL, as.size());
308 EXPECT_EQ(1UL, as.true_size());
309
310 // now an invalid removal
311 EXPECT_EQ(false, as.remove(5));
312 EXPECT_EQ(1UL, as.size());
313 EXPECT_EQ(1UL, as.true_size());
314
315 // now remove the final item.
316 EXPECT_EQ(true, as.remove(3));
317 EXPECT_EQ(0UL, as.size());
318 EXPECT_EQ(0UL, as.true_size());
319 }
320
TEST(audio_mutex_tests,RecursiveLockDetection)321 TEST(audio_mutex_tests, RecursiveLockDetection) {
322 constexpr pid_t pid = 0; // avoid registry shutdown.
323 android::audio_utils::thread_mutex_info<int, int, 8 /* stack depth */> tmi(pid);
324
325 // set up stack
326 tmi.push_held(50, 1);
327 tmi.push_held(40, 2);
328 tmi.push_held(30, 3);
329 EXPECT_EQ(3UL, tmi.stack().size());
330
331 // remove bottom.
332 tmi.remove_held(50);
333 EXPECT_EQ(2UL, tmi.stack().size());
334
335 // test recursive lock detection.
336
337 // same order, same item is recursive.
338 const auto& recursive = tmi.check_held(30, 3);
339 EXPECT_EQ(30, recursive.first.load());
340 EXPECT_EQ(3, recursive.second.load());
341
342 // same order but different item (10 != 30) is OK.
343 const auto& nil = tmi.check_held(10, 3);
344 EXPECT_EQ(0, nil.first.load());
345 EXPECT_EQ(0, nil.second.load());
346 }
347
TEST(audio_mutex_tests,OrderDetection)348 TEST(audio_mutex_tests, OrderDetection) {
349 constexpr pid_t pid = 0; // avoid registry shutdown.
350 android::audio_utils::thread_mutex_info<int, int, 8 /* stack depth */> tmi(pid);
351
352 // set up stack
353 tmi.push_held(50, 1);
354 tmi.push_held(40, 2);
355 tmi.push_held(30, 3);
356 EXPECT_EQ(3UL, tmi.stack().size());
357
358 // remove middle
359 tmi.remove_held(40);
360 EXPECT_EQ(2UL, tmi.stack().size());
361
362 // test inversion detection.
363
364 // lower order is a problem 1 < 3.
365 const auto& inversion = tmi.check_held(1, 1);
366 EXPECT_EQ(30, inversion.first.load());
367 EXPECT_EQ(3, inversion.second.load());
368
369 // higher order is OK.
370 const auto& nil2 = tmi.check_held(4, 4);
371 EXPECT_EQ(0, nil2.first.load());
372 EXPECT_EQ(0, nil2.second.load());
373 }
374
375 // The following tests are evaluated for the android::audio_utils::mutex
376 // Non-Priority Inheritance and Priority Inheritance cases.
377
378 class MutexTestSuite : public testing::TestWithParam<bool> {};
379
380 // Test that the mutex aborts on recursion (if the abort flag is set).
381
TEST_P(MutexTestSuite,FatalRecursiveMutex)382 TEST_P(MutexTestSuite, FatalRecursiveMutex)
383 NO_THREAD_SAFETY_ANALYSIS {
384 if (!android::audio_utils::AudioMutexAttributes::abort_on_recursion_check_
385 || !audio_utils::mutex_get_enable_flag()) {
386 ALOGD("Test FatalRecursiveMutex skipped");
387 return;
388 }
389
390 using Mutex = android::audio_utils::mutex;
391 using LockGuard = android::audio_utils::lock_guard;
392 const bool priority_inheritance = GetParam();
393
394 Mutex m(priority_inheritance);
395 LockGuard lg(m);
396
397 // Can't lock ourselves again.
398 ASSERT_DEATH(m.lock(), ".*recursive mutex.*");
399 }
400
401 // Test that the mutex aborts on lock order inversion (if the abort flag is set).
402
TEST_P(MutexTestSuite,FatalLockOrder)403 TEST_P(MutexTestSuite, FatalLockOrder)
404 NO_THREAD_SAFETY_ANALYSIS {
405 if (!android::audio_utils::AudioMutexAttributes::abort_on_order_check_
406 || !audio_utils::mutex_get_enable_flag()) {
407 ALOGD("Test FatalLockOrder skipped");
408 return;
409 }
410
411 using Mutex = android::audio_utils::mutex;
412 using LockGuard = android::audio_utils::lock_guard;
413 const bool priority_inheritance = GetParam();
414
415 Mutex m1{priority_inheritance, (android::audio_utils::AudioMutexAttributes::order_t)1};
416 Mutex m2{priority_inheritance, (android::audio_utils::AudioMutexAttributes::order_t)2};
417
418 LockGuard lg2(m2);
419 // m1 must be locked before m2 as 1 < 2.
420 ASSERT_DEATH(m1.lock(), ".*mutex order.*");
421 }
422
423 // Test that the mutex aborts on lock order inversion (if the abort flag is set).
424
TEST_P(MutexTestSuite,UnexpectedUnlock)425 TEST_P(MutexTestSuite, UnexpectedUnlock)
426 NO_THREAD_SAFETY_ANALYSIS {
427 if (!android::audio_utils::AudioMutexAttributes::abort_on_invalid_unlock_
428 || !audio_utils::mutex_get_enable_flag()) {
429 ALOGD("Test UnexpectedUnlock skipped");
430 return;
431 }
432
433 using Mutex = android::audio_utils::mutex;
434 const bool priority_inheritance = GetParam();
435
436 Mutex m1{priority_inheritance, (android::audio_utils::AudioMutexAttributes::order_t)1};
437 ASSERT_DEATH(m1.unlock(), ".*mutex unlock.*");
438 }
439
TEST_P(MutexTestSuite,TimedLock)440 TEST_P(MutexTestSuite, TimedLock) {
441 using ConditionVariable = android::audio_utils::condition_variable;
442 using Mutex = android::audio_utils::mutex;
443 using UniqueLock = android::audio_utils::unique_lock;
444 const bool priority_inheritance = GetParam();
445
446 Mutex m{priority_inheritance}, m1{priority_inheritance};
447 ConditionVariable cv;
448 bool quit = false; // GUARDED_BY(m)
449
450 std::atomic<pid_t> tid1{};
451
452 // launch thread.
453 std::thread t1([&]() {
454 UniqueLock ul1(m1);
455 UniqueLock ul(m);
456 tid1 = android::audio_utils::gettid_wrapper();
457 while (!quit) {
458 cv.wait(ul, [&]{ return quit; });
459 if (quit) break;
460 }
461 });
462
463 // ensure thread tid1 has acquired all locks.
464 while (tid1 == 0) { usleep(1000); }
465
466 // try lock for 1s
467 constexpr int64_t kTimeoutNs = 1'000'000'000;
468 {
469 // verify timed out state.
470 const int64_t beginNs = systemTime();
471 const bool success = m1.try_lock(kTimeoutNs);
472 const int64_t endNs = systemTime();
473 const int64_t diffNs = endNs - beginNs;
474
475 if (success) m1.unlock();
476 EXPECT_GT(diffNs, kTimeoutNs);
477 EXPECT_FALSE(success);
478 }
479
480 // exit the thread
481 {
482 UniqueLock ul(m);
483
484 quit = true;
485 cv.notify_one();
486 }
487
488 t1.join();
489
490 {
491 // verify success state.
492 const int64_t beginNs = systemTime();
493 const bool success = m1.try_lock(kTimeoutNs);
494 const int64_t endNs = systemTime();
495 const int64_t diffNs = endNs - beginNs;
496
497 if (success) m1.unlock();
498 constexpr int64_t kSuccessLockNs = kTimeoutNs / 4;
499 EXPECT_LT(diffNs, kSuccessLockNs);
500 EXPECT_TRUE(success);
501 }
502 }
503
504 // Test the deadlock detection algorithm for a single wait chain
505 // (no cycle).
506
TEST_P(MutexTestSuite,DeadlockDetection)507 TEST_P(MutexTestSuite, DeadlockDetection) {
508 using Mutex = android::audio_utils::mutex;
509 using UniqueLock = android::audio_utils::unique_lock;
510 using ConditionVariable = android::audio_utils::condition_variable;
511 const bool priority_inheritance = GetParam();
512
513 // order checked below.
514 constexpr size_t kOrder1 = 1;
515 constexpr size_t kOrder2 = 2;
516 constexpr size_t kOrder3 = 3;
517 static_assert(Mutex::attributes_t::order_size_ > kOrder3);
518
519 Mutex m1{priority_inheritance, static_cast<Mutex::attributes_t::order_t>(kOrder1)};
520 Mutex m2{priority_inheritance, static_cast<Mutex::attributes_t::order_t>(kOrder2)};
521 Mutex m3{priority_inheritance, static_cast<Mutex::attributes_t::order_t>(kOrder3)};
522 Mutex m4{priority_inheritance};
523 Mutex m{priority_inheritance};
524 ConditionVariable cv;
525 bool quit = false; // GUARDED_BY(m)
526 std::atomic<pid_t> tid1{}, tid2{}, tid3{}, tid4{};
527
528 std::thread t4([&]() {
529 UniqueLock ul4(m4);
530 UniqueLock ul(m);
531 tid4 = android::audio_utils::gettid_wrapper();
532 while (!quit) {
533 cv.wait(ul, [&]{ return quit; });
534 if (quit) break;
535 }
536 });
537
538 while (tid4 == 0) { usleep(1000); }
539
540 std::thread t3([&]() {
541 UniqueLock ul3(m3);
542 tid3 = android::audio_utils::gettid_wrapper();
543 UniqueLock ul4(m4);
544 });
545
546 while (tid3 == 0) { usleep(1000); }
547
548 std::thread t2([&]() {
549 UniqueLock ul2(m2);
550 tid2 = android::audio_utils::gettid_wrapper();
551 UniqueLock ul3(m3);
552 });
553
554 while (tid2 == 0) { usleep(1000); }
555
556 std::thread t1([&]() {
557 UniqueLock ul1(m1);
558 tid1 = android::audio_utils::gettid_wrapper();
559 UniqueLock ul2(m2);
560 });
561
562 while (tid1 == 0) { usleep(1000); }
563
564 // we know that the threads will now block in the proper order.
565 // however, we need to wait for the block to happen.
566 // this part is racy unless we check the thread state or use
567 // futexes directly in our mutex (which allows atomic accuracy of wait).
568 usleep(20000);
569
570 const auto deadlockInfo = android::audio_utils::mutex::deadlock_detection(tid1);
571
572 // no cycle.
573 EXPECT_EQ(false, deadlockInfo.has_cycle);
574
575 // no condition_variable detected
576 EXPECT_EQ(audio_utils::other_wait_reason_t::none, deadlockInfo.other_wait_reason);
577
578 // thread1 is waiting on a chain of 3 other threads.
579 const auto chain = deadlockInfo.chain;
580 const size_t chain_size = chain.size();
581 EXPECT_EQ(3u, chain_size);
582
583 const auto default_idx = static_cast<size_t>(Mutex::attributes_t::order_default_);
584 if (chain_size > 0) {
585 EXPECT_EQ(tid2, chain[0].first);
586 EXPECT_EQ(Mutex::attributes_t::order_names_[kOrder2], chain[0].second);
587 }
588 if (chain_size > 1) {
589 EXPECT_EQ(tid3, chain[1].first);
590 EXPECT_EQ(Mutex::attributes_t::order_names_[kOrder3], chain[1].second);
591 }
592 if (chain_size > 2) {
593 EXPECT_EQ(tid4, chain[2].first);
594 EXPECT_EQ(Mutex::attributes_t::order_names_[default_idx], chain[2].second);
595 }
596
597 ALOGD("%s", android::audio_utils::mutex::all_threads_to_string().c_str());
598
599 {
600 UniqueLock ul(m);
601
602 quit = true;
603 cv.notify_one();
604 }
605
606 t4.join();
607 t3.join();
608 t2.join();
609 t1.join();
610 }
611
TEST_P(MutexTestSuite,DeadlockConditionVariableDetection)612 TEST_P(MutexTestSuite, DeadlockConditionVariableDetection) {
613 using Mutex = android::audio_utils::mutex;
614 using UniqueLock = android::audio_utils::unique_lock;
615 using ConditionVariable = android::audio_utils::condition_variable;
616 const bool priority_inheritance = GetParam();
617
618 // order checked below.
619 constexpr size_t kOrder1 = 1;
620 constexpr size_t kOrder2 = 2;
621 constexpr size_t kOrder3 = 3;
622 static_assert(Mutex::attributes_t::order_size_ > kOrder3);
623
624 Mutex m1{priority_inheritance, static_cast<Mutex::attributes_t::order_t>(kOrder1)};
625 Mutex m2{priority_inheritance, static_cast<Mutex::attributes_t::order_t>(kOrder2)};
626 Mutex m3{priority_inheritance, static_cast<Mutex::attributes_t::order_t>(kOrder3)};
627 Mutex m4{priority_inheritance};
628 Mutex m{priority_inheritance};
629 ConditionVariable cv, cv2, cv4;
630 bool quit = false; // GUARDED_BY(m)
631 std::atomic<pid_t> tid1{}, tid2{}, tid3{}, tid4{};
632
633 std::thread t4([&]() {
634 // UniqueLock ul4(m4);
635 UniqueLock ul(m);
636 tid4 = android::audio_utils::gettid_wrapper();
637 while (!quit) {
638 cv.wait(ul, [&]{ return quit; });
639 if (quit) break;
640 }
641 });
642
643 while (tid4 == 0) { usleep(1000); }
644
645 std::thread t3([&]() {
646 UniqueLock ul3(m3);
647 tid3 = android::audio_utils::gettid_wrapper();
648 UniqueLock ul4(m4);
649 while (!quit) {
650 // use the wait method with the notifier_tid metadata.
651 cv4.wait(ul4, [&]{ return quit; }, tid4);
652 if (quit) break;
653 }
654 });
655
656 while (tid3 == 0) { usleep(1000); }
657
658 std::thread t2([&]() {
659 // UniqueLock ul2(m2);
660 tid2 = android::audio_utils::gettid_wrapper();
661 UniqueLock ul3(m3);
662 });
663
664 while (tid2 == 0) { usleep(1000); }
665
666 std::thread t1([&]() {
667 UniqueLock ul1(m1);
668 tid1 = android::audio_utils::gettid_wrapper();
669 UniqueLock ul2(m2);
670 while (!quit) {
671 // use the wait method with the notifier_tid metadata.
672 cv2.wait(ul2, [&]{ return quit; }, tid2);
673 if (quit) break;
674 }
675 });
676
677 while (tid1 == 0) { usleep(1000); }
678
679 // we know that the threads will now block in the proper order.
680 // however, we need to wait for the block to happen.
681 // this part is racy unless we check the thread state or use
682 // futexes directly in our mutex (which allows atomic accuracy of wait).
683 usleep(20000);
684
685 const auto deadlockInfo = android::audio_utils::mutex::deadlock_detection(tid1);
686
687 // no cycle.
688 EXPECT_EQ(false, deadlockInfo.has_cycle);
689
690 // condition_variable detected
691 EXPECT_EQ(audio_utils::other_wait_reason_t::cv, deadlockInfo.other_wait_reason);
692
693 // thread1 is waiting on a chain of 3 other threads.
694 const auto chain = deadlockInfo.chain;
695 const size_t chain_size = chain.size();
696 EXPECT_EQ(3u, chain_size);
697
698 const auto default_idx = static_cast<size_t>(Mutex::attributes_t::order_default_);
699 if (chain_size > 0) {
700 EXPECT_EQ(tid2, chain[0].first);
701 EXPECT_EQ(std::string("cv-").append(Mutex::attributes_t::order_names_[kOrder2]).c_str(),
702 chain[0].second);
703 }
704 if (chain_size > 1) {
705 EXPECT_EQ(tid3, chain[1].first);
706 EXPECT_EQ(Mutex::attributes_t::order_names_[kOrder3], chain[1].second);
707 }
708 if (chain_size > 2) {
709 EXPECT_EQ(tid4, chain[2].first);
710 EXPECT_EQ(std::string("cv-").append(
711 Mutex::attributes_t::order_names_[default_idx]).c_str(), chain[2].second);
712 }
713
714 ALOGD("with cv all_threads_to_string():\n%s",
715 android::audio_utils::mutex::all_threads_to_string().c_str());
716 ALOGD("with cv deadlock_info_t:\n%s",
717 android::audio_utils::mutex::deadlock_detection(
718 tid1).to_string().c_str());
719
720 {
721 UniqueLock ul(m);
722 quit = true;
723 cv.notify_one();
724 }
725 {
726 UniqueLock ul2(m);
727 cv2.notify_one();
728 }
729 {
730 UniqueLock ul4(m);
731 cv4.notify_one();
732 }
733
734 t4.join();
735 t3.join();
736 t2.join();
737 t1.join();
738 }
739
TEST_P(MutexTestSuite,DeadlockJoinDetection)740 TEST_P(MutexTestSuite, DeadlockJoinDetection) {
741 using Mutex = android::audio_utils::mutex;
742 using UniqueLock = android::audio_utils::unique_lock;
743 using ConditionVariable = android::audio_utils::condition_variable;
744 const bool priority_inheritance = GetParam();
745
746 Mutex m{priority_inheritance};
747 ConditionVariable cv;
748 bool quit = false; // GUARDED_BY(m)
749 std::atomic<pid_t> tid1{}, tid2{}, tid3{}, tid4{};
750
751 std::thread t4([&]() {
752 UniqueLock ul(m);
753 tid4 = android::audio_utils::gettid_wrapper();
754 while (!quit) {
755 cv.wait(ul, [&]{ return quit; });
756 if (quit) break;
757 }
758 });
759
760 while (tid4 == 0) { std::this_thread::sleep_for(1ms); }
761
762 std::thread t3([&]() {
763 tid3 = android::audio_utils::gettid_wrapper();
764 audio_utils::mutex::scoped_join_wait_check sjw(tid4);
765 t4.join();
766 });
767
768 while (tid3 == 0) { std::this_thread::sleep_for(1ms); }
769
770 std::thread t2([&]() {
771 tid2 = android::audio_utils::gettid_wrapper();
772 audio_utils::mutex::scoped_join_wait_check sjw(tid3);
773 t3.join();
774 });
775
776 while (tid2 == 0) { std::this_thread::sleep_for(1ms); }
777
778 std::thread t1([&]() {
779 tid1 = android::audio_utils::gettid_wrapper();
780 audio_utils::mutex::scoped_join_wait_check sjw(tid2);
781 t2.join();
782 });
783
784 while (tid1 == 0) { std::this_thread::sleep_for(1ms); }
785
786 // we know that the threads will now block in the proper order.
787 // however, we need to wait for the block to happen.
788 // this part is racy unless we check the thread state or use
789 // futexes directly in our mutex (which allows atomic accuracy of wait).
790 std::this_thread::sleep_for(20ms);
791
792 const auto deadlockInfo = android::audio_utils::mutex::deadlock_detection(tid1);
793
794 // no cycle.
795 EXPECT_EQ(false, deadlockInfo.has_cycle);
796
797 // thread join detected
798 EXPECT_EQ(audio_utils::other_wait_reason_t::join, deadlockInfo.other_wait_reason);
799
800 // thread1 is attempting to join, in a chain of 3 other threads.
801 const auto chain = deadlockInfo.chain;
802 const size_t chain_size = chain.size();
803 EXPECT_EQ(3u, chain_size);
804
805 const auto default_idx = static_cast<size_t>(Mutex::attributes_t::order_default_);
806 if (chain_size > 0) {
807 EXPECT_EQ(tid2, chain[0].first);
808 EXPECT_EQ("join", chain[0].second);
809 }
810 if (chain_size > 1) {
811 EXPECT_EQ(tid3, chain[1].first);
812 EXPECT_EQ("join", chain[1].second);
813 }
814 if (chain_size > 2) {
815 EXPECT_EQ(tid4, chain[2].first);
816 EXPECT_EQ("join", chain[2].second);
817 }
818
819 ALOGD("with join all_threads_to_string():\n%s",
820 android::audio_utils::mutex::all_threads_to_string().c_str());
821 ALOGD("with join deadlock_info_t:\n%s",
822 android::audio_utils::mutex::deadlock_detection(
823 tid1).to_string().c_str());
824
825 {
826 UniqueLock ul(m);
827 quit = true;
828 cv.notify_one();
829 }
830 t1.join();
831 }
832
833 INSTANTIATE_TEST_SUITE_P(Mutex_NonPI_and_PI, MutexTestSuite, testing::Values(false, true));
834
835 } // namespace android
836