brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.5 KiB · 6f3a5a0 Raw
118 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;14 15// template <class Clock, class Duration>16//   cv_status17//   wait_until(unique_lock<mutex>& lock,18//              const chrono::time_point<Clock, Duration>& abs_time);19 20#include <condition_variable>21#include <atomic>22#include <cassert>23#include <chrono>24#include <mutex>25#include <thread>26 27#include "make_test_thread.h"28#include "test_macros.h"29 30struct TestClock {31  typedef std::chrono::milliseconds duration;32  typedef duration::rep rep;33  typedef duration::period period;34  typedef std::chrono::time_point<TestClock> time_point;35  static const bool is_steady = true;36 37  static time_point now() {38    using namespace std::chrono;39    return time_point(duration_cast<duration>(steady_clock::now().time_since_epoch()));40  }41};42 43template <class Clock>44void test() {45  // Test unblocking via a call to notify_one() in another thread.46  //47  // To test this, we set a very long timeout in wait_until() and we wait48  // again in case we get awoken spuriously. Note that it can actually49  // happen that we get awoken spuriously and fail to recognize it50  // (making this test useless), but the likelihood should be small.51  {52    std::atomic<bool> ready(false);53    std::atomic<bool> likely_spurious(true);54    auto timeout = Clock::now() + std::chrono::seconds(3600);55    std::condition_variable cv;56    std::mutex mutex;57 58    std::thread t1 = support::make_test_thread([&] {59      std::unique_lock<std::mutex> lock(mutex);60      ready = true;61      do {62        std::cv_status result = cv.wait_until(lock, timeout);63        assert(result == std::cv_status::no_timeout);64      } while (likely_spurious);65 66      // This can technically fail if we have many spurious awakenings, but in practice the67      // tolerance is so high that it shouldn't be a problem.68      assert(Clock::now() < timeout);69    });70 71    std::thread t2 = support::make_test_thread([&] {72      while (!ready) {73        // spin74      }75 76      // Acquire the same mutex as t1. This blocks the condition variable inside its wait call77      // so we can notify it while it is waiting.78      std::unique_lock<std::mutex> lock(mutex);79      cv.notify_one();80      likely_spurious = false;81      lock.unlock();82    });83 84    t2.join();85    t1.join();86  }87 88  // Test unblocking via a timeout.89  //90  // To test this, we create a thread that waits on a condition variable91  // with a certain timeout, and we never awaken it. To guard against92  // spurious wakeups, we wait again whenever we are awoken for a reason93  // other than a timeout.94  {95    auto timeout = Clock::now() + std::chrono::milliseconds(250);96    std::condition_variable cv;97    std::mutex mutex;98 99    std::thread t1 = support::make_test_thread([&] {100      std::unique_lock<std::mutex> lock(mutex);101      std::cv_status result;102      do {103        result = cv.wait_until(lock, timeout);104        if (result == std::cv_status::timeout)105          assert(Clock::now() >= timeout);106      } while (result != std::cv_status::timeout);107    });108 109    t1.join();110  }111}112 113int main(int, char**) {114  test<TestClock>();115  test<std::chrono::steady_clock>();116  return 0;117}118