brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · 03a0fa2 Raw
246 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++11, c++14, c++1711 12// <condition_variable>13 14// class condition_variable_any;15 16// template<class Lock, class Clock, class Duration, class Predicate>17//   bool wait_until(Lock& lock, stop_token stoken,18//                   const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);19 20#include <atomic>21#include <cassert>22#include <chrono>23#include <concepts>24#include <condition_variable>25#include <functional>26#include <mutex>27#include <shared_mutex>28#include <stop_token>29#include <thread>30 31#include "helpers.h"32#include "make_test_thread.h"33#include "test_macros.h"34 35template <class Mutex, class Lock>36void test() {37  using namespace std::chrono_literals;38  const auto oneHourAgo   = std::chrono::steady_clock::now() - 1h;39  const auto oneHourLater = std::chrono::steady_clock::now() + 1h;40 41  // stop_requested before hand42  {43    std::stop_source ss;44    std::condition_variable_any cv;45    Mutex mutex;46    Lock lock{mutex};47    ss.request_stop();48    ElapsedTimeCheck check(1min);49 50    // [Note 4: The returned value indicates whether the predicate evaluated to true51    // regardless of whether the timeout was triggered or a stop request was made.]52    std::same_as<bool> auto r1 = cv.wait_until(lock, ss.get_token(), oneHourAgo, []() { return false; });53    assert(!r1);54 55    std::same_as<bool> auto r2 = cv.wait_until(lock, ss.get_token(), oneHourLater, []() { return false; });56    assert(!r2);57 58    std::same_as<bool> auto r3 = cv.wait_until(lock, ss.get_token(), oneHourAgo, []() { return true; });59    assert(r3);60 61    std::same_as<bool> auto r4 = cv.wait_until(lock, ss.get_token(), oneHourLater, []() { return true; });62    assert(r4);63 64    // Postconditions: lock is locked by the calling thread.65    assert(lock.owns_lock());66  }67 68  // no stop request, pred was true69  {70    std::stop_source ss;71    std::condition_variable_any cv;72    Mutex mutex;73    Lock lock{mutex};74    ElapsedTimeCheck check(1min);75 76    std::same_as<bool> auto r1 = cv.wait_until(lock, ss.get_token(), oneHourAgo, []() { return true; });77    assert(r1);78 79    std::same_as<bool> auto r2 = cv.wait_until(lock, ss.get_token(), oneHourLater, []() { return true; });80    assert(r2);81  }82 83  // no stop request, pred was false, abs_time was in the past84  {85    std::stop_source ss;86    std::condition_variable_any cv;87    Mutex mutex;88    Lock lock{mutex};89    ElapsedTimeCheck check(1min);90 91    std::same_as<bool> auto r1 = cv.wait_until(lock, ss.get_token(), oneHourAgo, []() { return false; });92    assert(!r1);93  }94 95  // no stop request, pred was false until timeout96  {97    std::stop_source ss;98    std::condition_variable_any cv;99    Mutex mutex;100    Lock lock{mutex};101 102    auto oldTime = std::chrono::steady_clock::now();103 104    std::same_as<bool> auto r1 =105        cv.wait_until(lock, ss.get_token(), oldTime + std::chrono::milliseconds(2), [&]() { return false; });106 107    assert((std::chrono::steady_clock::now() - oldTime) >= std::chrono::milliseconds(2));108    assert(!r1);109  }110 111  // no stop request, pred was false, changed to true before timeout112  {113    std::stop_source ss;114    std::condition_variable_any cv;115    Mutex mutex;116    Lock lock{mutex};117 118    bool flag   = false;119    auto thread = support::make_test_thread([&]() {120      std::this_thread::sleep_for(std::chrono::milliseconds(2));121      std::unique_lock<Mutex> lock2{mutex};122      flag = true;123      cv.notify_all();124    });125 126    ElapsedTimeCheck check(10min);127 128    std::same_as<bool> auto r1 = cv.wait_until(lock, ss.get_token(), oneHourLater, [&]() { return flag; });129    assert(flag);130    assert(r1);131 132    thread.join();133  }134 135  // stop request comes while waiting136  {137    std::stop_source ss;138    std::condition_variable_any cv;139    Mutex mutex;140    Lock lock{mutex};141 142    std::atomic_bool start = false;143    std::atomic_bool done  = false;144    auto thread            = support::make_test_thread([&]() {145      start.wait(false);146      ss.request_stop();147 148      while (!done) {149        cv.notify_all();150        std::this_thread::sleep_for(std::chrono::milliseconds(2));151      }152    });153 154    ElapsedTimeCheck check(10min);155 156    std::same_as<bool> auto r = cv.wait_until(lock, ss.get_token(), oneHourLater, [&]() {157      start.store(true);158      start.notify_all();159      return false;160    });161    assert(!r);162    done = true;163    thread.join();164 165    assert(lock.owns_lock());166  }167 168  // #76807 Hangs in std::condition_variable_any when used with std::stop_token169  {170    class MyThread {171    public:172      MyThread() {173        thread_ = support::make_test_jthread([this](std::stop_token st) {174          while (!st.stop_requested()) {175            std::unique_lock lock{m_};176            cv_.wait_until(lock, st, std::chrono::steady_clock::now() + std::chrono::hours(1), [] { return false; });177          }178        });179      }180 181    private:182      std::mutex m_;183      std::condition_variable_any cv_;184      std::jthread thread_;185    };186 187    ElapsedTimeCheck check(10min);188 189    [[maybe_unused]] MyThread my_thread;190  }191 192  // request_stop potentially in-between check and wait193  {194    std::stop_source ss;195    std::condition_variable_any cv;196    Mutex mutex;197    Lock lock{mutex};198 199    std::atomic_bool pred_started        = false;200    std::atomic_bool request_stop_called = false;201    auto thread                          = support::make_test_thread([&]() {202      pred_started.wait(false);203      ss.request_stop();204      request_stop_called.store(true);205      request_stop_called.notify_all();206    });207 208    ElapsedTimeCheck check(10min);209 210    std::same_as<bool> auto r = cv.wait_until(lock, ss.get_token(), oneHourLater, [&]() {211      pred_started.store(true);212      pred_started.notify_all();213      request_stop_called.wait(false);214      return false;215    });216    assert(!r);217    thread.join();218 219    assert(lock.owns_lock());220  }221 222#if !defined(TEST_HAS_NO_EXCEPTIONS)223  // Throws: Any exception thrown by pred.224  {225    std::stop_source ss;226    std::condition_variable_any cv;227    Mutex mutex;228    Lock lock{mutex};229 230    try {231      cv.wait_until(lock, ss.get_token(), oneHourLater, []() -> bool { throw 5; });232      assert(false);233    } catch (int i) {234      assert(i == 5);235    }236  }237#endif //!defined(TEST_HAS_NO_EXCEPTIONS)238}239 240int main(int, char**) {241  test<std::mutex, std::unique_lock<std::mutex>>();242  test<std::shared_mutex, std::shared_lock<std::shared_mutex>>();243 244  return 0;245}246