brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.1 KiB · b614668 Raw
130 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// bool try_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 try_lock_shared_called = false;31  bool unlock_shared_called   = false;32};33 34struct TrackedMutex {35  Monitor* monitor = nullptr;36 37  bool try_lock_shared() {38    if (monitor != nullptr)39      monitor->try_lock_shared_called = true;40    return true;41  }42  void unlock_shared() {43    if (monitor != nullptr)44      monitor->unlock_shared_called = true;45  }46};47 48template <class Mutex>49void test() {50  // Basic sanity test51  {52    Mutex mutex;53    std::vector<std::thread> threads;54    std::atomic<bool> ready(false);55    for (int i = 0; i != 5; ++i) {56      threads.push_back(support::make_test_thread([&] {57        while (!ready) {58          // spin59        }60 61        std::shared_lock<Mutex> lock(mutex, std::defer_lock);62        bool result = lock.try_lock();63        assert(result);64        assert(lock.owns_lock());65      }));66    }67 68    ready = true;69    for (auto& t : threads)70      t.join();71  }72 73  // Make sure that we throw an exception if we try to re-lock a mutex that is74  // already locked by the current thread.75  {76    Mutex mutex;77 78    std::shared_lock<Mutex> lock(mutex, std::defer_lock);79    assert(lock.try_lock());80    assert(lock.owns_lock());81#ifndef TEST_HAS_NO_EXCEPTIONS82    try {83      TEST_IGNORE_NODISCARD lock.try_lock();84      assert(false);85    } catch (std::system_error const& e) {86      assert(e.code() == std::errc::resource_deadlock_would_occur);87    }88#endif89  }90 91  // Make sure that we throw an exception if we try to lock a shared_lock92  // that is not associated to any mutex.93  {94    std::shared_lock<Mutex> lock; // not associated to a mutex95#ifndef TEST_HAS_NO_EXCEPTIONS96    try {97      TEST_IGNORE_NODISCARD lock.try_lock();98      assert(false);99    } catch (std::system_error const& e) {100      assert(e.code() == std::errc::operation_not_permitted);101    }102#endif103  }104}105 106int main(int, char**) {107#if TEST_STD_VER >= 17108  test<std::shared_mutex>();109#endif110  test<std::shared_timed_mutex>();111  test<TrackedMutex>();112 113  // Use shared_lock with a dummy mutex class that tracks whether each114  // operation has been called or not.115  {116    Monitor monitor;117    TrackedMutex mutex{&monitor};118 119    std::shared_lock<TrackedMutex> lock(mutex, std::defer_lock);120    bool result = lock.try_lock();121    assert(result);122    assert(monitor.try_lock_shared_called);123    assert(lock.owns_lock());124 125    lock.unlock();126    assert(monitor.unlock_shared_called);127  }128  return 0;129}130