2019-12-02 Mike Crowe <mac@mcrowe.com>
+ PR libstdc++/91906 Fix timed_mutex::try_lock_until on arbitrary clock
+ * include/std/mutex (__timed_mutex_impl::_M_try_lock_until): Loop
+ until the absolute timeout time is reached as measured against the
+ appropriate clock.
+ * testsuite/util/slow_clock.h: New file. Move implementation of
+ slow_clock test class.
+ * testsuite/30_threads/condition_variable/members/2.cc: Include
+ slow_clock from header.
+ * testsuite/30_threads/shared_timed_mutex/try_lock/3.cc: Convert
+ existing test to templated function so that it can be called with
+ both system_clock and steady_clock.
+ * testsuite/30_threads/timed_mutex/try_lock_until/3.cc: Also run test
+ using slow_clock to test above fix.
+ * testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc:
+ Likewise.
+ * testsuite/30_threads/recursive_timed_mutex/try_lock_until/4.cc: Add
+ new test that try_lock_until behaves as try_lock if the timeout has
+ already expired or exactly matches the current time.
+
PR libstdc++/78237 Add full steady_clock support to timed_mutex
* acinclude.m4 (GLIBCXX_CHECK_PTHREAD_MUTEX_CLOCKLOCK): Define to
detect presence of pthread_mutex_clocklock function.
bool
_M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
{
- auto __rtime = __atime - _Clock::now();
- return _M_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.
+ auto __now = _Clock::now();
+ do {
+ auto __rtime = __atime - __now;
+ if (_M_try_lock_for(__rtime))
+ return true;
+ __now = _Clock::now();
+ } while (__atime > __now);
+ return false;
}
};
#include <condition_variable>
#include <system_error>
#include <testsuite_hooks.h>
+#include <slow_clock.h>
template <typename ClockType>
void test01()
}
}
-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<slow_clock, duration>;
- static constexpr bool is_steady = false;
-
- static time_point now()
- {
- auto real = std::chrono::system_clock::now();
- return time_point{real.time_since_epoch() / 3};
- }
-};
-
-
void test01_alternate_clock()
{
try
#include <thread>
#include <system_error>
#include <testsuite_hooks.h>
+#include <slow_clock.h>
template <typename clock_type>
void test()
{
test<std::chrono::system_clock>();
test<std::chrono::steady_clock>();
+ test<slow_clock>();
}
#include <system_error>
#include <testsuite_hooks.h>
-int main()
+template <typename clock_type>
+void test()
{
typedef std::shared_timed_mutex mutex_type;
{
using namespace std::chrono;
auto timeout = 100ms;
- auto start = system_clock::now();
+ auto start = clock_type::now();
b = m.try_lock_for(timeout);
- auto t = system_clock::now() - start;
+ auto t = clock_type::now() - start;
VERIFY( !b );
VERIFY( t >= timeout );
- start = system_clock::now();
+ start = clock_type::now();
b = m.try_lock_until(start + timeout);
- t = system_clock::now() - start;
+ t = clock_type::now() - start;
VERIFY( !b );
VERIFY( t >= timeout );
}
VERIFY( false );
}
}
+
+int main()
+{
+ test<std::chrono::system_clock>();
+ test<std::chrono::steady_clock>();
+}
#include <thread>
#include <system_error>
#include <testsuite_hooks.h>
+#include <slow_clock.h>
template <typename clock_type>
void test()
{
test<std::chrono::system_clock>();
test<std::chrono::steady_clock>();
+ test<slow_clock>();
}
--- /dev/null
+// { dg-do run }
+// { dg-options "-pthread" }
+// { dg-require-effective-target c++14 }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 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 <mutex>
+#include <thread>
+#include <system_error>
+#include <testsuite_hooks.h>
+#include <slow_clock.h>
+
+template <typename clock_type>
+void test()
+{
+ typedef std::timed_mutex mutex_type;
+
+ try
+ {
+ using namespace std::chrono;
+ mutex_type m;
+
+ // Confirm that try_lock_until acts like try_lock if the timeout has
+ // already passed.
+
+ // First test with a timeout that is definitely in the past.
+ VERIFY( m.try_lock_until( clock_type::now() - 1s ) );
+ m.unlock();
+
+ // Then attempt to test with a timeout that might exactly match the
+ // current time.
+ VERIFY( m.try_lock_until( clock_type::now() ) );
+ 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>();
+}
--- /dev/null
+// -*- C++ -*-
+
+// Copyright (C) 2019 Free Software Foundation, Inc.
+
+// 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/>.
+
+
+// A clock that ticks at a third of the speed of system_clock that can be used
+// to ensure that functions with timeouts don't erroneously return early.
+
+#include <chrono>
+
+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<slow_clock, duration>;
+ static constexpr bool is_steady = false;
+
+ static time_point now()
+ {
+ auto real = std::chrono::system_clock::now();
+ return time_point{real.time_since_epoch() / 3};
+ }
+};