From 8fd5062025a4be33bf816f1060c3259cf1a9d624 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Thu, 5 Jul 2012 01:10:10 +0000 Subject: [PATCH] re PR libstdc++/53830 (condition_variable_any - deadlock issue) PR libstdc++/53830 * include/std/condition_variable (condition_variable_any::wait): Move _Unlock type to class scope. (condition_variable_any::wait_until): Reuse it. * testsuite/30_threads/condition_variable_any/53830.cc: New. From-SVN: r189275 --- libstdc++-v3/ChangeLog | 8 +++ libstdc++-v3/include/std/condition_variable | 48 +++++++------ .../condition_variable_any/53830.cc | 68 +++++++++++++++++++ 3 files changed, 104 insertions(+), 20 deletions(-) create mode 100644 libstdc++-v3/testsuite/30_threads/condition_variable_any/53830.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index ff20cb1a197a..6323133f558c 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,11 @@ +2012-07-05 Jonathan Wakely + + PR libstdc++/53830 + * include/std/condition_variable (condition_variable_any::wait): + Move _Unlock type to class scope. + (condition_variable_any::wait_until): Reuse it. + * testsuite/30_threads/condition_variable_any/53830.cc: New. + 2012-06-20 Jörg Sonnenberger Jonathan Wakely diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable index ff65dc49ce44..0f75d8e446ca 100644 --- a/libstdc++-v3/include/std/condition_variable +++ b/libstdc++-v3/include/std/condition_variable @@ -1,6 +1,6 @@ // -*- C++ -*- -// Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. +// Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -171,6 +171,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION condition_variable _M_cond; mutex _M_mutex; + // scoped unlock - unlocks in ctor, re-locks in dtor + template + struct _Unlock + { + explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); } + + ~_Unlock() noexcept(false) + { + if (uncaught_exception()) + __try { _M_lock.lock(); } __catch(...) { } + else + _M_lock.lock(); + } + + _Unlock(const _Unlock&) = delete; + _Unlock& operator=(const _Unlock&) = delete; + + _Lock& _M_lock; + }; + public: typedef condition_variable::native_handle_type native_handle_type; @@ -198,21 +218,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void wait(_Lock& __lock) { - // scoped unlock - unlocks in ctor, re-locks in dtor - struct _Unlock { - explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); } - ~_Unlock() noexcept(false) - { - if (uncaught_exception()) - __try { _M_lock.lock(); } __catch(...) { } - else - _M_lock.lock(); - } - _Lock& _M_lock; - }; - unique_lock __my_lock(_M_mutex); - _Unlock __unlock(__lock); + _Unlock<_Lock> __unlock(__lock); // _M_mutex must be unlocked before re-locking __lock so move // ownership of _M_mutex lock to an object with shorter lifetime. unique_lock __my_lock2(std::move(__my_lock)); @@ -233,11 +240,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION wait_until(_Lock& __lock, const chrono::time_point<_Clock, _Duration>& __atime) { - unique_lock __my_lock(_M_mutex); - __lock.unlock(); - cv_status __status = _M_cond.wait_until(__my_lock, __atime); - __lock.lock(); - return __status; + unique_lock __my_lock(_M_mutex); + _Unlock<_Lock> __unlock(__lock); + // _M_mutex must be unlocked before re-locking __lock so move + // ownership of _M_mutex lock to an object with shorter lifetime. + unique_lock __my_lock2(std::move(__my_lock)); + return _M_cond.wait_until(__my_lock2, __atime); } template. + +// PR libstdc++/53830 +// Test for deadlock in condition_variable_any::wait_for + +#include +#include +#include +#include +#include + +std::mutex mutex; +std::condition_variable_any cv; + +std::atomic barrier(0); + +// waits for data from another thread +void wait_for_data() +{ + std::unique_lock lock(mutex); + barrier = 1; + cv.wait_for(lock, std::chrono::milliseconds(100), []{ return false; }); + // read data +} + +// passes data to waiting thread +void provide_data() +{ + while (barrier == 0) + std::this_thread::yield(); + std::unique_lock lock(mutex); + // pass data + std::this_thread::sleep_for(std::chrono::seconds(1)); + cv.notify_one(); +} + +int main() +{ + std::thread thread1(wait_for_data); + provide_data(); + thread1.join(); + return 0; +} + -- 2.47.2