125 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: no-threads10// UNSUPPORTED: c++03, c++1111 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_lock21#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 29struct Monitor {30 bool lock_shared_called = false;31 bool unlock_shared_called = false;32};33 34struct TrackedMutex {35 Monitor* monitor = nullptr;36 37 void lock_shared() {38 if (monitor != nullptr)39 monitor->lock_shared_called = true;40 }41 void unlock_shared() {42 if (monitor != nullptr)43 monitor->unlock_shared_called = true;44 }45};46 47template <class Mutex>48void test() {49 // Basic sanity test50 {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 // spin58 }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_EXCEPTIONS78 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#endif85 }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 mutex90#ifndef TEST_HAS_NO_EXCEPTIONS91 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#endif98 }99}100 101int main(int, char**) {102#if TEST_STD_VER >= 17103 test<std::shared_mutex>();104#endif105 test<std::shared_timed_mutex>();106 test<TrackedMutex>();107 108 // Use shared_lock with a dummy mutex class that tracks whether each109 // 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