brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.7 KiB · 48efbf1 Raw
129 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 Predicate>16//   void wait(Lock& lock, Predicate pred);17 18#include <condition_variable>19#include <atomic>20#include <cassert>21#include <mutex>22#include <thread>23 24#include "make_test_thread.h"25#include "test_macros.h"26 27template <class Mutex>28struct MyLock : std::unique_lock<Mutex> {29  using std::unique_lock<Mutex>::unique_lock;30};31 32template <class Lock>33void test() {34  using Mutex = typename Lock::mutex_type;35 36  // Test unblocking via a call to notify_one() in another thread.37  //38  // To test this, we try to minimize the likelihood that we got awoken by a39  // spurious wakeup by updating the likely_spurious flag only immediately40  // before we perform the notification.41  {42    std::atomic<bool> ready(false);43    std::atomic<bool> likely_spurious(true);44    std::condition_variable_any cv;45    Mutex mutex;46 47    std::thread t1 = support::make_test_thread([&] {48      Lock lock(mutex);49      ready = true;50      cv.wait(lock, [&] { return !likely_spurious; });51    });52 53    std::thread t2 = support::make_test_thread([&] {54      while (!ready) {55        // spin56      }57 58      // Acquire the same mutex as t1. This ensures that the condition variable has started59      // waiting (and hence released that mutex).60      Lock lock(mutex);61 62      likely_spurious = false;63      lock.unlock();64      cv.notify_one();65    });66 67    t2.join();68    t1.join();69  }70 71  // Test unblocking via a spurious wakeup.72  //73  // To test this, we basically never wake up the condition variable. This way, we74  // are hoping to get out of the wait via a spurious wakeup.75  //76  // However, since spurious wakeups are not required to even happen, this test is77  // only trying to trigger that code path, but not actually asserting that it is78  // taken. In particular, we do need to eventually ensure we get out of the wait79  // by standard means, so we actually wake up the thread at the end.80  {81    std::atomic<bool> ready(false);82    std::atomic<bool> awoken(false);83    std::condition_variable_any cv;84    Mutex mutex;85 86    std::thread t1 = support::make_test_thread([&] {87      Lock lock(mutex);88      ready = true;89      cv.wait(lock, [&] { return true; });90      awoken = true;91    });92 93    std::thread t2 = support::make_test_thread([&] {94      while (!ready) {95        // spin96      }97 98      // Acquire the same mutex as t1. This ensures that the condition variable has started99      // waiting (and hence released that mutex).100      Lock lock(mutex);101      lock.unlock();102 103      // Give some time for t1 to be awoken spuriously so that code path is used.104      std::this_thread::sleep_for(std::chrono::seconds(1));105 106      // We would want to assert that the thread has been awoken after this time,107      // however nothing guarantees us that it ever gets spuriously awoken, so108      // we can't really check anything. This is still left here as documentation.109      bool woke = awoken.load();110      assert(woke || !woke);111 112      // Whatever happened, actually awaken the condition variable to ensure the test finishes.113      cv.notify_one();114    });115 116    t2.join();117    t1.join();118  }119}120 121int main(int, char**) {122  test<std::unique_lock<std::mutex>>();123  test<std::unique_lock<std::timed_mutex>>();124  test<MyLock<std::mutex>>();125  test<MyLock<std::timed_mutex>>();126 127  return 0;128}129