aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2018-10-11 17:37:23 +0100
committerJonathan Wakely <redi@gcc.gnu.org>2018-10-11 17:37:23 +0100
commitcfef4c324ac300c0ad120f0fcee376159de84a0c (patch)
tree9b0e03e36a75417b591a69a6f9f7405dbbc6f053
parent2045ae1d3f511717c2a1223148ce63f71800e1dd (diff)
downloadgcc-cfef4c324ac300c0ad120f0fcee376159de84a0c.zip
gcc-cfef4c324ac300c0ad120f0fcee376159de84a0c.tar.gz
gcc-cfef4c324ac300c0ad120f0fcee376159de84a0c.tar.bz2
PR libstdc++/80538 Only call sleep for non-zero values
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
-rw-r--r--libstdc++-v3/ChangeLog10
-rw-r--r--libstdc++-v3/src/c++11/thread.cc35
-rw-r--r--libstdc++-v3/testsuite/30_threads/this_thread/60421.cc15
3 files changed, 48 insertions, 12 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 1369896..b92fdf1 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -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
diff --git a/libstdc++-v3/src/c++11/thread.cc b/libstdc++-v3/src/c++11/thread.cc
index c62cb71..564eae6 100644
--- a/libstdc++-v3/src/c++11/thread.cc
+++ b/libstdc++-v3/src/c++11/thread.cc
@@ -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)
diff --git a/libstdc++-v3/testsuite/30_threads/this_thread/60421.cc b/libstdc++-v3/testsuite/30_threads/this_thread/60421.cc
index e7d69a4..cd8d2fd 100644
--- a/libstdc++-v3/testsuite/30_threads/this_thread/60421.cc
+++ b/libstdc++-v3/testsuite/30_threads/this_thread/60421.cc
@@ -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 );
}