From patchwork Wed Jul 4 22:17:10 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 169053 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 1DC9C2C0089 for ; Thu, 5 Jul 2012 08:17:35 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1342045057; h=Comment: DomainKey-Signature:Received:Received:Received:Received: MIME-Version:Received:Received:Date:Message-ID:Subject:From:To: Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=YubQbhD 6VJeEbAkubqIUHVyeAcM=; b=KBREEz4MgnN2kuSPkwAo3a+31Vj7LTDiMdg/BU/ GVvHfnZg2HOBiyDig2uOuRFLeMOabqXq6JUUENGzdWNZDFcSb/OHUO5h1Y5fcPHA MBFEaOrtEa+Ya/Q97PIWBWGFgvLrLvwXDxi0sdGwLcb7vxgVsp+6whUOYrKYxonC C2io= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:MIME-Version:Received:Received:Date:Message-ID:Subject:From:To:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=u8mkqntbUF1h9oNT8FqjfcErTyOzb0qqCkjwzxEbzyg2vWjzN5ogdd0N9XlLng UTlu4PSIlWcRQMCWY2BdENMkeeFc4MK1c/RAhy2LJWSNlgVsQNGK24ijmSX2o2gk 8U1Sqd+v2l0AFXwfSbQLyFGD17ZWDVbFQuEs/2gfhp/UM=; Received: (qmail 18277 invoked by alias); 4 Jul 2012 22:17:31 -0000 Received: (qmail 18261 invoked by uid 22791); 4 Jul 2012 22:17:30 -0000 X-SWARE-Spam-Status: No, hits=-4.4 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, KHOP_RCVD_TRUST, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_YE X-Spam-Check-By: sourceware.org Received: from mail-lb0-f175.google.com (HELO mail-lb0-f175.google.com) (209.85.217.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 04 Jul 2012 22:17:12 +0000 Received: by lbol5 with SMTP id l5so11871138lbo.20 for ; Wed, 04 Jul 2012 15:17:11 -0700 (PDT) MIME-Version: 1.0 Received: by 10.112.43.135 with SMTP id w7mr10885025lbl.48.1341440230939; Wed, 04 Jul 2012 15:17:10 -0700 (PDT) Received: by 10.112.48.6 with HTTP; Wed, 4 Jul 2012 15:17:10 -0700 (PDT) Date: Wed, 4 Jul 2012 23:17:10 +0100 Message-ID: Subject: [v3] fix libstdc++/53830 From: Jonathan Wakely To: "libstdc++" , gcc-patches Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This fixes a deadlock in condition_variable_any, which I should have fixed as part of PR 50862. 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. Tested x86_64-linux, committed to trunk. I'm also going to commit it on the 4.6 and 4.7 branches. commit 8c3d75d934e3e6d5cf313991c56af8844f725dce Author: Jonathan Wakely Date: Mon Jul 2 20:54:23 2012 +0100 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. diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable index c4e2080..85b50a7 100644 --- a/libstdc++-v3/include/std/condition_variable +++ b/libstdc++-v3/include/std/condition_variable @@ -176,6 +176,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: condition_variable_any() noexcept; @@ -202,21 +222,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)); @@ -237,11 +244,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; +} +