public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Mike Crowe <mac@mcrowe.com>
To: libstdc++@gcc.gnu.org,	gcc-patches@gcc.gnu.org
Cc: Mike Crowe <mac@mcrowe.com>
Subject: [PATCH 11/11] shared_mutex: Fix try_lock_until and try_lock_shared_until on arbitrary clock
Date: Sat, 28 Sep 2019 08:48:00 -0000	[thread overview]
Message-ID: <45929ebf94945c38491438f3fbe3a94f5e10999f.1569660153.git-series.mac@mcrowe.com> (raw)
In-Reply-To: <cover.401206917148c9c806e008aa7336564a639de964.1569660153.git-series.mac@mcrowe.com>

This is the equivalent to PR libstdc++/91906, but for shared_mutex.

A non-standard clock may tick more slowly than std::chrono::steady_clock.
This means that we risk returning false early when the specified timeout
may not have expired. This can be avoided by looping until the timeout time
as reported by the non-standard clock has been reached.

Unfortunately, we have no way to tell whether the non-standard clock ticks
more quickly that std::chrono::steady_clock. If it does then we risk
returning later than would be expected, but that is unavoidable without
waking up periodically to check, which would be rather too expensive.

	* include/std/shared_mutex (try_lock_until, try_lock_shared_until):
	Loop until the absolute timeout time is reached as measured against
	the appropriate clock.  *
	testsuite/30_threads/shared_mutex/try_lock_until/1.cc: New
	file. Test shared_mutex::try_lock_until and
	shared_mutex::try_lock_shared_until timeouts against various
	clocks.
---
 libstdc++-v3/include/std/shared_mutex                              | 28 ++++++++++++++++++-----
 libstdc++-v3/testsuite/30_threads/shared_mutex/try_lock_until/1.cc | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 6 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/30_threads/shared_mutex/try_lock_until/1.cc

diff --git a/libstdc++-v3/include/std/shared_mutex b/libstdc++-v3/include/std/shared_mutex
index 6e67324..40d45a1 100644
--- a/libstdc++-v3/include/std/shared_mutex
+++ b/libstdc++-v3/include/std/shared_mutex
@@ -554,9 +554,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       bool
       try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
       {
-        typename _Clock::time_point __now = _Clock::now();
-        auto __rtime = __atime - __now;
-        return try_lock_for(__rtime);
+        // The user-supplied clock may not tick at the same rate as
+        // steady_clock, so we must loop in order to guarantee that
+        // the timeout has expired before returning false.
+	typename _Clock::time_point __now = _Clock::now();
+        while (__atime > __now) {
+          auto __rtime = __atime - __now;
+          if (try_lock_for(__rtime))
+            return true;
+          __now = _Clock::now();
+        }
+        return false;
       }
 
     // Shared ownership
@@ -631,9 +639,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       try_lock_shared_until(const chrono::time_point<_Clock,
 						     _Duration>& __atime)
       {
-        typename _Clock::time_point __now = _Clock::now();
-        auto __rtime = __atime - __now;
-        return try_lock_shared_for(__rtime);
+        // The user-supplied clock may not tick at the same rate as
+        // steady_clock, so we must loop in order to guarantee that
+        // the timeout has expired before returning false.
+	typename _Clock::time_point __now = _Clock::now();
+        while (__atime > __now) {
+          auto __rtime = __atime - __now;
+          if (try_lock_shared_for(__rtime))
+            return true;
+          __now = _Clock::now();
+        }
+        return false;
       }
 
 #else // ! (_GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK)
diff --git a/libstdc++-v3/testsuite/30_threads/shared_mutex/try_lock_until/1.cc b/libstdc++-v3/testsuite/30_threads/shared_mutex/try_lock_until/1.cc
new file mode 100644
index 0000000..77baad9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/shared_mutex/try_lock_until/1.cc
@@ -0,0 +1,87 @@
+// { dg-do run }
+// { dg-options "-pthread"  }
+// { dg-require-effective-target c++14 }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2013-2019 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
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+
+#include <shared_mutex>
+#include <thread>
+#include <system_error>
+#include <testsuite_hooks.h>
+#include <slow_clock.h>
+
+template <typename clock_type>
+void test()
+{
+  typedef std::shared_timed_mutex mutex_type;
+
+  try
+    {
+      mutex_type m;
+      m.lock();
+      bool b;
+
+      std::thread t([&] {
+        try
+          {
+            using namespace std::chrono;
+            const auto timeout = 100ms;
+
+	    {
+	      const auto start = clock_type::now();
+	      const auto b = m.try_lock_until(start + timeout);
+	      const auto t = clock_type::now() - start;
+	      VERIFY( !b );
+	      VERIFY( t >= timeout );
+	    }
+
+	    {
+	      const auto start = clock_type::now();
+	      const auto b = m.try_lock_shared_until(start + timeout);
+	      const auto t = clock_type::now() - start;
+	      VERIFY( !b );
+	      VERIFY( t >= timeout );
+	    }
+          }
+        catch (const std::system_error& e)
+          {
+            VERIFY( false );
+          }
+	});
+      t.join();
+      m.unlock();
+    }
+  catch (const std::system_error& e)
+    {
+      VERIFY( false );
+    }
+  catch (...)
+    {
+      VERIFY( false );
+    }
+}
+
+int main()
+{
+  test<std::chrono::system_clock>();
+  test<std::chrono::steady_clock>();
+  test<slow_clock>();
+}
-- 
git-series 0.9.1

  parent reply	other threads:[~2019-09-28  8:48 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-09-28  8:45 [PATCH 00/11] timed_mutex, shared_timed_mutex: Add full steady clock support Mike Crowe
2019-09-28  8:45 ` [PATCH 07/11] PR libstdc++/91906 Fix timed_mutex::try_lock_until on arbitrary clock Mike Crowe
2019-09-28  8:45 ` [PATCH 01/11] libstdc++ testsuite: Check return value from timed_mutex::try_lock_until Mike Crowe
2019-09-28  8:45 ` [PATCH 05/11] PR libstdc++/78237 Add full steady_clock support to timed_mutex Mike Crowe
2019-09-28  8:45 ` [PATCH 09/11] libstdc++ shared_mutex: Add full steady_clock support to shared_timed_mutex Mike Crowe
2019-09-28  8:45 ` [PATCH 03/11] libstdc++ testsuite: Also test timed_mutex with steady_clock Mike Crowe
2019-09-28  8:48 ` [PATCH 08/11] libstdc++ testsuite: Also test shared_timed_mutex " Mike Crowe
2019-09-28  8:48 ` [PATCH 02/11] libstdc++ testsuite: Add timed_mutex::try_lock_until test Mike Crowe
2019-09-28  8:48 ` Mike Crowe [this message]
2019-09-28  8:48 ` [PATCH 10/11] libstdc++ timed_mutex: Ensure that try_lock_for waits for long enough Mike Crowe
2019-09-28  8:48 ` [PATCH 06/11] libstdc++ testsuite: Move slow_clock to its own header Mike Crowe
2019-09-28  8:48 ` [PATCH 04/11] libstdc++ testsuite: Also test unique_lock::try_lock_until with steady_clock Mike Crowe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=45929ebf94945c38491438f3fbe3a94f5e10999f.1569660153.git-series.mac@mcrowe.com \
    --to=mac@mcrowe.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=libstdc++@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).