From patchwork Fri May 29 06:17:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Crowe X-Patchwork-Id: 1300423 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=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gcc.gnu.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=fcTezfSi; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49YDst4twbz9sSn for ; Fri, 29 May 2020 16:18:58 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 80241388C027; Fri, 29 May 2020 06:18:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 80241388C027 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1590733101; bh=+coNTCZZOvPgGGrqCJudDzuxGwzQCy+n8owM/4G7JyI=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=fcTezfSi8yRLpTICwRGYRU3Y6EoK2Fc3Va1h932cPvtd2U4ptVKZf01jlLB0hsjJZ 9iMizH8o2QZCqbF9wCZfortN9wYHnRELpcVE/byaQaXc0/44VApby4J21fJh5Oaopk NqevRKC1aYWlI359v+TPxXNKJLl4uE29m0c8i6rE= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from avasout07.plus.net (avasout07.plus.net [84.93.230.235]) by sourceware.org (Postfix) with ESMTPS id 3E3F1388C00E for ; Fri, 29 May 2020 06:18:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 3E3F1388C00E Received: from deneb ([80.229.24.9]) by smtp with ESMTP id eYLJj2a0Y0wwMeYLKj60DN; Fri, 29 May 2020 07:18:17 +0100 X-Clacks-Overhead: "GNU Terry Pratchett" X-CM-Score: 0.00 X-CNFS-Analysis: v=2.3 cv=b/4pHuOx c=1 sm=1 tr=0 a=E/9URZZQ5L3bK/voZ0g0HQ==:117 a=E/9URZZQ5L3bK/voZ0g0HQ==:17 a=sTwFKg_x9MkA:10 a=0Faq-oMWdgr7wUJnaP0A:9 Received: from mac by deneb with local (Exim 4.92) (envelope-from ) id 1jeYL2-00063h-Ja; Fri, 29 May 2020 07:17:52 +0100 To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH v5 2/8] libstdc++ futex: Use FUTEX_CLOCK_REALTIME for wait Date: Fri, 29 May 2020 07:17:28 +0100 Message-Id: <796560f571e7787a1bd0aa655bc25b873e2d49b4.1590732962.git-series.mac@mcrowe.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: References: MIME-Version: 1.0 X-CMAE-Envelope: MS4wfIyAu5WvphuSlNvGvV2MTH0uBJuA3Sp+bNG0Xed3OoogHzOi/BexZLdPRcEu/33IhAuh2tRrkZnmu2WDDxwsM9shRUpiOk5nlftTwy9w0xiErND9Gv9m jXq44cKdrPBRm2mIxyXgfS85T3fsUU7IUtE= X-Spam-Status: No, score=-12.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=unavailable autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Mike Crowe via Gcc-patches From: Mike Crowe Reply-To: Mike Crowe Cc: Mike Crowe Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" 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 c9de11a..25b3e05 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