brintos

brintos / llvm-project-archived public Read only

0
0
Text · 2.6 KiB · 344667f Raw
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_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_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_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_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_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_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