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
This commit is contained in:
Jonathan Wakely 2018-10-11 17:37:23 +01:00 committed by Jonathan Wakely
parent 2045ae1d3f
commit cfef4c324a
3 changed files with 48 additions and 12 deletions

View 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

View 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)

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