brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.9 KiB · 6494bcd Raw
132 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-threads, c++0310 11// <condition_variable>12 13// class condition_variable_any;14 15// template <class Lock, class Clock, class Duration>16//   cv_status17//   wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time);18 19#include <condition_variable>20#include <atomic>21#include <cassert>22#include <chrono>23#include <mutex>24#include <thread>25 26#include "make_test_thread.h"27#include "test_macros.h"28 29struct TestClock {30  typedef std::chrono::milliseconds duration;31  typedef duration::rep rep;32  typedef duration::period period;33  typedef std::chrono::time_point<TestClock> time_point;34  static const bool is_steady = true;35 36  static time_point now() {37    using namespace std::chrono;38    return time_point(duration_cast<duration>(steady_clock::now().time_since_epoch()));39  }40};41 42template <class Mutex>43struct MyLock : std::unique_lock<Mutex> {44  using std::unique_lock<Mutex>::unique_lock;45};46 47template <class Lock, class Clock>48void test() {49  using Mutex = typename Lock::mutex_type;50  // Test unblocking via a call to notify_one() in another thread.51  //52  // To test this, we set a very long timeout in wait_until() and we wait53  // again in case we get awoken spuriously. Note that it can actually54  // happen that we get awoken spuriously and fail to recognize it55  // (making this test useless), but the likelihood should be small.56  {57    std::atomic<bool> ready(false);58    std::atomic<bool> likely_spurious(true);59    auto timeout = Clock::now() + std::chrono::seconds(3600);60    std::condition_variable_any cv;61    Mutex mutex;62 63    std::thread t1 = support::make_test_thread([&] {64      Lock lock(mutex);65      ready = true;66      do {67        std::cv_status result = cv.wait_until(lock, timeout);68        assert(result == std::cv_status::no_timeout);69      } while (likely_spurious);70 71      // This can technically fail if we have many spurious awakenings, but in practice the72      // tolerance is so high that it shouldn't be a problem.73      assert(Clock::now() < timeout);74    });75 76    std::thread t2 = support::make_test_thread([&] {77      while (!ready) {78        // spin79      }80 81      // Acquire the same mutex as t1. This blocks the condition variable inside its wait call82      // so we can notify it while it is waiting.83      Lock lock(mutex);84      cv.notify_one();85      likely_spurious = false;86      lock.unlock();87    });88 89    t2.join();90    t1.join();91  }92 93  // Test unblocking via a timeout.94  //95  // To test this, we create a thread that waits on a condition variable96  // with a certain timeout, and we never awaken it. To guard against97  // spurious wakeups, we wait again whenever we are awoken for a reason98  // other than a timeout.99  {100    auto timeout = Clock::now() + std::chrono::milliseconds(250);101    std::condition_variable_any cv;102    Mutex mutex;103 104    std::thread t1 = support::make_test_thread([&] {105      Lock lock(mutex);106      std::cv_status result;107      do {108        result = cv.wait_until(lock, timeout);109        if (result == std::cv_status::timeout)110          assert(Clock::now() >= timeout);111      } while (result != std::cv_status::timeout);112    });113 114    t1.join();115  }116}117 118int main(int, char**) {119  test<std::unique_lock<std::mutex>, TestClock>();120  test<std::unique_lock<std::mutex>, std::chrono::steady_clock>();121 122  test<std::unique_lock<std::timed_mutex>, TestClock>();123  test<std::unique_lock<std::timed_mutex>, std::chrono::steady_clock>();124 125  test<MyLock<std::mutex>, TestClock>();126  test<MyLock<std::mutex>, std::chrono::steady_clock>();127 128  test<MyLock<std::timed_mutex>, TestClock>();129  test<MyLock<std::timed_mutex>, std::chrono::steady_clock>();130  return 0;131}132