xref: /aosp_15_r20/system/media/audio_utils/tests/audio_mutex_tests.cpp (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
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 
TEST(audio_mutex_tests,StdTimedLock)376 TEST(audio_mutex_tests, StdTimedLock) {
377     using ConditionVariable = std::condition_variable;
378     using Mutex = std::mutex;
379     using UniqueLock = android::audio_utils::unique_lock<Mutex>;
380 
381     Mutex m, m1;
382     ConditionVariable cv;
383     bool quit = false;  // GUARDED_BY(m)
384 
385     std::atomic<pid_t> tid1{};
386 
387     // launch thread.
388     std::thread t1([&]() {
389         UniqueLock ul1(m1);
390         UniqueLock ul(m);
391         tid1 = android::audio_utils::gettid_wrapper();
392         while (!quit) {
393             cv.wait(ul, [&]{ return quit; });
394             if (quit) break;
395         }
396     });
397 
398     // ensure thread tid1 has acquired all locks.
399     while (tid1 == 0) { usleep(1000); }
400 
401     // try lock for 500ms.
402     // (don't make this too large otherwise the successful timeout will take > 500ms).
403     constexpr int64_t kTimeoutNs = 500'000'000;
404     {
405         //  verify timed out state.
406         const int64_t beginNs = systemTime();
407         const bool success = audio_utils::std_mutex_timed_lock(m1, kTimeoutNs);
408         const int64_t endNs = systemTime();
409         const int64_t diffNs = endNs - beginNs;
410 
411         if (success) m1.unlock();
412         EXPECT_GT(diffNs, kTimeoutNs);
413         EXPECT_FALSE(success);
414     }
415 
416     // exit the thread
417     {
418         UniqueLock ul(m);
419 
420         quit = true;
421         cv.notify_one();
422     }
423 
424     t1.join();
425 
426     {
427         // verify success state.
428         const int64_t beginNs = systemTime();
429         const bool success = audio_utils::std_mutex_timed_lock(m1, kTimeoutNs);
430         const int64_t endNs = systemTime();
431         const int64_t diffNs = endNs - beginNs;
432 
433         if (success) m1.unlock();
434 
435         // we're expecting to lock within 250ms (should be efficient).
436         constexpr int64_t kSuccessLockNs = 250'000'000;
437         EXPECT_LT(diffNs, kSuccessLockNs);
438         EXPECT_TRUE(success);
439     }
440 }
441 // The following tests are evaluated for the android::audio_utils::mutex
442 // Non-Priority Inheritance and Priority Inheritance cases.
443 
444 class MutexTestSuite : public testing::TestWithParam<bool> {};
445 
446 // Test that the mutex aborts on recursion (if the abort flag is set).
447 
TEST_P(MutexTestSuite,FatalRecursiveMutex)448 TEST_P(MutexTestSuite, FatalRecursiveMutex)
449 NO_THREAD_SAFETY_ANALYSIS {
450     if (!android::audio_utils::AudioMutexAttributes::abort_on_recursion_check_
451             || !audio_utils::mutex_get_enable_flag()) {
452         ALOGD("Test FatalRecursiveMutex skipped");
453         return;
454     }
455 
456     using Mutex = android::audio_utils::mutex;
457     using LockGuard = android::audio_utils::lock_guard;
458     const bool priority_inheritance = GetParam();
459 
460     Mutex m(priority_inheritance);
461     LockGuard lg(m);
462 
463     // Can't lock ourselves again.
464     ASSERT_DEATH(m.lock(), ".*recursive mutex.*");
465 }
466 
467 // Test that the mutex aborts on lock order inversion (if the abort flag is set).
468 
TEST_P(MutexTestSuite,FatalLockOrder)469 TEST_P(MutexTestSuite, FatalLockOrder)
470 NO_THREAD_SAFETY_ANALYSIS {
471     if (!android::audio_utils::AudioMutexAttributes::abort_on_order_check_
472             || !audio_utils::mutex_get_enable_flag()) {
473         ALOGD("Test FatalLockOrder skipped");
474         return;
475     }
476 
477     using Mutex = android::audio_utils::mutex;
478     using LockGuard = android::audio_utils::lock_guard;
479     const bool priority_inheritance = GetParam();
480 
481     Mutex m1{priority_inheritance, (android::audio_utils::AudioMutexAttributes::order_t)1};
482     Mutex m2{priority_inheritance, (android::audio_utils::AudioMutexAttributes::order_t)2};
483 
484     LockGuard lg2(m2);
485     // m1 must be locked before m2 as 1 < 2.
486     ASSERT_DEATH(m1.lock(), ".*mutex order.*");
487 }
488 
489 // Test that the mutex aborts on lock order inversion (if the abort flag is set).
490 
TEST_P(MutexTestSuite,UnexpectedUnlock)491 TEST_P(MutexTestSuite, UnexpectedUnlock)
492 NO_THREAD_SAFETY_ANALYSIS {
493     if (!android::audio_utils::AudioMutexAttributes::abort_on_invalid_unlock_
494             || !audio_utils::mutex_get_enable_flag()) {
495         ALOGD("Test UnexpectedUnlock skipped");
496         return;
497     }
498 
499     using Mutex = android::audio_utils::mutex;
500     const bool priority_inheritance = GetParam();
501 
502     Mutex m1{priority_inheritance, (android::audio_utils::AudioMutexAttributes::order_t)1};
503     ASSERT_DEATH(m1.unlock(), ".*mutex unlock.*");
504 }
505 
TEST_P(MutexTestSuite,TimedLock)506 TEST_P(MutexTestSuite, TimedLock) {
507     using ConditionVariable = android::audio_utils::condition_variable;
508     using Mutex = android::audio_utils::mutex;
509     using UniqueLock = android::audio_utils::unique_lock<Mutex>;
510     const bool priority_inheritance = GetParam();
511 
512     Mutex m{priority_inheritance}, m1{priority_inheritance};
513     ConditionVariable cv;
514     bool quit = false;  // GUARDED_BY(m)
515 
516     std::atomic<pid_t> tid1{};
517 
518     // launch thread.
519     std::thread t1([&]() {
520         UniqueLock ul1(m1);
521         UniqueLock ul(m);
522         tid1 = android::audio_utils::gettid_wrapper();
523         while (!quit) {
524             cv.wait(ul, [&]{ return quit; });
525             if (quit) break;
526         }
527     });
528 
529     // ensure thread tid1 has acquired all locks.
530     while (tid1 == 0) { usleep(1000); }
531 
532     // try lock for 1s
533     constexpr int64_t kTimeoutNs = 1'000'000'000;
534     {
535         //  verify timed out state.
536         const int64_t beginNs = systemTime();
537         const bool success = m1.try_lock(kTimeoutNs);
538         const int64_t endNs = systemTime();
539         const int64_t diffNs = endNs - beginNs;
540 
541         if (success) m1.unlock();
542         EXPECT_GT(diffNs, kTimeoutNs);
543         EXPECT_FALSE(success);
544     }
545 
546     // exit the thread
547     {
548         UniqueLock ul(m);
549 
550         quit = true;
551         cv.notify_one();
552     }
553 
554     t1.join();
555 
556     {
557         // verify success state.
558         const int64_t beginNs = systemTime();
559         const bool success = m1.try_lock(kTimeoutNs);
560         const int64_t endNs = systemTime();
561         const int64_t diffNs = endNs - beginNs;
562 
563         if (success) m1.unlock();
564         constexpr int64_t kSuccessLockNs = kTimeoutNs / 4;
565         EXPECT_LT(diffNs, kSuccessLockNs);
566         EXPECT_TRUE(success);
567     }
568 }
569 
570 // Test the deadlock detection algorithm for a single wait chain
571 // (no cycle).
572 
TEST_P(MutexTestSuite,DeadlockDetection)573 TEST_P(MutexTestSuite, DeadlockDetection) {
574     using Mutex = android::audio_utils::mutex;
575     using UniqueLock = android::audio_utils::unique_lock<Mutex>;
576     using ConditionVariable = android::audio_utils::condition_variable;
577     const bool priority_inheritance = GetParam();
578 
579     // order checked below.
580     constexpr size_t kOrder1 = 1;
581     constexpr size_t kOrder2 = 2;
582     constexpr size_t kOrder3 = 3;
583     static_assert(Mutex::attributes_t::order_size_ > kOrder3);
584 
585     Mutex m1{priority_inheritance, static_cast<Mutex::attributes_t::order_t>(kOrder1)};
586     Mutex m2{priority_inheritance, static_cast<Mutex::attributes_t::order_t>(kOrder2)};
587     Mutex m3{priority_inheritance, static_cast<Mutex::attributes_t::order_t>(kOrder3)};
588     Mutex m4{priority_inheritance};
589     Mutex m{priority_inheritance};
590     ConditionVariable cv;
591     bool quit = false;  // GUARDED_BY(m)
592     std::atomic<pid_t> tid1{}, tid2{}, tid3{}, tid4{};
593 
594     std::thread t4([&]() {
595         UniqueLock ul4(m4);
596         UniqueLock ul(m);
597         tid4 = android::audio_utils::gettid_wrapper();
598         while (!quit) {
599             cv.wait(ul, [&]{ return quit; });
600             if (quit) break;
601         }
602     });
603 
604     while (tid4 == 0) { usleep(1000); }
605 
606     std::thread t3([&]() {
607         UniqueLock ul3(m3);
608         tid3 = android::audio_utils::gettid_wrapper();
609         UniqueLock ul4(m4);
610     });
611 
612     while (tid3 == 0) { usleep(1000); }
613 
614     std::thread t2([&]() {
615         UniqueLock ul2(m2);
616         tid2 = android::audio_utils::gettid_wrapper();
617         UniqueLock ul3(m3);
618     });
619 
620     while (tid2 == 0) { usleep(1000); }
621 
622     std::thread t1([&]() {
623         UniqueLock ul1(m1);
624         tid1 = android::audio_utils::gettid_wrapper();
625         UniqueLock ul2(m2);
626     });
627 
628     while (tid1 == 0) { usleep(1000); }
629 
630     // we know that the threads will now block in the proper order.
631     // however, we need to wait for the block to happen.
632     // this part is racy unless we check the thread state or use
633     // futexes directly in our mutex (which allows atomic accuracy of wait).
634     usleep(20000);
635 
636     const auto deadlockInfo = android::audio_utils::mutex::deadlock_detection(tid1);
637 
638     // no cycle.
639     EXPECT_EQ(false, deadlockInfo.has_cycle);
640 
641     // no condition_variable detected
642     EXPECT_EQ(audio_utils::other_wait_reason_t::none, deadlockInfo.other_wait_reason);
643 
644     // thread1 is waiting on a chain of 3 other threads.
645     const auto chain = deadlockInfo.chain;
646     const size_t chain_size = chain.size();
647     EXPECT_EQ(3u, chain_size);
648 
649     const auto default_idx = static_cast<size_t>(Mutex::attributes_t::order_default_);
650     if (chain_size > 0) {
651         EXPECT_EQ(tid2, chain[0].first);
652         EXPECT_EQ(Mutex::attributes_t::order_names_[kOrder2], chain[0].second);
653     }
654     if (chain_size > 1) {
655         EXPECT_EQ(tid3, chain[1].first);
656         EXPECT_EQ(Mutex::attributes_t::order_names_[kOrder3], chain[1].second);
657     }
658     if (chain_size > 2) {
659         EXPECT_EQ(tid4, chain[2].first);
660         EXPECT_EQ(Mutex::attributes_t::order_names_[default_idx], chain[2].second);
661     }
662 
663     ALOGD("%s", android::audio_utils::mutex::all_threads_to_string().c_str());
664 
665     {
666         UniqueLock ul(m);
667 
668         quit = true;
669         cv.notify_one();
670     }
671 
672     t4.join();
673     t3.join();
674     t2.join();
675     t1.join();
676 }
677 
TEST_P(MutexTestSuite,DeadlockConditionVariableDetection)678 TEST_P(MutexTestSuite, DeadlockConditionVariableDetection) {
679     using Mutex = android::audio_utils::mutex;
680     using UniqueLock = android::audio_utils::unique_lock<Mutex>;
681     using ConditionVariable = android::audio_utils::condition_variable;
682     const bool priority_inheritance = GetParam();
683 
684     // order checked below.
685     constexpr size_t kOrder1 = 1;
686     constexpr size_t kOrder2 = 2;
687     constexpr size_t kOrder3 = 3;
688     static_assert(Mutex::attributes_t::order_size_ > kOrder3);
689 
690     Mutex m1{priority_inheritance, static_cast<Mutex::attributes_t::order_t>(kOrder1)};
691     Mutex m2{priority_inheritance, static_cast<Mutex::attributes_t::order_t>(kOrder2)};
692     Mutex m3{priority_inheritance, static_cast<Mutex::attributes_t::order_t>(kOrder3)};
693     Mutex m4{priority_inheritance};
694     Mutex m{priority_inheritance};
695     ConditionVariable cv, cv2, cv4;
696     bool quit = false;  // GUARDED_BY(m)
697     std::atomic<pid_t> tid1{}, tid2{}, tid3{}, tid4{};
698 
699     std::thread t4([&]() {
700         // UniqueLock ul4(m4);
701         UniqueLock ul(m);
702         tid4 = android::audio_utils::gettid_wrapper();
703         while (!quit) {
704             cv.wait(ul, [&]{ return quit; });
705             if (quit) break;
706         }
707     });
708 
709     while (tid4 == 0) { usleep(1000); }
710 
711     std::thread t3([&]() {
712         UniqueLock ul3(m3);
713         tid3 = android::audio_utils::gettid_wrapper();
714         UniqueLock ul4(m4);
715         while (!quit) {
716             // use the wait method with the notifier_tid metadata.
717             cv4.wait(ul4, [&]{ return quit; }, tid4);
718             if (quit) break;
719         }
720     });
721 
722     while (tid3 == 0) { usleep(1000); }
723 
724     std::thread t2([&]() {
725         // UniqueLock ul2(m2);
726         tid2 = android::audio_utils::gettid_wrapper();
727         UniqueLock ul3(m3);
728     });
729 
730     while (tid2 == 0) { usleep(1000); }
731 
732     std::thread t1([&]() {
733         UniqueLock ul1(m1);
734         tid1 = android::audio_utils::gettid_wrapper();
735         UniqueLock ul2(m2);
736         while (!quit) {
737             // use the wait method with the notifier_tid metadata.
738             cv2.wait(ul2, [&]{ return quit; }, tid2);
739             if (quit) break;
740         }
741     });
742 
743     while (tid1 == 0) { usleep(1000); }
744 
745     // we know that the threads will now block in the proper order.
746     // however, we need to wait for the block to happen.
747     // this part is racy unless we check the thread state or use
748     // futexes directly in our mutex (which allows atomic accuracy of wait).
749     usleep(20000);
750 
751     const auto deadlockInfo = android::audio_utils::mutex::deadlock_detection(tid1);
752 
753     // no cycle.
754     EXPECT_EQ(false, deadlockInfo.has_cycle);
755 
756     // condition_variable detected
757     EXPECT_EQ(audio_utils::other_wait_reason_t::cv, deadlockInfo.other_wait_reason);
758 
759     // thread1 is waiting on a chain of 3 other threads.
760     const auto chain = deadlockInfo.chain;
761     const size_t chain_size = chain.size();
762     EXPECT_EQ(3u, chain_size);
763 
764     const auto default_idx = static_cast<size_t>(Mutex::attributes_t::order_default_);
765     if (chain_size > 0) {
766         EXPECT_EQ(tid2, chain[0].first);
767         EXPECT_EQ(std::string("cv-").append(Mutex::attributes_t::order_names_[kOrder2]).c_str(),
768                 chain[0].second);
769     }
770     if (chain_size > 1) {
771         EXPECT_EQ(tid3, chain[1].first);
772         EXPECT_EQ(Mutex::attributes_t::order_names_[kOrder3], chain[1].second);
773     }
774     if (chain_size > 2) {
775         EXPECT_EQ(tid4, chain[2].first);
776         EXPECT_EQ(std::string("cv-").append(
777                 Mutex::attributes_t::order_names_[default_idx]).c_str(), chain[2].second);
778     }
779 
780     ALOGD("with cv all_threads_to_string():\n%s",
781             android::audio_utils::mutex::all_threads_to_string().c_str());
782     ALOGD("with cv deadlock_info_t:\n%s",
783             android::audio_utils::mutex::deadlock_detection(
784                    tid1).to_string().c_str());
785 
786     {
787         UniqueLock ul(m);
788         quit = true;
789         cv.notify_one();
790     }
791     {
792         UniqueLock ul2(m);
793         cv2.notify_one();
794     }
795     {
796         UniqueLock ul4(m);
797         cv4.notify_one();
798     }
799 
800     t4.join();
801     t3.join();
802     t2.join();
803     t1.join();
804 }
805 
TEST_P(MutexTestSuite,DeadlockJoinDetection)806 TEST_P(MutexTestSuite, DeadlockJoinDetection) {
807     using Mutex = android::audio_utils::mutex;
808     using UniqueLock = android::audio_utils::unique_lock<Mutex>;
809     using ConditionVariable = android::audio_utils::condition_variable;
810     const bool priority_inheritance = GetParam();
811 
812     Mutex m{priority_inheritance};
813     ConditionVariable cv;
814     bool quit = false;  // GUARDED_BY(m)
815     std::atomic<pid_t> tid1{}, tid2{}, tid3{}, tid4{};
816 
817     std::thread t4([&]() {
818         UniqueLock ul(m);
819         tid4 = android::audio_utils::gettid_wrapper();
820         while (!quit) {
821             cv.wait(ul, [&]{ return quit; });
822             if (quit) break;
823         }
824     });
825 
826     while (tid4 == 0) { std::this_thread::sleep_for(1ms); }
827 
828     std::thread t3([&]() {
829         tid3 = android::audio_utils::gettid_wrapper();
830         audio_utils::mutex::scoped_join_wait_check sjw(tid4);
831         t4.join();
832     });
833 
834     while (tid3 == 0) { std::this_thread::sleep_for(1ms); }
835 
836     std::thread t2([&]() {
837         tid2 = android::audio_utils::gettid_wrapper();
838         audio_utils::mutex::scoped_join_wait_check sjw(tid3);
839         t3.join();
840     });
841 
842     while (tid2 == 0) { std::this_thread::sleep_for(1ms); }
843 
844     std::thread t1([&]() {
845         tid1 = android::audio_utils::gettid_wrapper();
846         audio_utils::mutex::scoped_join_wait_check sjw(tid2);
847         t2.join();
848     });
849 
850     while (tid1 == 0) { std::this_thread::sleep_for(1ms); }
851 
852     // we know that the threads will now block in the proper order.
853     // however, we need to wait for the block to happen.
854     // this part is racy unless we check the thread state or use
855     // futexes directly in our mutex (which allows atomic accuracy of wait).
856     std::this_thread::sleep_for(20ms);
857 
858     const auto deadlockInfo = android::audio_utils::mutex::deadlock_detection(tid1);
859 
860     // no cycle.
861     EXPECT_EQ(false, deadlockInfo.has_cycle);
862 
863     // thread join detected
864     EXPECT_EQ(audio_utils::other_wait_reason_t::join, deadlockInfo.other_wait_reason);
865 
866     // thread1 is attempting to join, in a chain of 3 other threads.
867     const auto chain = deadlockInfo.chain;
868     const size_t chain_size = chain.size();
869     EXPECT_EQ(3u, chain_size);
870 
871     const auto default_idx = static_cast<size_t>(Mutex::attributes_t::order_default_);
872     if (chain_size > 0) {
873         EXPECT_EQ(tid2, chain[0].first);
874         EXPECT_EQ("join", chain[0].second);
875     }
876     if (chain_size > 1) {
877         EXPECT_EQ(tid3, chain[1].first);
878         EXPECT_EQ("join", chain[1].second);
879     }
880     if (chain_size > 2) {
881         EXPECT_EQ(tid4, chain[2].first);
882         EXPECT_EQ("join", chain[2].second);
883     }
884 
885     ALOGD("with join all_threads_to_string():\n%s",
886             android::audio_utils::mutex::all_threads_to_string().c_str());
887     ALOGD("with join deadlock_info_t:\n%s",
888             android::audio_utils::mutex::deadlock_detection(
889                    tid1).to_string().c_str());
890 
891     {
892         UniqueLock ul(m);
893         quit = true;
894         cv.notify_one();
895     }
896     t1.join();
897 }
898 
899 INSTANTIATE_TEST_SUITE_P(Mutex_NonPI_and_PI, MutexTestSuite, testing::Values(false, true));
900 
901 } // namespace android
902