From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 102461 invoked by alias); 11 Nov 2015 17:09:08 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 102437 invoked by uid 89); 11 Nov 2015 17:09:07 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL,BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Wed, 11 Nov 2015 17:08:57 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (Postfix) with ESMTPS id 411703024BD; Wed, 11 Nov 2015 17:08:56 +0000 (UTC) Received: from localhost (ovpn-116-102.ams2.redhat.com [10.36.116.102]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id tABH8tE0006041; Wed, 11 Nov 2015 12:08:55 -0500 Date: Wed, 11 Nov 2015 17:09:00 -0000 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [patch] libstdc++/60421 (again) Loop in std::this_thread sleep functions Message-ID: <20151111170854.GO2937@redhat.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="5oH/S/bF6lOfqCQb" Content-Disposition: inline X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.5.24 (2015-08-30) X-SW-Source: 2015-11/txt/msg01401.txt.bz2 --5oH/S/bF6lOfqCQb Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline Content-length: 380 This fixes part of PR 60421 by looping in this_thread::sleep_for when it is interrupted by a signal, and looping in this_thread::sleep_until to handle clock adjustments. There are still problems with integer overflow/wrapping in sleep_for, which still need to be addressed somehow. Maybe using the new overflow-checking built-ins. Tested powerpc64le-linux, committed to trunk. --5oH/S/bF6lOfqCQb Content-Type: text/x-patch; charset=us-ascii Content-Disposition: attachment; filename="patch.txt" Content-length: 4846 commit 1773ceda34abcbe088048786ac869ee1740ce1d9 Author: Jonathan Wakely Date: Wed Nov 11 16:16:55 2015 +0000 Loop in std::this_thread sleep functions PR libstdc++/60421 * include/std/thread (this_thread::sleep_for): Retry on EINTR. (this_thread::sleep_until): Retry if time not reached. * src/c++11/thread.cc (__sleep_for): Retry on EINTR. * testsuite/30_threads/this_thread/60421.cc: Test interruption and non-steady clocks. diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread index c67ec46..5940e6e 100644 --- a/libstdc++-v3/include/std/thread +++ b/libstdc++-v3/include/std/thread @@ -297,7 +297,8 @@ _GLIBCXX_END_NAMESPACE_VERSION static_cast(__s.count()), static_cast(__ns.count()) }; - ::nanosleep(&__ts, 0); + while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR) + { } #else __sleep_for(__s, __ns); #endif @@ -309,8 +310,17 @@ _GLIBCXX_END_NAMESPACE_VERSION sleep_until(const chrono::time_point<_Clock, _Duration>& __atime) { auto __now = _Clock::now(); - if (__now < __atime) - sleep_for(__atime - __now); + if (_Clock::is_steady) + { + if (__now < __atime) + sleep_for(__atime - __now); + return; + } + while (__now < __atime) + { + sleep_for(__atime - __now); + __now = _Clock::now(); + } } _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/src/c++11/thread.cc b/libstdc++-v3/src/c++11/thread.cc index e116afa..3407e80 100644 --- a/libstdc++-v3/src/c++11/thread.cc +++ b/libstdc++-v3/src/c++11/thread.cc @@ -221,7 +221,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_cast(__s.count()), static_cast(__ns.count()) }; - ::nanosleep(&__ts, 0); + while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR) + { } #elif defined(_GLIBCXX_HAVE_SLEEP) # ifdef _GLIBCXX_HAVE_USLEEP ::sleep(__s.count()); diff --git a/libstdc++-v3/testsuite/30_threads/this_thread/60421.cc b/libstdc++-v3/testsuite/30_threads/this_thread/60421.cc index ecc4deb..5dbf257 100644 --- a/libstdc++-v3/testsuite/30_threads/this_thread/60421.cc +++ b/libstdc++-v3/testsuite/30_threads/this_thread/60421.cc @@ -15,12 +15,19 @@ // with this library; see the file COPYING3. If not see // . -// { dg-options "-std=gnu++11" } +// { dg-do run { target *-*-freebsd* *-*-dragonfly* *-*-netbsd* *-*-linux* *-*-gnu* *-*-solaris* *-*-cygwin *-*-rtems* *-*-darwin* powerpc-ibm-aix* } } +// { dg-options " -std=gnu++11 -pthread" { target *-*-freebsd* *-*-dragonfly* *-*-netbsd* *-*-linux* *-*-gnu* powerpc-ibm-aix* } } +// { dg-options " -std=gnu++11 -pthreads" { target *-*-solaris* } } +// { dg-options " -std=gnu++11 " { target *-*-cygwin *-*-rtems* *-*-darwin* } } // { dg-require-cstdint "" } +// { dg-require-gthreads "" } // { dg-require-time "" } #include #include +#include +#include +#include #include void @@ -28,11 +35,64 @@ test01() { std::this_thread::sleep_for(std::chrono::seconds(0)); std::this_thread::sleep_for(std::chrono::seconds(-1)); - std::this_thread::sleep_for(std::chrono::duration::zero()); + std::this_thread::sleep_for(std::chrono::duration::zero()); +} + +void +test02() +{ + bool test __attribute__((unused)) = true; + + // test interruption of this_thread::sleep_for() by a signal + struct sigaction sa{ }; + sa.sa_handler = +[](int) { }; + sigaction(SIGUSR1, &sa, 0); + bool result = false; + std::atomic sleeping{false}; + std::thread t([&result, &sleeping] { + auto start = std::chrono::system_clock::now(); + auto time = std::chrono::seconds(3); + sleeping = true; + std::this_thread::sleep_for(time); + result = std::chrono::system_clock::now() >= (start + time); + }); + while (!sleeping) { } + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + pthread_kill(t.native_handle(), SIGUSR1); + t.join(); + VERIFY( result ); +} + +struct slow_clock +{ + using rep = std::chrono::system_clock::rep; + using period = std::chrono::system_clock::period; + using duration = std::chrono::system_clock::duration; + using time_point = std::chrono::time_point; + static constexpr bool is_steady = false; + + static time_point now() + { + auto real = std::chrono::system_clock::now(); + return time_point{real.time_since_epoch() / 2}; + } +}; + +void +test03() +{ + bool test __attribute__((unused)) = true; + + // test that this_thread::sleep_until() handles clock adjustments + auto when = slow_clock::now() + std::chrono::seconds(2); + std::this_thread::sleep_until(when); + VERIFY( slow_clock::now() >= when ); } int main() { test01(); + test02(); + test03(); } --5oH/S/bF6lOfqCQb--