brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.6 KiB · b4cfc3b Raw
157 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-exceptions10// UNSUPPORTED: no-threads11 12// <condition_variable>13 14// class condition_variable_any;15 16// RUN: %{build}17// RUN: %{run} 118// RUN: %{run} 219// RUN: %{run} 320// RUN: %{run} 421// RUN: %{run} 522// RUN: %{run} 623// RUN: %{run} 724// RUN: %{run} 825// RUN: %{run} 926 27// -----------------------------------------------------------------------------28// Overview29//   Check that std::terminate is called if wait(...) fails to meet its post30//   conditions. This can happen when reacquiring the mutex throws31//   an exception.32//33//  The following methods are tested within this file34//   1.  void wait(Lock& lock);35//   2.  void wait(Lock& lock, Pred);36//   3.  void wait_for(Lock& lock, Duration);37//   4.  void wait_for(Lock& lock, Duration, Pred);38//   5.  void wait_until(Lock& lock, TimePoint);39//   6.  void wait_until(Lock& lock, TimePoint, Pred);40//   7.  bool wait(Lock& lock, stop_token stoken, Predicate pred);41//   8.  bool wait_for(Lock& lock, stop_token stoken, Duration, Predicate pred);42//   9.  bool wait_until(Lock& lock, stop_token stoken, TimePoint, Predicate pred);43//44// Plan45//   1 Create a mutex type, 'ThrowingMutex', that throws when the lock is acquired46//     for the *second* time.47//48//   2 Replace the terminate handler with one that exits with a '0' exit code.49//50//   3 Create a 'condition_variable_any' object 'cv' and a 'ThrowingMutex'51//     object 'm' and lock 'm'.52//53//   4 Start a thread 'T2' that will notify 'cv' once 'm' has been unlocked.54//55//   5 From the main thread call the specified wait method on 'cv' with 'm'.56//     When 'T2' notifies 'cv' and the wait method attempts to re-lock57//    'm' an exception will be thrown from 'm.lock()'.58//59//   6 Check that control flow does not return from the wait method and that60//     terminate is called (If the program exits with a 0 exit code we know61//     that terminate has been called)62 63 64#include <atomic>65#include <cassert>66#include <chrono>67#include <condition_variable>68#include <cstdlib>69#include <exception>70#include <string>71#include <stop_token>72#include <thread>73 74#include "make_test_thread.h"75#include "test_macros.h"76 77void my_terminate() {78  std::_Exit(0); // Use _Exit to prevent cleanup from taking place.79}80 81// The predicate used in the cv.wait calls.82bool pred = false;83bool pred_function() {84  return pred == true;85}86 87class ThrowingMutex88{89  std::atomic_bool locked;90  unsigned state = 0;91  ThrowingMutex(const ThrowingMutex&) = delete;92  ThrowingMutex& operator=(const ThrowingMutex&) = delete;93public:94  ThrowingMutex() {95    locked = false;96  }97  ~ThrowingMutex() = default;98 99  void lock() {100    locked = true;101    if (++state == 2) {102      assert(pred); // Check that we actually waited until we were signaled.103      throw 1;  // this throw should end up calling terminate()104    }105  }106 107  void unlock() { locked = false; }108  bool isLocked() const { return locked == true; }109};110 111ThrowingMutex mut;112std::condition_variable_any cv;113 114void signal_me() {115  while (mut.isLocked()) {} // wait until T1 releases mut inside the cv.wait call.116  pred = true;117  cv.notify_one();118}119 120typedef std::chrono::system_clock Clock;121typedef std::chrono::milliseconds MS;122 123int main(int argc, char **argv) {124  assert(argc == 2);125  int id = std::stoi(argv[1]);126  assert(id >= 1 && id <= 9);127  std::set_terminate(my_terminate); // set terminate after std::stoi because it can throw.128  MS wait(250);129  try {130    mut.lock();131    assert(pred == false);132    support::make_test_thread(signal_me).detach();133    switch (id) {134      case 1: cv.wait(mut); break;135      case 2: cv.wait(mut, pred_function); break;136      case 3: cv.wait_for(mut, wait); break;137      case 4: cv.wait_for(mut, wait, pred_function); break;138      case 5: cv.wait_until(mut, Clock::now() + wait); break;139      case 6: cv.wait_until(mut, Clock::now() + wait, pred_function); break;140#if TEST_STD_VER >= 20141      case 7: cv.wait(mut, std::stop_source{}.get_token(), pred_function); break;142      case 8: cv.wait_for(mut, std::stop_source{}.get_token(), wait, pred_function); break;143      case 9: cv.wait_until(mut, std::stop_source{}.get_token(), Clock::now() + wait, pred_function); break;144#else145      case 7:146      case 8:147      case 9:148        return 0;149#endif150      default: assert(false);151    }152  } catch (...) {}153  assert(false);154 155  return 0;156}157