PR libstdc++/80538 Only call sleep for non-zero values
authorJonathan Wakely <jwakely@redhat.com>
Thu, 11 Oct 2018 16:37:23 +0000 (17:37 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Thu, 11 Oct 2018 16:37:23 +0000 (17:37 +0100)
Avoid a system call when no sleep is required. Sleep in a loop (actually
two loops) to handle interruption by signals.

PR libstdc++/80538
* src/c++11/thread.cc (this_thread::__sleep_for)
[_GLIBCXX_HAVE_SLEEP]: Only call sleep for non-zero values.
Loop while sleep call is interrupted and until steady_clock
shows requested duration has elapsed.
(!_GLIBCXX_HAVE_USLEEP]: Use the _GLIBCXX_HAVE_SLEEP code path, but
avoiding the usleep call.
* testsuite/30_threads/this_thread/60421.cc: Test repeated
signal interruptions.

From-SVN: r265044

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

index 136989619102c3e2803135554469914be0b43029..b92fdf14cacc59dd31f6532079ccca8c009583ee 100644 (file)
@@ -1,5 +1,15 @@
 2018-10-11  Jonathan Wakely  <jwakely@redhat.com>
 
+       PR libstdc++/80538
+       * src/c++11/thread.cc (this_thread::__sleep_for)
+       [_GLIBCXX_HAVE_SLEEP]: Only call sleep for non-zero values.
+       Loop while sleep call is interrupted and until steady_clock
+       shows requested duration has elapsed.
+       (!_GLIBCXX_HAVE_USLEEP]: Use the _GLIBCXX_HAVE_SLEEP code path, but
+       avoiding the usleep call.
+       * testsuite/30_threads/this_thread/60421.cc: Test repeated
+       signal interruptions.
+
        * include/bits/allocator.h
        (operator==(const allocator<_Tp>&, const allocator<_Tp>))
        (operator!=(const allocator<_Tp>&, const allocator<_Tp>)): Replace
index c62cb71bf990648debc3751ef6e2a548e1a4106a..564eae6f1663fa0ef88289d435889e0ac302d148 100644 (file)
@@ -194,18 +194,35 @@ namespace this_thread
     while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
       { }
 #elif defined(_GLIBCXX_HAVE_SLEEP)
-# ifdef _GLIBCXX_HAVE_USLEEP
-    ::sleep(__s.count());
-    if (__ns.count() > 0)
+    const auto target = chrono::steady_clock::now() + __s + __ns;
+    while (true)
       {
-        long __us = __ns.count() / 1000;
-        if (__us == 0)
-          __us = 1;
-        ::usleep(__us);
-      }
+       unsigned secs = __s.count();
+       if (__ns.count() > 0)
+         {
+# ifdef _GLIBCXX_HAVE_USLEEP
+           long us = __ns.count() / 1000;
+           if (us == 0)
+             us = 1;
+           ::usleep(us);
 # else
-    ::sleep(__s.count() + (__ns.count() >= 1000000));
+           if (__ns.count() > 1000000 || secs == 0)
+             ++secs; // No sub-second sleep function, so round up.
 # endif
+         }
+
+       if (secs > 0)
+         {
+           // Sleep in a loop to handle interruption by signals:
+           while ((secs = ::sleep(secs)))
+             { }
+         }
+       const auto now = chrono::steady_clock::now();
+       if (now >= target)
+         break;
+       __s = chrono::duration_cast<chrono::seconds>(target - now);
+       __ns = chrono::duration_cast<chrono::nanoseconds>(target - (now + __s));
+    }
 #elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
     unsigned long ms = __ns.count() / 1000000;
     if (__ns.count() > 0 && ms == 0)
index e7d69a49fb66be007ef19dd4fbe94771c2720041..cd8d2fdd6f387d4f4d1ffca0a727522f376b87d8 100644 (file)
@@ -53,10 +53,19 @@ test02()
     sleeping = true;
     std::this_thread::sleep_for(time);
     result = std::chrono::system_clock::now() >= (start + time);
+    sleeping = false;
   });
-  while (!sleeping) { }
-  std::this_thread::sleep_for(std::chrono::milliseconds(500));
-  pthread_kill(t.native_handle(), SIGUSR1);
+  while (!sleeping)
+  {
+    // Wait for the thread to start sleeping.
+  }
+  while (sleeping)
+  {
+    // The sleeping thread should finish eventually,
+    // even if continually interrupted after less than a second:
+    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+    pthread_kill(t.native_handle(), SIGUSR1);
+  }
   t.join();
   VERIFY( result );
 }