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