Loop in std::this_thread sleep functions
authorJonathan Wakely <jwakely@redhat.com>
Wed, 11 Nov 2015 17:08:51 +0000 (17:08 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 11 Nov 2015 17:08:51 +0000 (17:08 +0000)
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.

From-SVN: r230183

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/thread
libstdc++-v3/src/c++11/thread.cc
libstdc++-v3/testsuite/30_threads/this_thread/60421.cc

index 3506c0e419d6c1bfecdfd26b2b3bd58c20f5ab9b..aba4f7e2612ab5eb12e0cb4201884b0fb741837c 100644 (file)
@@ -1,3 +1,12 @@
+2015-11-11  Jonathan Wakely  <jwakely@redhat.com>
+
+       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.
+
 2015-11-11  Ville Voutilainen  <ville.voutilainen@gmail.com>
 
        LWG 2510, make the default constructors of library tag types
index c67ec46123f112a85ed8408da619672f17a8b73e..5940e6e521f97627c9a8d948d433927d5f089ba6 100644 (file)
@@ -297,7 +297,8 @@ _GLIBCXX_END_NAMESPACE_VERSION
            static_cast<std::time_t>(__s.count()),
            static_cast<long>(__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
index e116afa0ccb5595336e99481bac769a11f397eb5..3407e80a0a3a0430608959e1e7b91f50c105e0b1 100644 (file)
@@ -221,7 +221,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        static_cast<std::time_t>(__s.count()),
        static_cast<long>(__ns.count())
       };
-    ::nanosleep(&__ts, 0);
+    while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
+      { }
 #elif defined(_GLIBCXX_HAVE_SLEEP)
 # ifdef _GLIBCXX_HAVE_USLEEP
     ::sleep(__s.count());
index ecc4deb4a0f7ebd3a83d01f32a30bce6860ef4f0..5dbf257ac58b446f15cb7ec0f2b1b6c3f90bbc92 100644 (file)
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { 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 <thread>
 #include <chrono>
+#include <atomic>
+#include <cstdint>
+#include <signal.h>
 #include <testsuite_hooks.h>
 
 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<uint64_t>::zero());
+  std::this_thread::sleep_for(std::chrono::duration<std::uint64_t>::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<bool> 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<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() / 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();
 }