Index: include/shared_mutex =================================================================== --- include/shared_mutex +++ include/shared_mutex @@ -170,6 +170,8 @@ shared_timed_mutex::try_lock_until( const chrono::time_point<_Clock, _Duration>& __abs_time) { + bool __write_entered_timeout = false; + { unique_lock __lk(__mut_); if (__state_ & __write_entered_) { @@ -188,15 +190,22 @@ while (true) { cv_status __status = __gate2_.wait_until(__lk, __abs_time); - if ((__state_ & __n_readers_) == 0) + if ((__state_ & __n_readers_) == 0) { break; + } if (__status == cv_status::timeout) { + __write_entered_timeout = true; __state_ &= ~__write_entered_; - return false; + break; } } } + } + if (__write_entered_timeout) { + __gate1_.notify_all(); + return false; + } return true; } Index: test/std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/try_lock_until_deadlock_bug.pass.cpp =================================================================== --- /dev/null +++ test/std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/try_lock_until_deadlock_bug.pass.cpp @@ -0,0 +1,82 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: libcpp-has-no-threads +// UNSUPPORTED: c++03, c++98, c++11 + +// + +// class shared_timed_mutex; + +#include + +#include +#include +#include +#include +#include + +std::shared_timed_mutex m; + +std::atomic_bool read_lock_held = ATOMIC_VAR_INIT(false); + +const int total_readers = 2; +std::atomic readers_done = ATOMIC_VAR_INIT(0); + +typedef std::chrono::steady_clock Clock; +typedef Clock::time_point time_point; +typedef Clock::duration duration; +typedef std::chrono::milliseconds ms; + +void reader_one() { + m.lock_shared(); + read_lock_held = true; + while(readers_done != total_readers) { + } + m.unlock_shared(); +} + +// Wait until the reader_one has a read lock then attempt to get the write lock. +void writer_one() { + while (read_lock_held == false) {} + bool b = m.try_lock_for(ms(500)); + assert(b == false); +} + +void reader_two() { + // Wait until writer_one is waiting for the write lock. + while (read_lock_held == false) {} + while (m.try_lock_shared()) { + m.unlock_shared(); + } + // Attempt to get the read lock. writer_one should be blocking us because + // writer_one is blocked by reader_one. + m.lock_shared(); + m.unlock_shared(); + ++readers_done; +} + +int main() +{ + std::thread t1(reader_one); + std::thread t2(writer_one); + // create some readers + std::thread t3(reader_two); + std::thread t4(reader_two); + // Kill the test after 10 seconds if it hasn't completed. + time_point end_point = Clock::now() + std::chrono::seconds(10); + while (readers_done != total_readers && Clock::now() < end_point) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + assert(readers_done == total_readers); + t1.join(); + t2.join(); + t3.join(); + t4.join(); +}