| // { dg-options "-pthread" } |
| // { dg-do run { target { *-*-linux* *-*-gnu* } } } |
| // { dg-require-effective-target c++11 } |
| // { dg-require-effective-target pthread } |
| // { dg-require-gthreads "" } |
| |
| #include <condition_variable> |
| #include <chrono> |
| #include <mutex> |
| #include <thread> |
| |
| // PR libstdc++/103382 |
| |
| template<typename F> |
| void |
| test_cancel(F wait) |
| { |
| std::mutex m; |
| std::condition_variable cv; |
| bool waiting = false; |
| |
| std::thread t([&] { |
| std::unique_lock<std::mutex> lock(m); |
| waiting = true; |
| wait(cv, lock); // __forced_unwind exception should not terminate process. |
| }); |
| |
| // Ensure the condition variable is waiting before we cancel. |
| // This shouldn't be necessary because pthread_mutex_lock is not |
| // a cancellation point, but no harm in making sure we test what |
| // we intend to test: that cancel during a wait doesn't abort. |
| while (true) |
| { |
| std::unique_lock<std::mutex> lock(m); |
| if (waiting) |
| break; |
| } |
| |
| pthread_cancel(t.native_handle()); |
| t.join(); |
| } |
| |
| int main() |
| { |
| test_cancel( |
| [](std::condition_variable& cv, std::unique_lock<std::mutex>& l) { |
| cv.wait(l); |
| }); |
| |
| test_cancel( |
| [](std::condition_variable& cv, std::unique_lock<std::mutex>& l) { |
| cv.wait(l, []{ return false; }); |
| }); |
| |
| using mins = std::chrono::minutes; |
| |
| test_cancel( |
| [](std::condition_variable& cv, std::unique_lock<std::mutex>& l) { |
| cv.wait_for(l, mins(1)); |
| }); |
| |
| test_cancel( |
| [](std::condition_variable& cv, std::unique_lock<std::mutex>& l) { |
| cv.wait_until(l, std::chrono::system_clock::now() + mins(1)); |
| }); |
| } |