Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: py3.5
Changeset: r93425:570c2749ff19
Date: 2017-12-15 04:22 +0000
http://bitbucket.org/pypy/pypy/changeset/570c2749ff19/

Log:    Fix handling of time.sleep()'s argument and use nanosecond precision
        internally

diff --git a/pypy/interpreter/timeutils.py b/pypy/interpreter/timeutils.py
--- a/pypy/interpreter/timeutils.py
+++ b/pypy/interpreter/timeutils.py
@@ -1,6 +1,14 @@
 """
 Access to the time module's high-resolution monotonic clock
 """
+import math
+from rpython.rlib.rarithmetic import (
+    r_longlong, ovfcheck, ovfcheck_float_to_longlong)
+from pypy.interpreter.error import oefmt
+
+SECS_TO_NS = 10 ** 9
+MS_TO_NS = 10 ** 6
+US_TO_NS = 10 ** 3
 
 def monotonic(space):
     from pypy.module.time import interp_time
@@ -9,3 +17,21 @@
     else:
         w_res = interp_time.gettimeofday(space)
     return space.float_w(w_res)   # xxx back and forth
+
+def timestamp_w(space, w_secs):
+    if space.isinstance_w(w_secs, space.w_float):
+        secs = space.float_w(w_secs)
+        result_float = math.ceil(secs * SECS_TO_NS)
+        try:
+            return ovfcheck_float_to_longlong(result_float)
+        except OverflowError:
+            raise oefmt(space.w_OverflowError,
+                "timestamp %R too large to convert to C _PyTime_t", w_secs)
+    else:
+        sec = space.int_w(w_secs)
+        try:
+            result = ovfcheck(sec * SECS_TO_NS)
+        except OverflowError:
+            raise oefmt(space.w_OverflowError,
+                "timestamp too large to convert to C _PyTime_t")
+        return r_longlong(result)
diff --git a/pypy/module/time/interp_time.py b/pypy/module/time/interp_time.py
--- a/pypy/module/time/interp_time.py
+++ b/pypy/module/time/interp_time.py
@@ -3,10 +3,12 @@
 from pypy.interpreter.error import (OperationError, oefmt,
         strerror as _strerror, exception_from_saved_errno)
 from pypy.interpreter.gateway import unwrap_spec
-from pypy.interpreter import timeutils
+from pypy.interpreter.timeutils import (
+    SECS_TO_NS, MS_TO_NS, US_TO_NS, monotonic as _monotonic, timestamp_w)
 from pypy.interpreter.unicodehelper import decode_utf8, encode_utf8
 from rpython.rtyper.lltypesystem import lltype
-from rpython.rlib.rarithmetic import intmask, r_ulonglong, r_longfloat, widen
+from rpython.rlib.rarithmetic import (
+    intmask, r_ulonglong, r_longfloat, widen, ovfcheck, ovfcheck_float_to_int)
 from rpython.rlib.rtime import (GETTIMEOFDAY_NO_TZ, TIMEVAL,
                                 HAVE_GETTIMEOFDAY, HAVE_FTIME)
 from rpython.rlib import rposix, rtime
@@ -452,25 +454,22 @@
     from rpython.rlib.rtime import c_select
 from rpython.rlib import rwin32
 
-@unwrap_spec(secs=float)
-def sleep(space, secs):
-    if secs < 0:
+def sleep(space, w_secs):
+    ns = timestamp_w(space, w_secs)
+    if not (ns >= 0):
         raise oefmt(space.w_ValueError,
                     "sleep length must be non-negative")
-    end_time = timeutils.monotonic(space) + secs
+    end_time = _monotonic(space) + float(ns) / SECS_TO_NS
     while True:
         if _WIN:
             # as decreed by Guido, only the main thread can be
             # interrupted.
             main_thread = space.fromcache(State).main_thread
             interruptible = (main_thread == thread.get_ident())
-            millisecs = int(secs * 1000)
+            millisecs = ns // MS_TO_NS
             if millisecs == 0 or not interruptible:
-                rtime.sleep(secs)
+                rtime.sleep(float(ns) / SECS_TO_NS)
                 break
-            MAX = int(sys.maxint / 1000)  # > 24 days
-            if millisecs > MAX:
-                millisecs = MAX
             interrupt_event = space.fromcache(State).get_interrupt_event()
             rwin32.ResetEvent(interrupt_event)
             rc = rwin32.WaitForSingleObject(interrupt_event, millisecs)
@@ -479,9 +478,10 @@
         else:
             void = lltype.nullptr(rffi.VOIDP.TO)
             with lltype.scoped_alloc(TIMEVAL) as t:
-                frac = math.fmod(secs, 1.0)
-                rffi.setintfield(t, 'c_tv_sec', int(secs))
-                rffi.setintfield(t, 'c_tv_usec', int(frac*1000000.0))
+                seconds = ns // SECS_TO_NS
+                us = (ns % SECS_TO_NS) // US_TO_NS
+                rffi.setintfield(t, 'c_tv_sec', seconds)
+                rffi.setintfield(t, 'c_tv_usec', us)
 
                 res = rffi.cast(rffi.LONG, c_select(0, void, void, void, t))
             if res == 0:
@@ -489,8 +489,8 @@
             if rposix.get_saved_errno() != EINTR:
                 raise exception_from_saved_errno(space, space.w_OSError)
         space.getexecutioncontext().checksignals()
-        secs = end_time - timeutils.monotonic(space)   # retry
-        if secs <= 0.0:
+        secs = end_time - _monotonic(space)   # retry
+        if secs <= 0:
             break
 
 def _get_module_object(space, obj_name):
diff --git a/pypy/module/time/test/test_time.py 
b/pypy/module/time/test/test_time.py
--- a/pypy/module/time/test/test_time.py
+++ b/pypy/module/time/test/test_time.py
@@ -13,13 +13,11 @@
         assert isinstance(time._STRUCT_TM_ITEMS, int)
 
     def test_sleep(self):
-        import sys
-        import os
         import time
         raises(TypeError, time.sleep, "foo")
         time.sleep(0.12345)
         raises(ValueError, time.sleep, -1.0)
-        raises(ValueError, time.sleep, float('nan'))
+        raises((ValueError, OverflowError), time.sleep, float('nan'))
         raises(OverflowError, time.sleep, float('inf'))
 
     def test_clock(self):
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to