1 //===----------------------------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // UNSUPPORTED: libcpp-has-no-threads 11 // UNSUPPORTED: c++98, c++03, c++11, c++14 12 13 // <mutex> 14 15 // template <class ...Mutex> class scoped_lock; 16 17 // explicit scoped_lock(mutex_type& m); 18 19 #include <mutex> 20 #include <cassert> 21 #include "test_macros.h" 22 23 struct TestMutex { 24 bool locked = false; 25 TestMutex() = default; 26 ~TestMutex() { assert(!locked); } 27 28 void lock() { assert(!locked); locked = true; } 29 bool try_lock() { if (locked) return false; locked = true; return true; } 30 void unlock() { assert(locked); locked = false; } 31 32 TestMutex(TestMutex const&) = delete; 33 TestMutex& operator=(TestMutex const&) = delete; 34 }; 35 36 #if !defined(TEST_HAS_NO_EXCEPTIONS) 37 struct TestMutexThrows { 38 bool locked = false; 39 bool throws_on_lock = false; 40 41 TestMutexThrows() = default; 42 ~TestMutexThrows() { assert(!locked); } 43 44 void lock() { 45 assert(!locked); 46 if (throws_on_lock) { 47 throw 42; 48 } 49 locked = true; 50 } 51 52 bool try_lock() { 53 if (locked) return false; 54 lock(); 55 return true; 56 } 57 58 void unlock() { assert(locked); locked = false; } 59 60 TestMutexThrows(TestMutexThrows const&) = delete; 61 TestMutexThrows& operator=(TestMutexThrows const&) = delete; 62 }; 63 #endif // !defined(TEST_HAS_NO_EXCEPTIONS) 64 65 int main() 66 { 67 { 68 using LG = std::scoped_lock<>; 69 LG lg; 70 } 71 { 72 using LG = std::scoped_lock<TestMutex>; 73 TestMutex m1; 74 { 75 LG lg(m1); 76 assert(m1.locked); 77 } 78 assert(!m1.locked); 79 } 80 { 81 using LG = std::scoped_lock<TestMutex, TestMutex>; 82 TestMutex m1, m2; 83 { 84 LG lg(m1, m2); 85 assert(m1.locked && m2.locked); 86 } 87 assert(!m1.locked && !m2.locked); 88 } 89 { 90 using LG = std::scoped_lock<TestMutex, TestMutex, TestMutex>; 91 TestMutex m1, m2, m3; 92 { 93 LG lg(m1, m2, m3); 94 assert(m1.locked && m2.locked && m3.locked); 95 } 96 assert(!m1.locked && !m2.locked && !m3.locked); 97 } 98 #if !defined(TEST_HAS_NO_EXCEPTIONS) 99 { 100 using MT = TestMutexThrows; 101 using LG = std::scoped_lock<MT>; 102 MT m1; 103 m1.throws_on_lock = true; 104 try { 105 LG lg(m1); 106 assert(false); 107 } catch (int) {} 108 assert(!m1.locked); 109 } 110 { 111 using MT = TestMutexThrows; 112 using LG = std::scoped_lock<MT, MT>; 113 MT m1, m2; 114 m1.throws_on_lock = true; 115 try { 116 LG lg(m1, m2); 117 assert(false); 118 } catch (int) {} 119 assert(!m1.locked && !m2.locked); 120 } 121 { 122 using MT = TestMutexThrows; 123 using LG = std::scoped_lock<MT, MT, MT>; 124 MT m1, m2, m3; 125 m2.throws_on_lock = true; 126 try { 127 LG lg(m1, m2, m3); 128 assert(false); 129 } catch (int) {} 130 assert(!m1.locked && !m2.locked && !m3.locked); 131 } 132 #endif 133 134 #ifdef __cpp_deduction_guides 135 { 136 TestMutex m1, m2, m3; 137 { 138 std::scoped_lock sl{}; 139 static_assert((std::is_same<decltype(sl), std::scoped_lock<>>::value), "" ); 140 } 141 { 142 std::scoped_lock sl{m1}; 143 static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1)>>::value), "" ); 144 } 145 { 146 std::scoped_lock sl{m1, m2}; 147 static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1), decltype(m2)>>::value), "" ); 148 } 149 { 150 std::scoped_lock sl{m1, m2, m3}; 151 static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1), decltype(m2), decltype(m3)>>::value), "" ); 152 } 153 } 154 #endif 155 } 156