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 11 12 // <shared_mutex> 13 14 // template <class Mutex> class shared_lock; 15 16 // void lock(); 17 18 #include <atomic> 19 #include <cassert> 20 #include <mutex> // std::defer_lock 21 #include <shared_mutex> 22 #include <system_error> 23 #include <thread> 24 #include <vector> 25 26 #include "make_test_thread.h" 27 #include "test_macros.h" 28 29 struct Monitor { 30 bool lock_shared_called = false; 31 bool unlock_shared_called = false; 32 }; 33 34 struct TrackedMutex { 35 Monitor* monitor = nullptr; 36 lock_sharedTrackedMutex37 void lock_shared() { 38 if (monitor != nullptr) 39 monitor->lock_shared_called = true; 40 } unlock_sharedTrackedMutex41 void unlock_shared() { 42 if (monitor != nullptr) 43 monitor->unlock_shared_called = true; 44 } 45 }; 46 47 template <class Mutex> test()48void test() { 49 // Basic sanity test 50 { 51 Mutex mutex; 52 std::vector<std::thread> threads; 53 std::atomic<bool> ready(false); 54 for (int i = 0; i != 5; ++i) { 55 threads.push_back(support::make_test_thread([&] { 56 while (!ready) { 57 // spin 58 } 59 60 std::shared_lock<Mutex> lock(mutex, std::defer_lock); 61 lock.lock(); 62 assert(lock.owns_lock()); 63 })); 64 } 65 66 ready = true; 67 for (auto& t : threads) 68 t.join(); 69 } 70 71 // Try locking the same shared_lock again in the same thread. This should throw an exception. 72 { 73 Mutex mutex; 74 std::shared_lock<Mutex> lock(mutex, std::defer_lock); 75 lock.lock(); 76 assert(lock.owns_lock()); 77 #ifndef TEST_HAS_NO_EXCEPTIONS 78 try { 79 lock.lock(); 80 assert(false); 81 } catch (std::system_error const& e) { 82 assert(e.code() == std::errc::resource_deadlock_would_occur); 83 } 84 #endif 85 } 86 87 // Try locking a shared_lock that isn't associated to any mutex. This should throw an exception. 88 { 89 std::shared_lock<Mutex> lock; // no associated mutex 90 #ifndef TEST_HAS_NO_EXCEPTIONS 91 try { 92 lock.lock(); 93 assert(false); 94 } catch (std::system_error const& e) { 95 assert(e.code() == std::errc::operation_not_permitted); 96 } 97 #endif 98 } 99 } 100 main(int,char **)101int main(int, char**) { 102 #if TEST_STD_VER >= 17 103 test<std::shared_mutex>(); 104 #endif 105 test<std::shared_timed_mutex>(); 106 test<TrackedMutex>(); 107 108 // Use shared_lock with a dummy mutex class that tracks whether each 109 // operation has been called or not. 110 { 111 Monitor monitor; 112 TrackedMutex mutex{&monitor}; 113 114 std::shared_lock<TrackedMutex> lock(mutex, std::defer_lock); 115 lock.lock(); 116 assert(monitor.lock_shared_called); 117 assert(lock.owns_lock()); 118 119 lock.unlock(); 120 assert(monitor.unlock_shared_called); 121 } 122 123 return 0; 124 } 125