Change sleep_for, sleep_until, and the condition_variable timed wait
functions to protect against duration and time_point overflow. Since we're about to wait anyway, we can afford to spend a few more cycles on this checking. I purposefully did not treat the timed try_locks with overflow checking. This fixes http://llvm.org/bugs/show_bug.cgi?id=13721 . I'm unsure if the standard needs clarification in this area, or if this is simply QOI. The <chrono> facilities were never intended to overflow check, but just to not overflow if durations stayed within +/- 292 years. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@162925 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c417a802ed
commit
cf115d2cc6
@ -323,11 +323,6 @@ public:
|
|||||||
template <class _Predicate>
|
template <class _Predicate>
|
||||||
void wait(unique_lock<mutex>& __lk, _Predicate __pred);
|
void wait(unique_lock<mutex>& __lk, _Predicate __pred);
|
||||||
|
|
||||||
template <class _Duration>
|
|
||||||
cv_status
|
|
||||||
wait_until(unique_lock<mutex>& __lk,
|
|
||||||
const chrono::time_point<chrono::system_clock, _Duration>& __t);
|
|
||||||
|
|
||||||
template <class _Clock, class _Duration>
|
template <class _Clock, class _Duration>
|
||||||
cv_status
|
cv_status
|
||||||
wait_until(unique_lock<mutex>& __lk,
|
wait_until(unique_lock<mutex>& __lk,
|
||||||
@ -382,28 +377,13 @@ condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
|
|||||||
wait(__lk);
|
wait(__lk);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _Duration>
|
|
||||||
cv_status
|
|
||||||
condition_variable::wait_until(unique_lock<mutex>& __lk,
|
|
||||||
const chrono::time_point<chrono::system_clock, _Duration>& __t)
|
|
||||||
{
|
|
||||||
using namespace chrono;
|
|
||||||
typedef time_point<system_clock, nanoseconds> __nano_sys_tmpt;
|
|
||||||
__do_timed_wait(__lk,
|
|
||||||
__nano_sys_tmpt(__ceil<nanoseconds>(__t.time_since_epoch())));
|
|
||||||
return system_clock::now() < __t ? cv_status::no_timeout :
|
|
||||||
cv_status::timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class _Clock, class _Duration>
|
template <class _Clock, class _Duration>
|
||||||
cv_status
|
cv_status
|
||||||
condition_variable::wait_until(unique_lock<mutex>& __lk,
|
condition_variable::wait_until(unique_lock<mutex>& __lk,
|
||||||
const chrono::time_point<_Clock, _Duration>& __t)
|
const chrono::time_point<_Clock, _Duration>& __t)
|
||||||
{
|
{
|
||||||
using namespace chrono;
|
using namespace chrono;
|
||||||
system_clock::time_point __s_now = system_clock::now();
|
wait_for(__lk, __t - _Clock::now());
|
||||||
typename _Clock::time_point __c_now = _Clock::now();
|
|
||||||
__do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__t - __c_now));
|
|
||||||
return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
|
return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,9 +407,17 @@ condition_variable::wait_for(unique_lock<mutex>& __lk,
|
|||||||
const chrono::duration<_Rep, _Period>& __d)
|
const chrono::duration<_Rep, _Period>& __d)
|
||||||
{
|
{
|
||||||
using namespace chrono;
|
using namespace chrono;
|
||||||
|
if (__d <= __d.zero())
|
||||||
|
return cv_status::timeout;
|
||||||
|
typedef time_point<system_clock, duration<long double, nano> > __sys_tpf;
|
||||||
|
typedef time_point<system_clock, nanoseconds> __sys_tpi;
|
||||||
|
__sys_tpf _Max = __sys_tpi::max();
|
||||||
system_clock::time_point __s_now = system_clock::now();
|
system_clock::time_point __s_now = system_clock::now();
|
||||||
steady_clock::time_point __c_now = steady_clock::now();
|
steady_clock::time_point __c_now = steady_clock::now();
|
||||||
__do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
|
if (_Max - __d > __s_now)
|
||||||
|
__do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
|
||||||
|
else
|
||||||
|
__do_timed_wait(__lk, __sys_tpi::max());
|
||||||
return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
|
return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
|
||||||
cv_status::timeout;
|
cv_status::timeout;
|
||||||
}
|
}
|
||||||
|
@ -410,10 +410,20 @@ void
|
|||||||
sleep_for(const chrono::duration<_Rep, _Period>& __d)
|
sleep_for(const chrono::duration<_Rep, _Period>& __d)
|
||||||
{
|
{
|
||||||
using namespace chrono;
|
using namespace chrono;
|
||||||
nanoseconds __ns = duration_cast<nanoseconds>(__d);
|
if (__d > duration<_Rep, _Period>::zero())
|
||||||
if (__ns < __d)
|
{
|
||||||
++__ns;
|
_LIBCPP_CONSTEXPR duration<long double> _Max = nanoseconds::max();
|
||||||
sleep_for(__ns);
|
nanoseconds __ns;
|
||||||
|
if (__d < _Max)
|
||||||
|
{
|
||||||
|
__ns = duration_cast<nanoseconds>(__d);
|
||||||
|
if (__ns < __d)
|
||||||
|
++__ns;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
__ns = nanoseconds::max();
|
||||||
|
sleep_for(__ns);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _Clock, class _Duration>
|
template <class _Clock, class _Duration>
|
||||||
|
@ -51,10 +51,22 @@ condition_variable::__do_timed_wait(unique_lock<mutex>& lk,
|
|||||||
__throw_system_error(EPERM,
|
__throw_system_error(EPERM,
|
||||||
"condition_variable::timed wait: mutex not locked");
|
"condition_variable::timed wait: mutex not locked");
|
||||||
nanoseconds d = tp.time_since_epoch();
|
nanoseconds d = tp.time_since_epoch();
|
||||||
|
if (d > nanoseconds(0x59682F000000E941))
|
||||||
|
d = nanoseconds(0x59682F000000E941);
|
||||||
timespec ts;
|
timespec ts;
|
||||||
seconds s = duration_cast<seconds>(d);
|
seconds s = duration_cast<seconds>(d);
|
||||||
ts.tv_sec = static_cast<decltype(ts.tv_sec)>(s.count());
|
typedef decltype(ts.tv_sec) ts_sec;
|
||||||
ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((d - s).count());
|
_LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max();
|
||||||
|
if (s.count() < ts_sec_max)
|
||||||
|
{
|
||||||
|
ts.tv_sec = static_cast<ts_sec>(s.count());
|
||||||
|
ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((d - s).count());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ts.tv_sec = ts_sec_max;
|
||||||
|
ts.tv_nsec = giga::num - 1;
|
||||||
|
}
|
||||||
int ec = pthread_cond_timedwait(&__cv_, lk.mutex()->native_handle(), &ts);
|
int ec = pthread_cond_timedwait(&__cv_, lk.mutex()->native_handle(), &ts);
|
||||||
if (ec != 0 && ec != ETIMEDOUT)
|
if (ec != 0 && ec != ETIMEDOUT)
|
||||||
__throw_system_error(ec, "condition_variable timed_wait failed");
|
__throw_system_error(ec, "condition_variable timed_wait failed");
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "exception"
|
#include "exception"
|
||||||
#include "vector"
|
#include "vector"
|
||||||
#include "future"
|
#include "future"
|
||||||
|
#include "limits"
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#if !_WIN32
|
#if !_WIN32
|
||||||
#if !__sun__ && !__linux__
|
#if !__sun__ && !__linux__
|
||||||
@ -83,11 +84,22 @@ void
|
|||||||
sleep_for(const chrono::nanoseconds& ns)
|
sleep_for(const chrono::nanoseconds& ns)
|
||||||
{
|
{
|
||||||
using namespace chrono;
|
using namespace chrono;
|
||||||
if (ns >= nanoseconds::zero())
|
if (ns > nanoseconds::zero())
|
||||||
{
|
{
|
||||||
|
seconds s = duration_cast<seconds>(ns);
|
||||||
timespec ts;
|
timespec ts;
|
||||||
ts.tv_sec = static_cast<decltype(ts.tv_sec)>(duration_cast<seconds>(ns).count());
|
typedef decltype(ts.tv_sec) ts_sec;
|
||||||
ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns - seconds(ts.tv_sec)).count());
|
_LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max();
|
||||||
|
if (s.count() < ts_sec_max)
|
||||||
|
{
|
||||||
|
ts.tv_sec = static_cast<ts_sec>(s.count());
|
||||||
|
ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns-s).count());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ts.tv_sec = ts_sec_max;
|
||||||
|
ts.tv_nsec = giga::num - 1;
|
||||||
|
}
|
||||||
nanosleep(&ts, 0);
|
nanosleep(&ts, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user