From patchwork Sun Oct 27 15:46:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Crowe X-Patchwork-Id: 1185042 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-511862-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=quarantine dis=none) header.from=mcrowe.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="FI/K3lTb"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=mcrowe.com header.i=@mcrowe.com header.b="l7xXXyFf"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 471Mhx4hV7z9sP4 for ; Mon, 28 Oct 2019 02:49:05 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; q=dns; s=default; b=N8W H37BqE2e6WEF07zZKqHmNJHD4H6vdVh2ft02rRfn1nkUEaW2sa44a9GA/AB2EkHA OJCHqmfC1AQRFZmHycxgZX1OV5UUKV+2mcMpYCmsd0D08VLAMhAqcrmiQbZvj/YX gqRZQ1N92rPF/axyDtP6vfwG5yPSBrKCDnmoYW88= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=default; bh=kCmXvoAko RjHPLKULG1eJUY4GkE=; b=FI/K3lTbV+6CJuPIoE+X6DgMWpB9pmriya8pu7DVB J9PW/DO/9R4lTR3g7k8knSIezS81sLMMLTB7KeH9CAT3XpAGtppxOwjMbqOvMcYE SkbfGN+3D4lQCs/Hw8AjsZD6ZtDBDWu9M+UweHExb5GWDVMlvPipZleH9r4WWcuC 3M= Received: (qmail 95039 invoked by alias); 27 Oct 2019 15:47:04 -0000 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 Received: (qmail 94518 invoked by uid 89); 27 Oct 2019 15:47:01 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.1 spammy=properly, HX-Languages-Length:2645, warp, whilst X-HELO: avasout03.plus.net Received: from avasout03.plus.net (HELO avasout03.plus.net) (84.93.230.244) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 27 Oct 2019 15:46:59 +0000 Received: from deneb ([80.229.24.9]) by smtp with ESMTP id OkkoieIUmtvkXOkkpihKUR; Sun, 27 Oct 2019 15:46:57 +0000 X-Clacks-Overhead: "GNU Terry Pratchett" X-CM-Score: 0.00 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mcrowe.com; s=20191005; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description; bh=9S2mIPLMdjHp1/R4NIit2rd5swqiFZE0aCMURMebkWc=; b=l7xXX yFfzNWe1Qyz7gyFpL8NHZkNE2v4i0DKUd1CmQZe8rcujpI7bUjnhtXceC00AyKmbQ+pD2IIPrL0ZO /A5jXKx05dFgFgJvaCSbcQU8L46v1/i0pBhFyWMRZ43pqhPBP5Y3r3mEXiALLiYEvlc7eIdgtFcX5 F6CeOVV9mj4asWrn8AoMxH+wx5jgrR13nNYqC/0EMojGExV6sjyGA8miss8hqm9TYsCEAKxdPWa4w +xsOTTA+vNG8Xu3IeinqU78tFu5fUvwzd4ZlQKx9zL1Bzb0rWfaDuKTlzLHxajPyErgGboo+qT8R3 XxGZItleOVmD/EF2K7DFWTjTTJWkQ==; Received: from mac by deneb with local (Exim 4.92) (envelope-from ) id 1iOkkf-0005PV-74; Sun, 27 Oct 2019 15:46:45 +0000 From: Mike Crowe To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Cc: Mike Crowe Subject: [PATCH v4 1/7] libstdc++: Improve async test Date: Sun, 27 Oct 2019 15:46:24 +0000 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Add tests for waiting for the future using both std::chrono::steady_clock and std::chrono::system_clock in preparation for dealing with those clocks properly in futex.cc. * libstdc++-v3/testsuite/30_threads/async/async.cc (test02): Test steady_clock with std::future::wait_until. (test03): Add new test templated on clock type waiting for future associated with async to resolve. (main): Call test03 to test both system_clock and steady_clock. --- libstdc++-v3/testsuite/30_threads/async/async.cc | 33 +++++++++++++++++- 1 file changed, 33 insertions(+) diff --git a/libstdc++-v3/testsuite/30_threads/async/async.cc b/libstdc++-v3/testsuite/30_threads/async/async.cc index 851925b..1b6e2ff 100644 --- a/libstdc++-v3/testsuite/30_threads/async/async.cc +++ b/libstdc++-v3/testsuite/30_threads/async/async.cc @@ -51,17 +51,50 @@ void test02() VERIFY( status == std::future_status::timeout ); status = f1.wait_until(std::chrono::system_clock::now()); VERIFY( status == std::future_status::timeout ); + status = f1.wait_until(std::chrono::steady_clock::now()); + VERIFY( status == std::future_status::timeout ); l.unlock(); // allow async thread to proceed f1.wait(); // wait for it to finish status = f1.wait_for(std::chrono::milliseconds(0)); VERIFY( status == std::future_status::ready ); status = f1.wait_until(std::chrono::system_clock::now()); VERIFY( status == std::future_status::ready ); + status = f1.wait_until(std::chrono::steady_clock::now()); + VERIFY( status == std::future_status::ready ); +} + +// This test is prone to failures if run on a loaded machine where the +// kernel decides not to schedule us for several seconds. It also +// assumes that no-one will warp CLOCK whilst the test is +// running when CLOCK is std::chrono::system_clock. +template +void test03() +{ + auto const start = CLOCK::now(); + future f1 = async(launch::async, []() { + std::this_thread::sleep_for(std::chrono::seconds(2)); + }); + std::future_status status; + + status = f1.wait_for(std::chrono::milliseconds(500)); + VERIFY( status == std::future_status::timeout ); + + status = f1.wait_until(start + std::chrono::seconds(1)); + VERIFY( status == std::future_status::timeout ); + + status = f1.wait_until(start + std::chrono::seconds(5)); + VERIFY( status == std::future_status::ready ); + + auto const elapsed = CLOCK::now() - start; + VERIFY( elapsed >= std::chrono::seconds(2) ); + VERIFY( elapsed < std::chrono::seconds(5) ); } int main() { test01(); test02(); + test03(); + test03(); return 0; } From patchwork Sun Oct 27 15:46:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Crowe X-Patchwork-Id: 1185046 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-511864-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=quarantine dis=none) header.from=mcrowe.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="MHLOatIr"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=mcrowe.com header.i=@mcrowe.com header.b="EXzcqscr"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 471Mjf40QMz9sP4 for ; Mon, 28 Oct 2019 02:49:42 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; q=dns; s=default; b=G3L YISGSpbmJa0cwgcQ+8SoHu43TcrKl8b/zyocB/NVVB2QK+ppv+LTT9VgM2ucm4qS 23S+uYeNqlgoGnHtNU59UaUbtGOuqxKLj9pGK5DhbqEWWRC2kmvYnUwBFE98Nv5m /aQYUSa26kUiJkDFZDQc1MRWbW0y4ri/3O9CNv00= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=default; bh=4+ZvAMe7+ a/B4B3q3oNv/5HJ2BQ=; b=MHLOatIrS28lqlbB0aH6pdX5E47Y8GtHoud2ZDdWL /YgKOX603ZJpOIKhH+4Wj+8+/Ywu0gR64ulUYQhOzezF6ApA0vraB3j/n2o+21j+ oXj4qDZhabhT12eezrdq1VLP/Sgv+VPG9A/wnKVOzOPNcZEaRYZSPXfpcEZJ/2yk RI= Received: (qmail 95990 invoked by alias); 27 Oct 2019 15:47:10 -0000 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 Received: (qmail 95646 invoked by uid 89); 27 Oct 2019 15:47:07 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.1 spammy=calculate, discovering, accessed, HContent-Transfer-Encoding:8bit X-HELO: avasout06.plus.net Received: from avasout06.plus.net (HELO avasout06.plus.net) (212.159.14.18) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 27 Oct 2019 15:47:05 +0000 Received: from deneb ([80.229.24.9]) by smtp with ESMTP id Okkxi7yPxuVHWOkkyiL2n6; Sun, 27 Oct 2019 15:47:05 +0000 X-Clacks-Overhead: "GNU Terry Pratchett" X-CM-Score: 0.00 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mcrowe.com; s=20191005; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description; bh=ICl33uoI0NBAbt1682vcnx7NCsyov1tFMNLlTekF6Kw=; b=EXzcq scr0e87/hDup1uLTpEqF+jxbSLBdaKaCYH+aNT0dg56o3mz5vx3op1OpvotW0tN5G0OWDQYgDEIqG 1fjzSnmXZ7jugcnvaVxcqBeFjmvCZ9b1HIfqeBU2U22reneNknFe5ML2/CosjKHOfH4ahjywnfVnQ Z5Mz5TmnMBI8iMYHmb6U53yHh42+imXTQ/jPwbohGVKmNXDuyphOjgt5sp1HpZ0QDUj0M5YexcK1i Syk7sbRmZt2WgYPYGTCXTfalEEuK/HRm874XB0K9ZEhfGPJXMfM7WZDuFrCUfTz3EEF4rPX29z6uS u85L8VscEZsdE5L4n1GNXP3CKXvHA==; Received: from mac by deneb with local (Exim 4.92) (envelope-from ) id 1iOkkf-0005Pv-Ti; Sun, 27 Oct 2019 15:46:45 +0000 From: Mike Crowe To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Cc: Mike Crowe Subject: [PATCH v4 2/7] libstdc++ futex: Use FUTEX_CLOCK_REALTIME for wait Date: Sun, 27 Oct 2019 15:46:25 +0000 Message-Id: <00d3253ff2ecc1ecc99d96ab12cc19fdc3e01785.1572191159.git-series.mac@mcrowe.com> In-Reply-To: References: MIME-Version: 1.0 The futex system call supports waiting for an absolute time if FUTEX_WAIT_BITSET is used rather than FUTEX_WAIT. Doing so provides two benefits: 1. The call to gettimeofday is not required in order to calculate a relative timeout. 2. If someone changes the system clock during the wait then the futex timeout will correctly expire earlier or later. Currently that only happens if the clock is changed prior to the call to gettimeofday. According to futex(2), support for FUTEX_CLOCK_REALTIME was added in the v2.6.28 Linux kernel and FUTEX_WAIT_BITSET was added in v2.6.25. To ensure that the code still works correctly with earlier kernel versions, an ENOSYS error from futex[1] results in the futex_clock_realtime_unavailable flag being set. This flag is used to avoid the unnecessary unsupported futex call in the future and to fall back to the previous gettimeofday and relative time implementation. glibc applied an equivalent switch in pthread_cond_timedwait to use FUTEX_CLOCK_REALTIME and FUTEX_WAIT_BITSET rather than FUTEX_WAIT for glibc-2.10 back in 2009. See glibc:cbd8aeb836c8061c23a5e00419e0fb25a34abee7 The futex_clock_realtime_unavailable flag is accessed using std::memory_order_relaxed to stop it becoming a bottleneck. If the first two calls to _M_futex_wait_until happen to happen simultaneously then the only consequence is that both will try to use FUTEX_CLOCK_REALTIME, both risk discovering that it doesn't work and, if so, both set the flag. [1] This is how glibc's nptl-init.c determines whether these flags are supported. * libstdc++-v3/src/c++11/futex.cc: Add new constants for required futex flags. Add futex_clock_realtime_unavailable flag to store result of trying to use FUTEX_CLOCK_REALTIME. (__atomic_futex_unsigned_base::_M_futex_wait_until): Try to use FUTEX_WAIT_BITSET with FUTEX_CLOCK_REALTIME and only fall back to using gettimeofday and FUTEX_WAIT if that's not supported. --- libstdc++-v3/src/c++11/futex.cc | 37 ++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+) diff --git a/libstdc++-v3/src/c++11/futex.cc b/libstdc++-v3/src/c++11/futex.cc index 3ea32f7..38ae448 100644 --- a/libstdc++-v3/src/c++11/futex.cc +++ b/libstdc++-v3/src/c++11/futex.cc @@ -35,8 +35,16 @@ // Constants for the wait/wake futex syscall operations const unsigned futex_wait_op = 0; +const unsigned futex_wait_bitset_op = 9; +const unsigned futex_clock_realtime_flag = 256; +const unsigned futex_bitset_match_any = ~0; const unsigned futex_wake_op = 1; +namespace +{ + std::atomic futex_clock_realtime_unavailable; +} + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -58,6 +66,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } else { + if (!futex_clock_realtime_unavailable.load(std::memory_order_relaxed)) + { + struct timespec rt; + rt.tv_sec = __s.count(); + rt.tv_nsec = __ns.count(); + if (syscall (SYS_futex, __addr, + futex_wait_bitset_op | futex_clock_realtime_flag, + __val, &rt, nullptr, futex_bitset_match_any) == -1) + { + __glibcxx_assert(errno == EINTR || errno == EAGAIN + || errno == ETIMEDOUT || errno == ENOSYS); + if (errno == ETIMEDOUT) + return false; + if (errno == ENOSYS) + { + futex_clock_realtime_unavailable.store(true, + std::memory_order_relaxed); + // Fall through to legacy implementation if the system + // call is unavailable. + } + else + return true; + } + else + return true; + } + + // We only get to here if futex_clock_realtime_unavailable was + // true or has just been set to true. struct timeval tv; gettimeofday (&tv, NULL); // Convert the absolute timeout value to a relative timeout From patchwork Sun Oct 27 15:46:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Crowe X-Patchwork-Id: 1185047 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-511865-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=quarantine dis=none) header.from=mcrowe.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="KlueNX5z"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=mcrowe.com header.i=@mcrowe.com header.b="YtLm9wOO"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 471MkH1zknz9sP4 for ; Mon, 28 Oct 2019 02:50:15 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; q=dns; s=default; b=hjc E/MHQaQ0ayPx3ApOLoPvn8ZN2ZHirE3Mka6lDrbqKSoI5gkJ5SCPeMUfWv5P/cVc BzSsJtvfS3W0PnSZbeRqANKzoQYXumYecep8TntZ0Nbycd7bEzO5G+whK+BrxHTx xIH7FLKWxqB7IAp3LFXbVGtf3R0LFIwVHnT12A5Y= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=default; bh=7swj9fOYg d1/ZJwHzmQymFmtj80=; b=KlueNX5zKJ2P2ytDWqczSsnYfQhEyv3PfNipOrazH /ULVDZ74tvs22OFj4Qn4EPkMFYvdKjza7m9m079uuOKRfBWvsCowpBljZp5C8aBh ZIaEvVa3vhVIQ1OhPHgXLQartgv1n7Ees1SMURjon1DScBn3lTHL+q2SLjHEjmuW Ts= Received: (qmail 111350 invoked by alias); 27 Oct 2019 15:50:07 -0000 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 Received: (qmail 111338 invoked by uid 89); 27 Oct 2019 15:50:07 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.3 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_SOFTFAIL autolearn=ham version=3.3.1 spammy=XXX, HX-detected-operating-system:timestamps, libsupc X-HELO: eggs.gnu.org Received: from eggs.gnu.org (HELO eggs.gnu.org) (209.51.188.92) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 27 Oct 2019 15:50:04 +0000 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iOknp-0005pe-32 for gcc-patches@gcc.gnu.org; Sun, 27 Oct 2019 11:50:02 -0400 Received: from avasout03.plus.net ([84.93.230.244]:59627) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iOkno-0005nB-Qz for gcc-patches@gcc.gnu.org; Sun, 27 Oct 2019 11:50:01 -0400 Received: from deneb ([80.229.24.9]) by smtp with ESMTP id OkkiieIUYtvkXOkkjihKUF; Sun, 27 Oct 2019 15:46:58 +0000 X-Clacks-Overhead: "GNU Terry Pratchett" X-CM-Score: 0.00 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mcrowe.com; s=20191005; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description; bh=373Y0alntjcQZAM4gL2b6ml6f3bB/FxCfTftbnR1HjY=; b=YtLm9 wOO1R62LqL8AFrbl/C02AarAMq9v67S5LC4ucs4VXjYRDgLSNsXrFYhKIi8leqzzIVHy7/Z9rGpfR +e5YqUy0DuxUM9dvzp3MuVvzw+ovaC2loIORwOUu/LeEJuZOXR9DYBVMeHWFqyb7M10fcawzpGxn6 6QSQYO2K1WPzJoDREJ5AiNupKCI9rvppWJ5l5H1ryXyqkSv6Njso2pb9NT7QfeaH6YVRoHygBIEiL 8PLb/5Z7J23kDUU1FlMj2IZJ5pW2KXd2kw/4d18IiG9OJ0qypDfqImU2vQpCqL4yv8h7JuywIs+AS pvcDqihtZgsSP5Kz+PMrtQcK3NbIw==; Received: from mac by deneb with local (Exim 4.92) (envelope-from ) id 1iOkkg-0005QX-KX; Sun, 27 Oct 2019 15:46:46 +0000 From: Mike Crowe To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Cc: Mike Crowe Subject: [PATCH v4 3/7] libstdc++ futex: Support waiting on std::chrono::steady_clock directly Date: Sun, 27 Oct 2019 15:46:26 +0000 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x (no timestamps) [generic] [fuzzy] X-Received-From: 84.93.230.244 The user-visible effect of this change is for std::future::wait_until to use CLOCK_MONOTONIC when passed a timeout of std::chrono::steady_clock type. This makes it immune to any changes made to the system clock CLOCK_REALTIME. Add an overload of __atomic_futex_unsigned::_M_load_and_text_until_impl that accepts a std::chrono::steady_clock, and correctly passes this through to __atomic_futex_unsigned_base::_M_futex_wait_until_steady which uses CLOCK_MONOTONIC for the timeout within the futex system call. These functions are mostly just copies of the std::chrono::system_clock versions with small tweaks. Prior to this commit, a std::chrono::steady timeout would be converted via std::chrono::system_clock which risks reducing or increasing the timeout if someone changes CLOCK_REALTIME whilst the wait is happening. (The commit immediately prior to this one increases the window of opportunity for that from a short period during the calculation of a relative timeout, to the entire duration of the wait.) FUTEX_WAIT_BITSET was added in kernel v2.6.25. If futex reports ENOSYS to indicate that this operation is not supported then the code falls back to using clock_gettime(2) to calculate a relative time to wait for. I believe that I've added this functionality in a way that it doesn't break ABI compatibility, but that has made it more verbose and less type safe. I believe that it would be better to maintain the timeout as an instance of the correct clock type all the way down to a single _M_futex_wait_until function with an overload for each clock. The current scheme of separating out the seconds and nanoseconds early risks accidentally calling the wait function for the wrong clock. Unfortunately, doing this would break code that compiled against the old header. * libstdc++-v3/config/abi/pre/gnu.ver: Update for addition of __atomic_futex_unsigned_base::_M_futex_wait_until_steady. * libstdc++-v3/include/bits/atomic_futex.h (__atomic_futex_unsigned_base): Add comments to clarify that _M_futex_wait_until _M_load_and_test_until use CLOCK_REALTIME. Declare new _M_futex_wait_until_steady and _M_load_and_text_until_steady methods that use CLOCK_MONOTONIC. Add _M_load_and_test_until_impl and _M_load_when_equal_until overloads that accept a steady_clock time_point and use these new methods. * libstdc++-v3/src/c++11/futex.cc: Include headers required for clock_gettime. Add futex_clock_monotonic_flag constant to tell futex to use CLOCK_MONOTONIC to match the existing futex_clock_realtime_flag. Add futex_clock_monotonic_unavailable to store the result of trying to use CLOCK_MONOTONIC. (__atomic_futex_unsigned_base::_M_futex_wait_until_steady): Add new variant of _M_futex_wait_until that uses CLOCK_MONOTONIC to support waiting using steady_clock. --- libstdc++-v3/config/abi/pre/gnu.ver | 10 +-- libstdc++-v3/include/bits/atomic_futex.h | 67 +++++++++++++++++++- libstdc++-v3/src/c++11/futex.cc | 82 +++++++++++++++++++++++++- 3 files changed, 154 insertions(+), 5 deletions(-) diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index e61fbe0..26492bc 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -1916,10 +1916,9 @@ GLIBCXX_3.4.21 { _ZNSt7codecvtID[is]c*; _ZT[ISV]St7codecvtID[is]c*E; - extern "C++" - { - std::__atomic_futex_unsigned_base*; - }; + # std::__atomic_futex_unsigned_base members + _ZNSt28__atomic_futex_unsigned_base19_M_futex_notify_all*; + _ZNSt28__atomic_futex_unsigned_base19_M_futex_wait_until*; # codecvt_utf8 etc. _ZNKSt19__codecvt_utf8_base*; @@ -2291,6 +2290,9 @@ GLIBCXX_3.4.28 { _ZNSt12__shared_ptrINSt10filesystem28recursive_directory_iterator10_Dir_stackELN9__gnu_cxx12_Lock_policyE[012]EEC2EOS5_; _ZNSt12__shared_ptrINSt10filesystem7__cxx1128recursive_directory_iterator10_Dir_stackELN9__gnu_cxx12_Lock_policyE[012]EEC2EOS6_; + # std::__atomic_futex_unsigned_base::_M_futex_wait_until_steady + _ZNSt28__atomic_futex_unsigned_base26_M_futex_wait_until_steady*; + } GLIBCXX_3.4.27; # Symbols in the support library (libsupc++) have their own tag. diff --git a/libstdc++-v3/include/bits/atomic_futex.h b/libstdc++-v3/include/bits/atomic_futex.h index 36fda38..6d28d28 100644 --- a/libstdc++-v3/include/bits/atomic_futex.h +++ b/libstdc++-v3/include/bits/atomic_futex.h @@ -52,11 +52,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if defined(_GLIBCXX_HAVE_LINUX_FUTEX) && ATOMIC_INT_LOCK_FREE > 1 struct __atomic_futex_unsigned_base { - // Returns false iff a timeout occurred. + // __s and __ns are measured against CLOCK_REALTIME. Returns false + // iff a timeout occurred. bool _M_futex_wait_until(unsigned *__addr, unsigned __val, bool __has_timeout, chrono::seconds __s, chrono::nanoseconds __ns); + // __s and __ns are measured against CLOCK_MONOTONIC. Returns + // false iff a timeout occurred. + bool + _M_futex_wait_until_steady(unsigned *__addr, unsigned __val, + bool __has_timeout, chrono::seconds __s, chrono::nanoseconds __ns); + // This can be executed after the object has been destroyed. static void _M_futex_notify_all(unsigned* __addr); }; @@ -86,6 +93,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // value if equal is false. // The assumed value is the caller's assumption about the current value // when making the call. + // __s and __ns are measured against CLOCK_REALTIME. unsigned _M_load_and_test_until(unsigned __assumed, unsigned __operand, bool __equal, memory_order __mo, bool __has_timeout, @@ -110,6 +118,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } + // If a timeout occurs, returns a current value after the timeout; + // otherwise, returns the operand's value if equal is true or a different + // value if equal is false. + // The assumed value is the caller's assumption about the current value + // when making the call. + // __s and __ns are measured against CLOCK_MONOTONIC. + unsigned + _M_load_and_test_until_steady(unsigned __assumed, unsigned __operand, + bool __equal, memory_order __mo, bool __has_timeout, + chrono::seconds __s, chrono::nanoseconds __ns) + { + for (;;) + { + // Don't bother checking the value again because we expect the caller + // to have done it recently. + // memory_order_relaxed is sufficient because we can rely on just the + // modification order (store_notify uses an atomic RMW operation too), + // and the futex syscalls synchronize between themselves. + _M_data.fetch_or(_Waiter_bit, memory_order_relaxed); + bool __ret = _M_futex_wait_until_steady((unsigned*)(void*)&_M_data, + __assumed | _Waiter_bit, + __has_timeout, __s, __ns); + // Fetch the current value after waiting (clears _Waiter_bit). + __assumed = _M_load(__mo); + if (!__ret || ((__operand == __assumed) == __equal)) + return __assumed; + // TODO adapt wait time + } + } + // Returns the operand's value if equal is true or a different value if // equal is false. // The assumed value is the caller's assumption about the current value @@ -140,6 +178,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION true, __s.time_since_epoch(), __ns); } + template + unsigned + _M_load_and_test_until_impl(unsigned __assumed, unsigned __operand, + bool __equal, memory_order __mo, + const chrono::time_point& __atime) + { + auto __s = chrono::time_point_cast(__atime); + auto __ns = chrono::duration_cast(__atime - __s); + // XXX correct? + return _M_load_and_test_until_steady(__assumed, __operand, __equal, __mo, + true, __s.time_since_epoch(), __ns); + } + public: _GLIBCXX_ALWAYS_INLINE unsigned @@ -200,6 +251,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return (__i & ~_Waiter_bit) == __val; } + // Returns false iff a timeout occurred. + template + _GLIBCXX_ALWAYS_INLINE bool + _M_load_when_equal_until(unsigned __val, memory_order __mo, + const chrono::time_point& __atime) + { + unsigned __i = _M_load(__mo); + if ((__i & ~_Waiter_bit) == __val) + return true; + // TODO Spin-wait first. Ignore effect on timeout. + __i = _M_load_and_test_until_impl(__i, __val, true, __mo, __atime); + return (__i & ~_Waiter_bit) == __val; + } + _GLIBCXX_ALWAYS_INLINE void _M_store_notify_all(unsigned __val, memory_order __mo) { diff --git a/libstdc++-v3/src/c++11/futex.cc b/libstdc++-v3/src/c++11/futex.cc index 38ae448..1df84bb 100644 --- a/libstdc++-v3/src/c++11/futex.cc +++ b/libstdc++-v3/src/c++11/futex.cc @@ -33,9 +33,15 @@ #include #include +#ifdef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL +#include +#include +#endif + // Constants for the wait/wake futex syscall operations const unsigned futex_wait_op = 0; const unsigned futex_wait_bitset_op = 9; +const unsigned futex_clock_monotonic_flag = 0; const unsigned futex_clock_realtime_flag = 256; const unsigned futex_bitset_match_any = ~0; const unsigned futex_wake_op = 1; @@ -43,6 +49,7 @@ const unsigned futex_wake_op = 1; namespace { std::atomic futex_clock_realtime_unavailable; + std::atomic futex_clock_monotonic_unavailable; } namespace std _GLIBCXX_VISIBILITY(default) @@ -121,6 +128,81 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } + bool + __atomic_futex_unsigned_base::_M_futex_wait_until_steady(unsigned *__addr, + unsigned __val, + bool __has_timeout, chrono::seconds __s, chrono::nanoseconds __ns) + { + if (!__has_timeout) + { + // Ignore whether we actually succeeded to block because at worst, + // we will fall back to spin-waiting. The only thing we could do + // here on errors is abort. + int ret __attribute__((unused)); + ret = syscall (SYS_futex, __addr, futex_wait_op, __val, nullptr); + __glibcxx_assert(ret == 0 || errno == EINTR || errno == EAGAIN); + return true; + } + else + { + if (!futex_clock_monotonic_unavailable.load(std::memory_order_relaxed)) + { + struct timespec rt; + rt.tv_sec = __s.count(); + rt.tv_nsec = __ns.count(); + + if (syscall (SYS_futex, __addr, + futex_wait_bitset_op | futex_clock_monotonic_flag, + __val, &rt, nullptr, futex_bitset_match_any) == -1) + { + __glibcxx_assert(errno == EINTR || errno == EAGAIN + || errno == ETIMEDOUT || errno == ENOSYS); + if (errno == ETIMEDOUT) + return false; + else if (errno == ENOSYS) + { + futex_clock_monotonic_unavailable.store(true, + std::memory_order_relaxed); + // Fall through to legacy implementation if the system + // call is unavailable. + } + else + return true; + } + } + + // We only get to here if futex_clock_monotonic_unavailable was + // true or has just been set to true. + struct timespec ts; +#ifdef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL + syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts); +#else + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif + // Convert the absolute timeout value to a relative timeout + struct timespec rt; + rt.tv_sec = __s.count() - ts.tv_sec; + rt.tv_nsec = __ns.count() - ts.tv_nsec; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + // Did we already time out? + if (rt.tv_sec < 0) + return false; + + if (syscall (SYS_futex, __addr, futex_wait_op, __val, &rt) == -1) + { + __glibcxx_assert(errno == EINTR || errno == EAGAIN + || errno == ETIMEDOUT); + if (errno == ETIMEDOUT) + return false; + } + return true; + } + } + void __atomic_futex_unsigned_base::_M_futex_notify_all(unsigned* __addr) { From patchwork Sun Oct 27 15:46:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Crowe X-Patchwork-Id: 1185041 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-511861-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=quarantine dis=none) header.from=mcrowe.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="F9K+clEL"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=mcrowe.com header.i=@mcrowe.com header.b="AMKo3ssy"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 471Mhn4s36z9sP4 for ; Mon, 28 Oct 2019 02:48:57 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; q=dns; s=default; b=FHw WJn5n38aLK37RjfQzbINAPedRq5aFr+rSXBm8gAqustP3QZk3BuAGn6iLyRq5TUC C/Pa2dMjD4uXfD6zPcm1d/dSgdyfdPRVSF92akKGUXb4Lu6VsyJHAzzxuGEl0Gb9 eZNP08O4kxAgqz5oKBj2H1+lEHMPd6d8YYSaCNoQ= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=default; bh=fEgnTfpe2 OlmHkx5KaRS6W4gS34=; b=F9K+clELgmhsYibh6gloKH6zzw6fRVvdWD0Zfm37+ mLUm1kkC1VTlr8Cs0WrMdsC4M5YN/CZQiSghQ8vkbu9vKmI5AUzdJcjIqMB+3ogA +4V1s34iJ2xjGsm59SoRZEABnXG1Uo/thB9c+bDmfXZWp7lgG/qCcYDyjfHGkRvV 4k= Received: (qmail 94629 invoked by alias); 27 Oct 2019 15:47:01 -0000 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 Received: (qmail 94460 invoked by uid 89); 27 Oct 2019 15:47:00 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.1 spammy=immune, HContent-Transfer-Encoding:8bit X-HELO: avasout06.plus.net Received: from avasout06.plus.net (HELO avasout06.plus.net) (212.159.14.18) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 27 Oct 2019 15:46:58 +0000 Received: from deneb ([80.229.24.9]) by smtp with ESMTP id Okkqi7yPUuVHWOkksiL2mw; Sun, 27 Oct 2019 15:46:58 +0000 X-Clacks-Overhead: "GNU Terry Pratchett" X-CM-Score: 0.00 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mcrowe.com; s=20191005; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description; bh=QfFtlGNf+dxQqZSk8UZNOMOAaBhuQKEAEA8KioaUUMU=; b=AMKo3 ssymdX0S4KhXgnMnstdrxZYYiig92Ip/+Ytm6r56HtmEM6NuWnk2oDXxbCh7g0kAutVp2i7fwUZNB vG2inOAaS6GChythv+NpDgIhE0PJqfWCL2s0GgJt3MMws6EIlMQw2AcKLP2i49PY6H+VOoUIMMP9R fDKfdOgRLK/6cu+R40LfF7Qd5ue/RUKuo318Xitu5jD7v5pB6Pfje0rB39RuI03x1j7cG4Z9ws9uR SE1wXFEFxQ7CkUjWV1OzjoK4x6qJllvyJy5PqA6tR6Q3DWJfQAC7tUV5efTSGCZJbS4uGHQ8hFEhm /or1Je80KsNWYn5PYspSQKzEUw2sQ==; Received: from mac by deneb with local (Exim 4.92) (envelope-from ) id 1iOkkh-0005R2-Kj; Sun, 27 Oct 2019 15:46:47 +0000 From: Mike Crowe To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Cc: Mike Crowe Subject: [PATCH v4 4/7] libstdc++ atomic_futex: Use std::chrono::steady_clock as reference clock Date: Sun, 27 Oct 2019 15:46:27 +0000 Message-Id: In-Reply-To: References: MIME-Version: 1.0 The user-visible effect of this change is that std::future::wait_for now uses std::chrono::steady_clock to determine the timeout. This makes it immune to changes made to the system clock. It also means that anyone using their own clock types with std::future::wait_until will have the timeout converted to std::chrono::steady_clock rather than std::chrono::system_clock. Now that use of both std::chrono::steady_clock and std::chrono::system_clock are correctly supported for the wait timeout, I believe that std::chrono::steady_clock is a better choice for the reference clock that all other clocks are converted to since it is guaranteed to advance steadily. The previous behaviour of converting to std::chrono::system_clock risks timeouts changing dramatically when the system clock is changed. * libstdc++-v3/include/bits/atomic_futex.h: (__atomic_futex_unsigned): Change __clock_t typedef to use steady_clock so that unknown clocks are synced to it rather than system_clock. Change existing __clock_t overloads of _M_load_and_text_until_impl and _M_load_when_equal_until to use system_clock explicitly. Remove comment about DR 887 since these changes address that problem as best as we currently able. --- libstdc++-v3/include/bits/atomic_futex.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libstdc++-v3/include/bits/atomic_futex.h b/libstdc++-v3/include/bits/atomic_futex.h index 6d28d28..387ee9d 100644 --- a/libstdc++-v3/include/bits/atomic_futex.h +++ b/libstdc++-v3/include/bits/atomic_futex.h @@ -71,7 +71,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template class __atomic_futex_unsigned : __atomic_futex_unsigned_base { - typedef chrono::system_clock __clock_t; + typedef chrono::steady_clock __clock_t; // This must be lock-free and at offset 0. atomic _M_data; @@ -169,7 +169,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION unsigned _M_load_and_test_until_impl(unsigned __assumed, unsigned __operand, bool __equal, memory_order __mo, - const chrono::time_point<__clock_t, _Dur>& __atime) + const chrono::time_point& __atime) { auto __s = chrono::time_point_cast(__atime); auto __ns = chrono::duration_cast(__atime - __s); @@ -229,7 +229,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_load_when_equal_until(unsigned __val, memory_order __mo, const chrono::time_point<_Clock, _Duration>& __atime) { - // DR 887 - Sync unknown clock to known clock. const typename _Clock::time_point __c_entry = _Clock::now(); const __clock_t::time_point __s_entry = __clock_t::now(); const auto __delta = __atime - __c_entry; @@ -241,7 +240,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template _GLIBCXX_ALWAYS_INLINE bool _M_load_when_equal_until(unsigned __val, memory_order __mo, - const chrono::time_point<__clock_t, _Duration>& __atime) + const chrono::time_point& __atime) { unsigned __i = _M_load(__mo); if ((__i & ~_Waiter_bit) == __val) From patchwork Sun Oct 27 15:46:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Crowe X-Patchwork-Id: 1185036 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-511858-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=quarantine dis=none) header.from=mcrowe.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="fvlULXfM"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=mcrowe.com header.i=@mcrowe.com header.b="V7UVLbhn"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 471Mfg2yMhz9sP4 for ; Mon, 28 Oct 2019 02:47:05 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; q=dns; s=default; b=YqB ZPzq4g93OmgeXyx/mqXFJaztxwTuROKsAFLd+kP9CIK8N2yfJlOTpsqCA6HnEl8k S5zGTigx/nSETMOt2QOUINuVu2qh8P1i1bUGJd5XMqo6VziU6Z2sPGMqLOHJUpwL hGlW3m0c+wlnl7rBH/mp25DGYGAV9oacXthJ/5M4= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=default; bh=vALODyzNk eyOJTig1a07Ft6lV3Q=; b=fvlULXfMTjhUd8AZ0pIE2TgvE+TUzal03fVNN+sBe 3zYvjS2URqxpCRpBQOMDKeaqqNmSqFigLphGUzz9GLVo/8ysWa4wLZyzDJLsXb8H wCmTYm5FhCbwma0rvbIshN1fHV+N401IGO/g/bb9X7GjRMJcwSsiWQmGcM++gp5Q OM= Received: (qmail 93914 invoked by alias); 27 Oct 2019 15:46:55 -0000 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 Received: (qmail 93888 invoked by uid 89); 27 Oct 2019 15:46:54 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.1 spammy=calculates, __val, elapsed, slightly X-HELO: avasout06.plus.net Received: from avasout06.plus.net (HELO avasout06.plus.net) (212.159.14.18) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 27 Oct 2019 15:46:53 +0000 Received: from deneb ([80.229.24.9]) by smtp with ESMTP id Okkji7yP3uVHWOkkliL2mn; Sun, 27 Oct 2019 15:46:51 +0000 X-Clacks-Overhead: "GNU Terry Pratchett" X-CM-Score: 0.00 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mcrowe.com; s=20191005; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description; bh=T0l8lyAnb56lzz+Oy3Q2GzQ2FlGTQFUnUTaMpqeMdzY=; b=V7UVL bhn2/ZyTrKYnlwyzXRD1ltgYtNAVT66oh6N3EAVARBrHp9obUGvEOfkV+dC2nM0U0JZQx0nWBRcWr GDBeSMOTAl66X+s8dBThzBom8wnL131s6w5B2Yl5qKu6xaogYwlj26rtoLGsSti9bI9k87oBaDHTI x8OrOSTiqZe6juZq2wicaUDsIfqZKLNoR/m9D3XiwZ7bREtISoWwYa97hEWtoQpt03qVKApek5+pa AjTPMH6KrLx5eHWpjHQpECB2rMukxjNuXxYmI7wIiclhXPLA+vi4LF1sI/sJzh40aGFdw3Z4sspi1 m0C4pqecu2HrKioZMeICASZvd4e5w==; Received: from mac by deneb with local (Exim 4.92) (envelope-from ) id 1iOkki-0005Rd-B6; Sun, 27 Oct 2019 15:46:48 +0000 From: Mike Crowe To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Cc: Mike Crowe Subject: [PATCH v4 5/7] libstdc++ futex: Loop when waiting against arbitrary clock Date: Sun, 27 Oct 2019 15:46:28 +0000 Message-Id: In-Reply-To: References: MIME-Version: 1.0 If std::future::wait_until is passed a time point measured against a clock that is neither std::chrono::steady_clock nor std::chrono::system_clock then the generic implementation of __atomic_futex_unsigned::_M_load_when_equal_until is called which calculates the timeout based on __clock_t and calls the _M_load_when_equal_until method for that clock to perform the actual wait. There's no guarantee that __clock_t is running at the same speed as the caller's clock, so if the underlying wait times out timeout we need to check the timeout against the caller's clock again before potentially looping. Also add two extra tests to the testsuite's async.cc: * run test03 with steady_clock_copy, which behaves identically to std::chrono::steady_clock, but isn't std::chrono::steady_clock. This causes the overload of __atomic_futex_unsigned::_M_load_when_equal_until that takes an arbitrary clock to be called. * invent test04 which uses a deliberately slow running clock in order to exercise the looping behaviour o __atomic_futex_unsigned::_M_load_when_equal_until described above. * libstdc++-v3/include/bits/atomic_futex.h: (__atomic_futex_unsigned) Add loop to _M_load_when_equal_until on generic _Clock to check the timeout against _Clock again after _M_load_when_equal_until returns indicating a timeout. * libstdc++-v3/testsuite/30_threads/async/async.cc: Invent slow_clock that runs at an eleventh of steady_clock's speed. Use it to test the user-supplied-clock variant of __atomic_futex_unsigned::_M_load_when_equal_until works generally with test03 and loops correctly when the timeout time hasn't been reached in test04. --- libstdc++-v3/include/bits/atomic_futex.h | 15 +++-- libstdc++-v3/testsuite/30_threads/async/async.cc | 52 +++++++++++++++++- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/libstdc++-v3/include/bits/atomic_futex.h b/libstdc++-v3/include/bits/atomic_futex.h index 387ee9d..b04e806 100644 --- a/libstdc++-v3/include/bits/atomic_futex.h +++ b/libstdc++-v3/include/bits/atomic_futex.h @@ -229,11 +229,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_load_when_equal_until(unsigned __val, memory_order __mo, const chrono::time_point<_Clock, _Duration>& __atime) { - const typename _Clock::time_point __c_entry = _Clock::now(); - const __clock_t::time_point __s_entry = __clock_t::now(); - const auto __delta = __atime - __c_entry; - const auto __s_atime = __s_entry + __delta; - return _M_load_when_equal_until(__val, __mo, __s_atime); + typename _Clock::time_point __c_entry = _Clock::now(); + do { + const __clock_t::time_point __s_entry = __clock_t::now(); + const auto __delta = __atime - __c_entry; + const auto __s_atime = __s_entry + __delta; + if (_M_load_when_equal_until(__val, __mo, __s_atime)) + return true; + __c_entry = _Clock::now(); + } while (__c_entry < __atime); + return false; } // Returns false iff a timeout occurred. diff --git a/libstdc++-v3/testsuite/30_threads/async/async.cc b/libstdc++-v3/testsuite/30_threads/async/async.cc index 1b6e2ff..7700913 100644 --- a/libstdc++-v3/testsuite/30_threads/async/async.cc +++ b/libstdc++-v3/testsuite/30_threads/async/async.cc @@ -90,11 +90,63 @@ void test03() VERIFY( elapsed < std::chrono::seconds(5) ); } +// This clock is supposed to run at a tenth of normal speed, but we +// don't have to worry about rounding errors causing us to wake up +// slightly too early below if we actually run it at an eleventh of +// normal speed. It is used to exercise the +// __atomic_futex_unsigned::_M_load_when_equal_until overload that +// takes an arbitrary clock. +struct slow_clock +{ + using rep = std::chrono::steady_clock::rep; + using period = std::chrono::steady_clock::period; + using duration = std::chrono::steady_clock::duration; + using time_point = std::chrono::time_point; + static constexpr bool is_steady = true; + + static time_point now() + { + auto steady = std::chrono::steady_clock::now(); + return time_point{steady.time_since_epoch() / 11}; + } +}; + +void test04() +{ + using namespace std::chrono; + + auto const slow_start = slow_clock::now(); + future f1 = async(launch::async, []() { + std::this_thread::sleep_for(std::chrono::seconds(2)); + }); + + // Wait for ~1s + { + auto const steady_begin = steady_clock::now(); + auto const status = f1.wait_until(slow_start + milliseconds(100)); + VERIFY(status == std::future_status::timeout); + auto const elapsed = steady_clock::now() - steady_begin; + VERIFY(elapsed >= seconds(1)); + VERIFY(elapsed < seconds(2)); + } + + // Wait for up to ~2s more + { + auto const steady_begin = steady_clock::now(); + auto const status = f1.wait_until(slow_start + milliseconds(300)); + VERIFY(status == std::future_status::ready); + auto const elapsed = steady_clock::now() - steady_begin; + VERIFY(elapsed < seconds(2)); + } +} + int main() { test01(); test02(); test03(); test03(); + test03(); + test04(); return 0; } From patchwork Sun Oct 27 15:46:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Crowe X-Patchwork-Id: 1185040 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-511863-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=quarantine dis=none) header.from=mcrowe.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="iJiWkBau"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=mcrowe.com header.i=@mcrowe.com header.b="fP42l9Ei"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 471Mgs1dQgz9sP4 for ; Mon, 28 Oct 2019 02:48:09 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; q=dns; s=default; b=Oks TmlGSLajxNaffremdC6ScJTYgmtzzBfRekatZ5iyiERgx1+qexOB3qcbv3Z0wE4+ ruBX9CEjYR2F+j36gjs3RRsJiHGdw1dv8UPP6aYtQ1YT4ajCznqfCX5qV8L36Oab /l7kgcSVyBFuiFl+SnTXV8wEhu0K20ix6awN+0PY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=default; bh=kTERUmyPi mAwhvOG/VQ+sHb95To=; b=iJiWkBauD4D1tjNaNtJ3YjCd8NNuumDqnU+3iLndG FgpQ6FEJ+DS4nnuz7dtsnaNjyiH+QfdRfmDFsuqL8JEd87I8VQA5nEiQNMX9Kt+z wmgwiDdp/6Nxb+mbGz2imUdwra6NkTmt5c7lG8CyYMPU7BfAmzFQo97GcQ09BLRT iI= Received: (qmail 95220 invoked by alias); 27 Oct 2019 15:47:05 -0000 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 Received: (qmail 94861 invoked by uid 89); 27 Oct 2019 15:47:03 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.1 spammy=HContent-Transfer-Encoding:8bit X-HELO: avasout03.plus.net Received: from avasout03.plus.net (HELO avasout03.plus.net) (84.93.230.244) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 27 Oct 2019 15:47:01 +0000 Received: from deneb ([80.229.24.9]) by smtp with ESMTP id OkksieIV2tvkXOkktihKUW; Sun, 27 Oct 2019 15:47:01 +0000 X-Clacks-Overhead: "GNU Terry Pratchett" X-CM-Score: 0.00 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mcrowe.com; s=20191005; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description; bh=1PTNeSSS2eOF6Ak8dV6pcorEQPVc7QlncluikHNv6Sw=; b=fP42l 9EiwblPIsuFqVAAJKCIgCP1H9gUtkiT8svyZGkfdf9DgPV6NzB7nUiq1QmtbbvOg/MQwB22Eqp6Cv fcvJRVf8Cs7j/mgbMNKL08LX/tpI/KgQeevlqjCRflI+HSwM2GXEXccs9Hjlj2wnPoKwgX4jKfHGO oG74q/Cl5I+fP3VrFuWYvXkdx/7bPJLkGfB7rbRAuHGK7bhgbRz2sqG2EModgExfsonQB/ml3tjGc u/o/x0zuKugWk5aBZa8hijEBu9FUxZlJjnBOg+xEicsVAxoF+ppunELXUjmn9HPGtl4+j8thuH2FN R02s7ZBxMYhym576pJm9ChhwISaRA==; Received: from mac by deneb with local (Exim 4.92) (envelope-from ) id 1iOkkj-0005SV-23; Sun, 27 Oct 2019 15:46:49 +0000 From: Mike Crowe To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Cc: Mike Crowe Subject: [PATCH v4 6/7] libstdc++ atomic_futex: Avoid rounding errors in std::future::wait_for Date: Sun, 27 Oct 2019 15:46:29 +0000 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Convert the specified duration to the target clock's duration type before adding it to the current time. This avoids the situation described in PR libstdc++/68519 when the specified duration type lacks sufficient precision. * libstdc++-v3/include/bits/atomic_futex.h: (__atomic_futex_unsigned::_M_load_when_equal_for): Round up timeout if required after conversion to reference clock duration. * libstdc++-v3/testsuite/30_threads/async/async.cc: (test_pr68519): New test for the equivalent of PR libstdc++/68519. --- libstdc++-v3/include/bits/atomic_futex.h | 6 +++++- libstdc++-v3/testsuite/30_threads/async/async.cc | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/libstdc++-v3/include/bits/atomic_futex.h b/libstdc++-v3/include/bits/atomic_futex.h index b04e806..ec823eb 100644 --- a/libstdc++-v3/include/bits/atomic_futex.h +++ b/libstdc++-v3/include/bits/atomic_futex.h @@ -219,8 +219,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_load_when_equal_for(unsigned __val, memory_order __mo, const chrono::duration<_Rep, _Period>& __rtime) { + using __dur = typename __clock_t::duration; + auto __reltime = chrono::duration_cast<__dur>(__rtime); + if (__reltime < __rtime) + ++__reltime; return _M_load_when_equal_until(__val, __mo, - __clock_t::now() + __rtime); + __clock_t::now() + __reltime); } // Returns false iff a timeout occurred. diff --git a/libstdc++-v3/testsuite/30_threads/async/async.cc b/libstdc++-v3/testsuite/30_threads/async/async.cc index 7700913..ddd007d 100644 --- a/libstdc++-v3/testsuite/30_threads/async/async.cc +++ b/libstdc++-v3/testsuite/30_threads/async/async.cc @@ -140,6 +140,20 @@ void test04() } } +void test_pr68519() +{ + future f1 = async(launch::async, []() { + std::this_thread::sleep_for(std::chrono::seconds(1)); + }); + + std::chrono::duration const wait_time = std::chrono::seconds(1); + auto const start_steady = chrono::steady_clock::now(); + auto status = f1.wait_for(wait_time); + auto const elapsed_steady = chrono::steady_clock::now() - start_steady; + + VERIFY( elapsed_steady >= std::chrono::seconds(1) ); +} + int main() { test01(); @@ -148,5 +162,6 @@ int main() test03(); test03(); test04(); + test_pr68519(); return 0; } From patchwork Sun Oct 27 15:46:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Crowe X-Patchwork-Id: 1185038 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-511860-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=quarantine dis=none) header.from=mcrowe.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="TARkFZln"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=mcrowe.com header.i=@mcrowe.com header.b="T7Ze+GdB"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 471MgV2l1Fz9sPV for ; Mon, 28 Oct 2019 02:47:50 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; q=dns; s=default; b=Snt JE7R33IaoAVAM3QPssmfX9v4f8vCv0Vub8StSXVmx1pFvg3v+tJylxiGew6Rf6aj fZqHsqAIwwb3EiVgPC0MzHQEg4rCxoWV8omlm0njb/b/gFq+2Dd9sw9gOV+1FfRk dJX5dzaC1jmJrnnxXxMw3CZm9oAP9LLQiAHEHwLY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=default; bh=SM0DWUH0K afeAMB0tR2nPM6NAk0=; b=TARkFZlnDNmjHOmouKKKQb/3xYrdCTby46XbCKIbz hzHwgufEwdp+2M/cU1dDddfAn/JVcdSg/kc5oR3clidld90KebO+DEbGyLLUGDN2 jt54kaOEarQUWPs1Ew6rwaoUyVOsjb4YN0b4fc9622SCaVrEfVvo4AsDlDg1M0dK dA= Received: (qmail 94488 invoked by alias); 27 Oct 2019 15:47:00 -0000 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 Received: (qmail 94316 invoked by uid 89); 27 Oct 2019 15:46:59 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.1 spammy=commits, forth, HContent-Transfer-Encoding:8bit X-HELO: avasout03.plus.net Received: from avasout03.plus.net (HELO avasout03.plus.net) (84.93.230.244) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 27 Oct 2019 15:46:57 +0000 Received: from deneb ([80.229.24.9]) by smtp with ESMTP id OkklieIUetvkXOkkmihKUL; Sun, 27 Oct 2019 15:46:55 +0000 X-Clacks-Overhead: "GNU Terry Pratchett" X-CM-Score: 0.00 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mcrowe.com; s=20191005; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description; bh=zQV59MYCU4autYAbxoH20Ky4uFJw7V7af6vLgC27gIw=; b=T7Ze+ GdBYv1LrMkXHMZ3y7lmvmoN5tPEeubvDR6YLj61ngthq5lnWuEoQDeG90NuJJq+66GXP8+HAdpUxk wcvcWa9yiu++a5AVgO72NJwTOfwT1hxKovg0k18O8upVmRYIZIEE74hOw2NqwBZmpcP7tibf9Y89s o/BhiwKY6DnDHP2/fPdSBeQA0d4Cu9PLu8PS2gdeOz39YCsqGr2YFddpbJuV4jSSy/wrf0xUd+90D pDyxfg/Hjvu86RHg+0B1dUe0wiAV1dVYxZVWnLrIABWkdx7lnv3ULpklMBgAsCM/WdAc3zRwaZBFq efxi04pKts4E/IiE7odIrUdabUQZA==; Received: from mac by deneb with local (Exim 4.92) (envelope-from ) id 1iOkkj-0005T9-Rn; Sun, 27 Oct 2019 15:46:49 +0000 From: Mike Crowe To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Cc: Mike Crowe Subject: [PATCH v4 7/7] libstdc++: Extra async tests, not for merging Date: Sun, 27 Oct 2019 15:46:30 +0000 Message-Id: <0c16c36d653cba3bd50af231c37f9f2ce29ca676.1572191159.git-series.mac@mcrowe.com> In-Reply-To: References: MIME-Version: 1.0 These tests show that changing the system clock has an effect on std::future::wait_until when using std::chrono::system_clock but not when using std::chrono::steady_clock. Unfortunately these tests have a number of downsides: 1. Nothing that is attempting to keep the clock set correctly (ntpd, systemd-timesyncd) can be running at the same time. 2. The test process requires the CAP_SYS_TIME capability (although, as it's written it checks for being root.) 3. Other processes running concurrently may misbehave when the clock darts back and forth. 4. They are slow to run. As such, I don't think they are suitable for merging. I include them here because I wanted to document how I had tested the changes in the previous commits. --- libstdc++-v3/testsuite/30_threads/async/async.cc | 70 +++++++++++++++++- 1 file changed, 70 insertions(+) diff --git a/libstdc++-v3/testsuite/30_threads/async/async.cc b/libstdc++-v3/testsuite/30_threads/async/async.cc index ddd007d..979f5b4 100644 --- a/libstdc++-v3/testsuite/30_threads/async/async.cc +++ b/libstdc++-v3/testsuite/30_threads/async/async.cc @@ -24,6 +24,7 @@ #include #include +#include using namespace std; @@ -154,6 +155,71 @@ void test_pr68519() VERIFY( elapsed_steady >= std::chrono::seconds(1) ); } +void perturb_system_clock(const std::chrono::seconds &seconds) +{ + struct timeval tv; + if (gettimeofday(&tv, NULL)) + abort(); + + tv.tv_sec += seconds.count(); + if (settimeofday(&tv, NULL)) + abort(); +} + +// Ensure that advancing CLOCK_REALTIME doesn't make any difference +// when we're waiting on std::chrono::steady_clock. +void test05() +{ + auto const start = chrono::steady_clock::now(); + future f1 = async(launch::async, []() { + std::this_thread::sleep_for(std::chrono::seconds(10)); + }); + + perturb_system_clock(chrono::seconds(20)); + + std::future_status status; + status = f1.wait_for(std::chrono::seconds(4)); + VERIFY( status == std::future_status::timeout ); + + status = f1.wait_until(start + std::chrono::seconds(6)); + VERIFY( status == std::future_status::timeout ); + + status = f1.wait_until(start + std::chrono::seconds(12)); + VERIFY( status == std::future_status::ready ); + + auto const elapsed = chrono::steady_clock::now() - start; + VERIFY( elapsed >= std::chrono::seconds(10) ); + VERIFY( elapsed < std::chrono::seconds(15) ); + + perturb_system_clock(chrono::seconds(-20)); +} + +// Ensure that advancing CLOCK_REALTIME does make a difference when +// we're waiting on std::chrono::system_clock. +void test06() +{ + auto const start = chrono::system_clock::now(); + auto const start_steady = chrono::steady_clock::now(); + + future f1 = async(launch::async, []() { + std::this_thread::sleep_for(std::chrono::seconds(5)); + perturb_system_clock(chrono::seconds(60)); + std::this_thread::sleep_for(std::chrono::seconds(5)); + }); + future_status status; + status = f1.wait_until(start + std::chrono::seconds(60)); + VERIFY( status == std::future_status::timeout ); + + auto const elapsed_steady = chrono::steady_clock::now() - start_steady; + VERIFY( elapsed_steady >= std::chrono::seconds(5) ); + VERIFY( elapsed_steady < std::chrono::seconds(10) ); + + status = f1.wait_until(start + std::chrono::seconds(75)); + VERIFY( status == std::future_status::ready ); + + perturb_system_clock(chrono::seconds(-60)); +} + int main() { test01(); @@ -163,5 +229,9 @@ int main() test03(); test04(); test_pr68519(); + if (geteuid() == 0) { + test05(); + test06(); + } return 0; }