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
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)
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 );
}