1// Copyright 2018 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#include "tests.h"
8
9#include <stdint.h>
10#include <fbl/mutex.h>
11#include <lib/unittest/unittest.h>
12#include <lockdep/guard_multiple.h>
13#include <lockdep/lockdep.h>
14
15#if WITH_LOCK_DEP_TESTS
16
17namespace test {
18
19// Global flag that determines whether try lock operations succeed.
20bool g_try_lock_succeeds = true;
21
22// Define some proxy types to simulate different kinds of locks.
23struct Spinlock : fbl::Mutex {
24    using fbl::Mutex::Mutex;
25
26    bool AcquireIrqSave(uint64_t* flags) __TA_ACQUIRE() {
27        (void)flags;
28        Acquire();
29        return true;
30    }
31    void ReleaseIrqRestore(uint64_t flags) __TA_RELEASE() {
32        (void)flags;
33        Release();
34    }
35
36    bool TryAcquire() __TA_TRY_ACQUIRE(true) {
37        if (g_try_lock_succeeds)
38            Acquire();
39        return g_try_lock_succeeds;
40    }
41    bool TryAcquireIrqSave(uint64_t* flags) __TA_TRY_ACQUIRE(true) {
42        (void) flags;
43        if (g_try_lock_succeeds)
44            Acquire();
45        return g_try_lock_succeeds;
46    }
47};
48LOCK_DEP_TRAITS(Spinlock, lockdep::LockFlagsIrqSafe);
49
50// Fake C-style locking primitive.
51struct spinlock_t {};
52LOCK_DEP_TRAITS(spinlock_t, lockdep::LockFlagsIrqSafe);
53
54void spinlock_lock(spinlock_t* /*lock*/) {}
55void spinlock_unlock(spinlock_t* /*lock*/) {}
56bool spinlock_try_lock(spinlock_t* /*lock*/) { return true; }
57void spinlock_lock_irqsave(spinlock_t* /*lock*/, uint64_t* /*flags*/) {}
58void spinlock_unlock_irqrestore(spinlock_t* /*lock*/, uint64_t /*flags*/) {}
59bool spinlock_try_lock_irqsave(spinlock_t* /*lock*/, uint64_t* /*flags*/) { return true; }
60
61// Type tags to select Guard<> lock policies for Spinlock and spinlock_t.
62struct IrqSave {};
63struct NoIrqSave {};
64struct TryIrqSave {};
65struct TryNoIrqSave {};
66
67struct SpinlockNoIrqSave {
68    struct State {};
69
70    static bool Acquire(Spinlock* lock, State*) __TA_ACQUIRE(lock) {
71        lock->Acquire();
72        return true;
73    }
74    static void Release(Spinlock* lock, State*) __TA_RELEASE(lock) {
75        lock->Release();
76    }
77};
78LOCK_DEP_POLICY_OPTION(Spinlock, NoIrqSave, SpinlockNoIrqSave);
79
80struct SpinlockIrqSave {
81    struct State {
82        State() {}
83        uint64_t flags;
84    };
85
86    static bool Acquire(Spinlock* lock, State* state) __TA_ACQUIRE(lock) {
87        lock->AcquireIrqSave(&state->flags);
88        return true;
89    }
90    static void Release(Spinlock* lock, State* state) __TA_RELEASE(lock) {
91        lock->ReleaseIrqRestore(state->flags);
92    }
93};
94LOCK_DEP_POLICY_OPTION(Spinlock, IrqSave, SpinlockIrqSave);
95
96struct SpinlockTryNoIrqSave {
97    struct State {};
98
99    static bool Acquire(Spinlock* lock, State*) __TA_TRY_ACQUIRE(true, lock) {
100        return lock->TryAcquire();
101    }
102    static void Release(Spinlock* lock, State*) __TA_RELEASE(lock) {
103        lock->Release();
104    }
105};
106LOCK_DEP_POLICY_OPTION(Spinlock, TryNoIrqSave, SpinlockTryNoIrqSave);
107
108struct SpinlockTryIrqSave {
109    struct State {
110        State() {}
111        uint64_t flags;
112    };
113
114    static bool Acquire(Spinlock* lock, State* state) __TA_TRY_ACQUIRE(true, lock) {
115        return lock->TryAcquireIrqSave(&state->flags);
116    }
117    static void Release(Spinlock* lock, State* state) __TA_RELEASE(lock) {
118        lock->ReleaseIrqRestore(state->flags);
119    }
120};
121LOCK_DEP_POLICY_OPTION(Spinlock, TryIrqSave, SpinlockTryIrqSave);
122
123struct spinlock_t_NoIrqSave {
124    struct State {};
125
126    static bool Acquire(spinlock_t* lock, State*) {
127        spinlock_lock(lock);
128        return true;
129    }
130    static void Release(spinlock_t* lock, State*) {
131        spinlock_unlock(lock);
132    }
133};
134LOCK_DEP_POLICY_OPTION(spinlock_t, NoIrqSave, spinlock_t_NoIrqSave);
135
136struct spinlock_t_IrqSave {
137    struct State {
138        State() {}
139        uint64_t flags;
140    };
141
142    static bool Acquire(spinlock_t* lock, State* state) {
143        spinlock_lock_irqsave(lock, &state->flags);
144        return true;
145    }
146    static void Release(spinlock_t* lock, State* state) {
147        spinlock_unlock_irqrestore(lock, state->flags);
148    }
149};
150LOCK_DEP_POLICY_OPTION(spinlock_t, IrqSave, spinlock_t_IrqSave);
151
152struct spinlock_t_TryNoIrqSave {
153    struct State {};
154
155    static bool Acquire(spinlock_t* lock, State*) {
156        spinlock_lock(lock);
157      return g_try_lock_succeeds;
158    }
159    static void Release(spinlock_t* lock, State*) {
160        spinlock_unlock(lock);
161    }
162};
163LOCK_DEP_POLICY_OPTION(spinlock_t, TryNoIrqSave, spinlock_t_TryNoIrqSave);
164
165struct spinlock_t_TryIrqSave {
166    struct State {
167        State() {}
168        uint64_t flags;
169    };
170
171    static bool Acquire(spinlock_t* lock, State* state) {
172        spinlock_lock_irqsave(lock, &state->flags);
173      return g_try_lock_succeeds;
174    }
175    static void Release(spinlock_t* lock, State* state) {
176        spinlock_unlock_irqrestore(lock, state->flags);
177    }
178};
179LOCK_DEP_POLICY_OPTION(spinlock_t, TryIrqSave, spinlock_t_TryIrqSave);
180
181struct Mutex : fbl::Mutex {
182    using fbl::Mutex::Mutex;
183};
184// Uses the default traits: fbl::LockClassState::None.
185
186struct Nestable : fbl::Mutex {
187    using fbl::Mutex::Mutex;
188};
189LOCK_DEP_TRAITS(Nestable, lockdep::LockFlagsNestable);
190
191struct Foo {
192    LOCK_DEP_INSTRUMENT(Foo, Mutex) lock;
193
194    void TestRequire() __TA_REQUIRES(lock) {}
195    void TestExclude() __TA_EXCLUDES(lock) {}
196};
197
198struct Bar {
199    LOCK_DEP_INSTRUMENT(Bar, Mutex) lock;
200
201    void TestRequire() __TA_REQUIRES(lock) {}
202    void TestExclude() __TA_EXCLUDES(lock) {}
203};
204
205template <typename LockType>
206struct Baz {
207    LOCK_DEP_INSTRUMENT(Baz, LockType) lock;
208
209    void TestRequire() __TA_REQUIRES(lock) {}
210    void TestExclude() __TA_EXCLUDES(lock) {}
211};
212
213struct MultipleLocks {
214    LOCK_DEP_INSTRUMENT(MultipleLocks, Mutex) lock_a;
215    LOCK_DEP_INSTRUMENT(MultipleLocks, Mutex) lock_b;
216
217    void TestRequireLockA() __TA_REQUIRES(lock_a) {}
218    void TestExcludeLockA() __TA_EXCLUDES(lock_a) {}
219    void TestRequireLockB() __TA_REQUIRES(lock_b) {}
220    void TestExcludeLockB() __TA_EXCLUDES(lock_b) {}
221};
222
223template <size_t Index>
224struct Number {
225    LOCK_DEP_INSTRUMENT(Number, Mutex) lock;
226
227    void TestRequire() __TA_REQUIRES(lock) {}
228    void TestExclude() __TA_EXCLUDES(lock) {}
229};
230
231lockdep::LockResult GetLastResult() {
232#if WITH_LOCK_DEP
233    lockdep::ThreadLockState* state = lockdep::ThreadLockState::Get();
234    return state->last_result();
235#else
236    return lockdep::LockResult::Success;
237#endif
238}
239
240void ResetTrackingState() {
241#if WITH_LOCK_DEP
242    for (auto& state : lockdep::LockClassState::Iter())
243      state.Reset();
244#endif
245}
246
247} // namespace test
248
249static bool lock_dep_dynamic_analysis_tests() {
250    BEGIN_TEST;
251
252    using lockdep::Guard;
253    using lockdep::GuardMultiple;
254    using lockdep::LockResult;
255    using lockdep::ThreadLockState;
256    using lockdep::LockClassState;
257    using test::Bar;
258    using test::Baz;
259    using test::Foo;
260    using test::GetLastResult;
261    using test::IrqSave;
262    using test::TryIrqSave;
263    using test::MultipleLocks;
264    using test::Mutex;
265    using test::Nestable;
266    using test::NoIrqSave;
267    using test::TryNoIrqSave;
268    using test::Number;
269    using test::Spinlock;
270    using test::spinlock_t;
271
272    // Reset the tracking state before each test run.
273    test::ResetTrackingState();
274
275    // Single lock.
276    {
277        Foo a{};
278
279        Guard<Mutex> guard_a{&a.lock};
280        EXPECT_TRUE(guard_a, "");
281        EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
282    }
283
284    // Single lock.
285    {
286        Bar a{};
287
288        Guard<Mutex> guard_a{&a.lock};
289        EXPECT_TRUE(guard_a, "");
290        EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
291    }
292
293    // Test order invariant.
294    {
295        Foo a{};
296        Foo b{};
297
298        Guard<Mutex> guard_a{&a.lock};
299        EXPECT_TRUE(guard_a, "");
300        EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
301
302        Guard<Mutex> guard_b{&b.lock};
303        EXPECT_TRUE(guard_b, "");
304        EXPECT_EQ(LockResult::AlreadyAcquired, test::GetLastResult(), "");
305    }
306
307    // Test order invariant with a different lock class.
308    {
309        Bar a{};
310        Bar b{};
311
312        Guard<Mutex> guard_a{&a.lock};
313        EXPECT_TRUE(guard_a, "");
314        EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
315
316        Guard<Mutex> guard_b{&b.lock};
317        EXPECT_TRUE(guard_b, "");
318        EXPECT_EQ(LockResult::AlreadyAcquired, test::GetLastResult(), "");
319    }
320
321    // Test address order invariant.
322    {
323        Foo a{};
324        Foo b{};
325
326        {
327            GuardMultiple<2, Mutex> guard_all{&a.lock, &b.lock};
328            EXPECT_TRUE(guard_all, "");
329            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
330        }
331
332        {
333            GuardMultiple<2, Mutex> guard_all{&b.lock, &a.lock};
334            EXPECT_TRUE(guard_all, "");
335            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
336        }
337    }
338
339    // Test address order invariant with a differnt lock class.
340    {
341        Bar a{};
342        Bar b{};
343
344        {
345            GuardMultiple<2, Mutex> guard_all{&a.lock, &b.lock};
346            EXPECT_TRUE(guard_all, "");
347            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
348        }
349
350        {
351            GuardMultiple<2, Mutex> guard_all{&b.lock, &a.lock};
352            EXPECT_TRUE(guard_all, "");
353            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
354        }
355    }
356
357    // Test address order invariant with spinlocks.
358    {
359        Baz<Spinlock> a{};
360        Baz<Spinlock> b{};
361
362        {
363            GuardMultiple<2, Spinlock, NoIrqSave> guard_all{&a.lock, &b.lock};
364            EXPECT_TRUE(guard_all, "");
365            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
366        }
367
368        {
369            GuardMultiple<2, Spinlock, NoIrqSave> guard_all{&b.lock, &a.lock};
370            EXPECT_TRUE(guard_all, "");
371            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
372        }
373
374        {
375            test::g_try_lock_succeeds = true;
376            GuardMultiple<2, Spinlock, TryNoIrqSave> guard_all{&a.lock, &b.lock};
377            EXPECT_TRUE(guard_all, "");
378            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
379        }
380
381        {
382            test::g_try_lock_succeeds = true;
383            GuardMultiple<2, Spinlock, TryNoIrqSave> guard_all{&b.lock, &a.lock};
384            EXPECT_TRUE(guard_all, "");
385            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
386        }
387
388        {
389            test::g_try_lock_succeeds = false;
390            GuardMultiple<2, Spinlock, TryNoIrqSave> guard_all{&a.lock, &b.lock};
391            EXPECT_FALSE(guard_all, "");
392            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
393        }
394
395        {
396            test::g_try_lock_succeeds = false;
397            GuardMultiple<2, Spinlock, TryNoIrqSave> guard_all{&b.lock, &a.lock};
398            EXPECT_FALSE(guard_all, "");
399            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
400        }
401    }
402
403    // Foo -> Bar -- establish order.
404    {
405        Foo a{};
406        Bar b{};
407
408        Guard<Mutex> guard_a{&a.lock};
409        EXPECT_TRUE(guard_a, "");
410        EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
411
412        Guard<Mutex> guard_b{&b.lock};
413        EXPECT_TRUE(guard_b, "");
414        EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
415    }
416
417    // Bar -> Foo -- check order invariant.
418    {
419        Foo a{};
420        Bar b{};
421
422        Guard<Mutex> guard_b{&b.lock};
423        EXPECT_TRUE(guard_b, "");
424        EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
425
426        Guard<Mutex> guard_a{&a.lock};
427        EXPECT_TRUE(guard_a, "");
428        EXPECT_EQ(LockResult::OutOfOrder, test::GetLastResult(), "");
429    }
430
431    // Test external order invariant.
432    {
433        Baz<Nestable> baz1;
434        Baz<Nestable> baz2;
435
436        {
437            Guard<Nestable> auto_baz1{&baz1.lock, 0};
438            EXPECT_TRUE(auto_baz1, "");
439            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
440
441            Guard<Nestable> auto_baz2{&baz2.lock, 1};
442            EXPECT_TRUE(auto_baz2, "");
443            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
444        }
445
446        {
447            Guard<Nestable> auto_baz2{&baz2.lock, 0};
448            EXPECT_TRUE(auto_baz2, "");
449            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
450
451            Guard<Nestable> auto_baz1{&baz1.lock, 1};
452            EXPECT_TRUE(auto_baz1, "");
453            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
454        }
455
456        {
457            Guard<Nestable> auto_baz2{&baz2.lock, 1};
458            EXPECT_TRUE(auto_baz2, "");
459            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
460
461            Guard<Nestable> auto_baz1{&baz1.lock, 0};
462            EXPECT_TRUE(auto_baz1, "");
463            EXPECT_EQ(LockResult::InvalidNesting, test::GetLastResult(), "");
464        }
465    }
466
467    // Test irq-safety invariant.
468    {
469        Baz<Mutex> baz1;
470        Baz<Spinlock> baz2;
471
472        {
473            Guard<Mutex> auto_baz1{&baz1.lock};
474            EXPECT_TRUE(auto_baz1, "");
475            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
476
477            Guard<Spinlock, NoIrqSave> auto_baz2{&baz2.lock};
478            EXPECT_TRUE(auto_baz2, "");
479            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
480        }
481
482        {
483            Guard<Spinlock, NoIrqSave> auto_baz2{&baz2.lock};
484            EXPECT_TRUE(auto_baz2, "");
485            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
486
487            Guard<Mutex> auto_baz1{&baz1.lock};
488            EXPECT_TRUE(auto_baz1, "");
489            EXPECT_EQ(LockResult::InvalidIrqSafety, test::GetLastResult(), "");
490        }
491    }
492
493    // Test spinlock options compile and baisc guard functions.
494    // TODO(eieio): Add Guard<>::state() accessor and check state values.
495    {
496        Baz<Spinlock> baz1;
497        Baz<spinlock_t> baz2;
498
499        {
500            Guard<Spinlock, NoIrqSave> guard{&baz1.lock};
501            EXPECT_TRUE(guard, "");
502            guard.Release();
503            EXPECT_FALSE(guard, "");
504        }
505
506        {
507            Guard<Spinlock, IrqSave> guard{&baz1.lock};
508            EXPECT_TRUE(guard, "");
509            guard.Release();
510            EXPECT_FALSE(guard, "");
511        }
512
513        {
514            Guard<spinlock_t, NoIrqSave> guard{&baz2.lock};
515            EXPECT_TRUE(guard, "");
516            guard.Release();
517            EXPECT_FALSE(guard, "");
518        }
519
520        {
521            Guard<spinlock_t, IrqSave> guard{&baz2.lock};
522            EXPECT_TRUE(guard, "");
523            guard.Release();
524            EXPECT_FALSE(guard, "");
525        }
526
527        {
528            test::g_try_lock_succeeds = true;
529            Guard<Spinlock, TryNoIrqSave> guard{&baz1.lock};
530            EXPECT_TRUE(guard, "");
531            guard.Release();
532            EXPECT_FALSE(guard, "");
533        }
534
535        {
536            test::g_try_lock_succeeds = true;
537            Guard<Spinlock, TryIrqSave> guard{&baz1.lock};
538            EXPECT_TRUE(guard, "");
539            guard.Release();
540            EXPECT_FALSE(guard, "");
541        }
542
543        {
544            test::g_try_lock_succeeds = false;
545            Guard<spinlock_t, TryNoIrqSave> guard{&baz2.lock};
546            EXPECT_FALSE(guard, "");
547            guard.Release();
548            EXPECT_FALSE(guard, "");
549        }
550
551        {
552            test::g_try_lock_succeeds = false;
553            Guard<spinlock_t, TryIrqSave> guard{&baz2.lock};
554            EXPECT_FALSE(guard, "");
555            guard.Release();
556            EXPECT_FALSE(guard, "");
557        }
558
559        // Test that Guard<LockType, Option> fails to compile when Option is
560        // required by the policy config but not specified.
561        {
562#if TEST_WILL_NOT_COMPILE || 0
563            Guard<Spinlock> guard1{&baz1.lock};
564            Guard<spinlock_t> guard2{&baz2.lock};
565#endif
566        }
567    }
568
569    // Test that each lock in a structure behaves as an individual lock class.
570    {
571        MultipleLocks value{};
572
573        {
574            Guard<Mutex> guard_a{&value.lock_a};
575            EXPECT_TRUE(guard_a, "");
576            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
577
578            Guard<Mutex> guard_b{&value.lock_b};
579            EXPECT_TRUE(guard_b, "");
580            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
581        }
582
583        {
584            Guard<Mutex> guard_b{&value.lock_b};
585            EXPECT_TRUE(guard_b, "");
586            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
587
588            Guard<Mutex> guard_a{&value.lock_a};
589            EXPECT_TRUE(guard_a, "");
590            EXPECT_EQ(LockResult::OutOfOrder, test::GetLastResult(), "");
591        }
592    }
593
594    // Test circular dependency detection.
595    {
596        Number<1> a{}; // Node A.
597        Number<2> b{}; // Node B.
598        Number<3> c{}; // Node C.
599        Number<4> d{}; // Node D.
600
601        // A -> B
602        {
603            Guard<Mutex> guard_a{&a.lock};
604            EXPECT_TRUE(guard_a, "");
605            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
606
607            Guard<Mutex> guard_b{&b.lock};
608            EXPECT_TRUE(guard_b, "");
609            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
610        }
611
612        // B -> C
613        {
614            Guard<Mutex> guard_b{&b.lock};
615            EXPECT_TRUE(guard_b, "");
616            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
617
618            Guard<Mutex> guard_c{&c.lock};
619            EXPECT_TRUE(guard_c, "");
620            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
621        }
622
623        // C -> A -- cycle in (A, B, C)
624        {
625            Guard<Mutex> guard_c{&c.lock};
626            EXPECT_TRUE(guard_c, "");
627            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
628
629            Guard<Mutex> guard_a{&a.lock};
630            EXPECT_TRUE(guard_a, "");
631            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
632        }
633
634        // C -> D
635        {
636            Guard<Mutex> guard_c{&c.lock};
637            EXPECT_TRUE(guard_c, "");
638            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
639
640            Guard<Mutex> guard_d{&d.lock};
641            EXPECT_TRUE(guard_d, "");
642            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
643        }
644
645        // D -> A -- cycle in (A, B, C, D)
646        {
647            Guard<Mutex> guard_d{&d.lock};
648            EXPECT_TRUE(guard_d, "");
649            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
650
651            Guard<Mutex> guard_a{&a.lock};
652            EXPECT_TRUE(guard_a, "");
653            EXPECT_EQ(LockResult::Success, test::GetLastResult(), "");
654        }
655    }
656
657    END_TEST;
658}
659
660// Basic compile-time tests of lockdep clang lock annotations.
661static bool lock_dep_static_analysis_tests() {
662    BEGIN_TEST;
663
664    using lockdep::Guard;
665    using lockdep::GuardMultiple;
666    using lockdep::LockResult;
667    using lockdep::ThreadLockState;
668    using test::Bar;
669    using test::Baz;
670    using test::Foo;
671    using test::MultipleLocks;
672    using test::Mutex;
673    using test::Nestable;
674    using test::Number;
675    using test::Spinlock;
676    using test::TryNoIrqSave;
677
678    // Test require and exclude annotations.
679    {
680        Foo a{};
681
682        Guard<Mutex> guard_a{&a.lock};
683        a.TestRequire();
684#if TEST_WILL_NOT_COMPILE || 0
685        a.TestExclude();
686#endif
687
688        guard_a.Release();
689#if TEST_WILL_NOT_COMPILE || 0
690        a.TestRequire();
691#endif
692        a.TestExclude();
693    }
694
695    // Test multiple acquire.
696    {
697        Foo a{};
698
699        Guard<Mutex> guard_a{&a.lock};
700#if TEST_WILL_NOT_COMPILE || 0
701        Guard<Mutex> guard_b{&a.lock};
702#endif
703    }
704
705    // Test sequential acquire/release.
706    {
707        Foo a{};
708
709        Guard<Mutex> guard_a{&a.lock};
710        guard_a.Release();
711        Guard<Mutex> guard_b{&a.lock};
712    }
713
714    END_TEST;
715}
716
717UNITTEST_START_TESTCASE(lock_dep_tests)
718UNITTEST("lock_dep_dynamic_analysis_tests", lock_dep_dynamic_analysis_tests)
719UNITTEST("lock_dep_static_analysis_tests", lock_dep_static_analysis_tests)
720UNITTEST_END_TESTCASE(lock_dep_tests, "lock_dep_tests", "lock_dep_tests");
721
722#endif
723