Author: Ronan Lamy <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit