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