]> granicus.if.org Git - python/commitdiff
Issue #23646: Enhance precision of time.sleep() and socket timeout when
authorVictor Stinner <victor.stinner@gmail.com>
Fri, 20 Mar 2015 00:42:20 +0000 (01:42 +0100)
committerVictor Stinner <victor.stinner@gmail.com>
Fri, 20 Mar 2015 00:42:20 +0000 (01:42 +0100)
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
Lib/test/eintrdata/eintr_tester.py
Modules/socketmodule.c
Modules/timemodule.c
Python/pytime.c

index 7a14456d3f5958194f2151feabfd2c1ea8dfd2d7..d46b17c62933b0fb7c90eb743d3afbf1052ee5e6 100644 (file)
@@ -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);
index 400dd21191ef8573621d69f6a3a8dd6aeac4948e..64db2e55dc3c2487327a2b5d473a63b28c2b81dc 100644 (file)
@@ -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():
index 057430b7040c6205acaa5f7be3090dfcab37e9a0..480ee5ab4ec538006595e53270a1294d4915b310 100644 (file)
@@ -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; \
index 179c33fb9228c9be82c7b517a8c22ed0bced3b37..204626e8f76e140b47f6bbb76213bccc134adbba 100644 (file)
@@ -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);
index cdaa22ec669a0f3fc9c81ab50cc5db9aa9b3f034..894008db8b7903024697212f5edd9a243ce7bf5f 100644 (file)
@@ -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)
 {