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