From 9a8089b32adee874caefbe2a96096998625c5a78 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 20 Mar 2015 01:42:20 +0100 Subject: Issue #23646: Enhance precision of time.sleep() and socket timeout when interrupted by a signal Add a new _PyTime_AddDouble() function and remove _PyTime_ADD_SECONDS() macro. The _PyTime_ADD_SECONDS only supported an integer number of seconds, the _PyTime_AddDouble() has subsecond resolution. --- Include/pytime.h | 12 +++++------- Lib/test/eintrdata/eintr_tester.py | 7 ++----- Modules/socketmodule.c | 2 +- Modules/timemodule.c | 4 ++-- Python/pytime.c | 17 +++++++++++++++++ 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Include/pytime.h b/Include/pytime.h index 7a14456..d46b17c 100644 --- a/Include/pytime.h +++ b/Include/pytime.h @@ -41,13 +41,6 @@ PyAPI_FUNC(int) _PyTime_gettimeofday_info( _PyTime_timeval *tp, _Py_clock_info_t *info); -#define _PyTime_ADD_SECONDS(tv, interval) \ -do { \ - tv.tv_usec += (long) (((long) interval - interval) * 1000000); \ - tv.tv_sec += (time_t) interval + (time_t) (tv.tv_usec / 1000000); \ - tv.tv_usec %= 1000000; \ -} while (0) - #define _PyTime_INTERVAL(tv_start, tv_end) \ ((tv_end.tv_sec - tv_start.tv_sec) + \ (tv_end.tv_usec - tv_start.tv_usec) * 0.000001) @@ -109,6 +102,11 @@ PyAPI_FUNC(int) _PyTime_monotonic_info( _PyTime_timeval *tp, _Py_clock_info_t *info); +/* Add interval seconds to tv */ +PyAPI_FUNC(void) +_PyTime_AddDouble(_PyTime_timeval *tv, double interval, + _PyTime_round_t round); + /* Initialize time. Return 0 on success, raise an exception and return -1 on error. */ PyAPI_FUNC(int) _PyTime_Init(void); diff --git a/Lib/test/eintrdata/eintr_tester.py b/Lib/test/eintrdata/eintr_tester.py index 400dd21..64db2e5 100644 --- a/Lib/test/eintrdata/eintr_tester.py +++ b/Lib/test/eintrdata/eintr_tester.py @@ -258,13 +258,10 @@ class TimeEINTRTest(EINTRBaseTest): def test_sleep(self): t0 = time.monotonic() - # time.sleep() may retry when interrupted by a signal - time.sleep(2) + time.sleep(self.sleep_time) signal.alarm(0) dt = time.monotonic() - t0 - # Tolerate a difference 100 ms: on Windows, time.monotonic() has - # a resolution of 15.6 ms or greater - self.assertGreaterEqual(dt, 1.9) + self.assertGreaterEqual(dt, self.sleep_time) def test_main(): diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 057430b..480ee5a 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -687,7 +687,7 @@ internal_select(PySocketSockObject *s, int writing) if (has_timeout) { \ _PyTime_monotonic(&now); \ deadline = now; \ - _PyTime_ADD_SECONDS(deadline, s->sock_timeout); \ + _PyTime_AddDouble(&deadline, s->sock_timeout, _PyTime_ROUND_UP); \ } \ while (1) { \ errno = 0; \ diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 179c33f..204626e 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -1399,14 +1399,14 @@ floatsleep(double secs) #endif _PyTime_monotonic(&deadline); - _PyTime_ADD_SECONDS(deadline, secs); + _PyTime_AddDouble(&deadline, secs, _PyTime_ROUND_UP); do { #ifndef MS_WINDOWS frac = fmod(secs, 1.0); secs = floor(secs); timeout.tv_sec = (long)secs; - timeout.tv_usec = (long)(frac*1000000.0); + timeout.tv_usec = (long)(frac*1e6); Py_BEGIN_ALLOW_THREADS err = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &timeout); diff --git a/Python/pytime.c b/Python/pytime.c index cdaa22e..894008d 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -367,6 +367,23 @@ _PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec, return _PyTime_ObjectToDenominator(obj, sec, usec, 1e6, round); } +void +_PyTime_AddDouble(_PyTime_timeval *tv, double interval, _PyTime_round_t round) +{ + _PyTime_timeval tv2; + double frac; + + frac = fmod(interval, 1.0); + interval = floor(interval); + tv2.tv_sec = (long)interval; + tv2.tv_usec = (long)(frac*1e6); + + tv->tv_sec += tv2.tv_sec; + tv->tv_usec += tv2.tv_usec; + tv->tv_sec += (time_t)(tv->tv_usec / 1000000); + tv->tv_usec %= 1000000; +} + int _PyTime_Init(void) { -- cgit v0.12