111 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: c++0310// UNSUPPORTED: no-threads11 12// <mutex>13 14// class recursive_timed_mutex;15 16// void lock();17 18#include <mutex>19#include <atomic>20#include <cassert>21#include <thread>22#include <vector>23 24#include "make_test_thread.h"25 26bool is_lockable(std::recursive_timed_mutex& m) {27 bool did_lock;28 std::thread t = support::make_test_thread([&] {29 did_lock = m.try_lock();30 if (did_lock)31 m.unlock(); // undo side effects32 });33 t.join();34 35 return did_lock;36}37 38int main(int, char**) {39 // Lock a mutex that is not locked yet. This should succeed.40 {41 std::recursive_timed_mutex m;42 m.lock();43 m.unlock();44 }45 46 // Lock a mutex that is already locked by this thread. This should succeed and the mutex should only47 // be unlocked after a matching number of calls to unlock() on the same thread.48 {49 std::recursive_timed_mutex m;50 int lock_count = 0;51 for (int i = 0; i != 10; ++i) {52 m.lock();53 ++lock_count;54 }55 while (lock_count != 0) {56 assert(!is_lockable(m));57 m.unlock();58 --lock_count;59 }60 assert(is_lockable(m));61 }62 63 // Lock a mutex that is already locked by another thread. This should block until it is unlocked.64 {65 std::atomic<bool> ready(false);66 std::recursive_timed_mutex m;67 m.lock();68 std::atomic<bool> is_locked_from_main(true);69 70 std::thread t = support::make_test_thread([&] {71 ready = true;72 m.lock();73 assert(!is_locked_from_main);74 m.unlock();75 });76 77 while (!ready)78 /* spin */;79 80 // We would rather signal this after we unlock, but that would create a race condition.81 // We instead signal it before we unlock, which means that it's technically possible for82 // the thread to take the lock while main is still holding it yet for the test to still pass.83 is_locked_from_main = false;84 m.unlock();85 86 t.join();87 }88 89 // Make sure that at most one thread can acquire the mutex concurrently.90 {91 std::atomic<int> counter(0);92 std::recursive_timed_mutex mutex;93 94 std::vector<std::thread> threads;95 for (int i = 0; i != 10; ++i) {96 threads.push_back(support::make_test_thread([&] {97 mutex.lock();98 counter++;99 assert(counter == 1);100 counter--;101 mutex.unlock();102 }));103 }104 105 for (auto& t : threads)106 t.join();107 }108 109 return 0;110}111