diff -r e6cfbc3e2ed9 -r 8ea8efb67210 Include/pytime.h --- a/Include/pytime.h Thu Sep 04 09:53:16 2014 +0200 +++ b/Include/pytime.h Fri Sep 05 00:04:33 2014 +0200 @@ -13,6 +13,19 @@ functions and constants extern "C" { #endif +#ifdef PY_INT64_T +typedef PY_INT64_T _PyTime_t; +#else +# error "_PyTime_t need signed 64-bit integer type" +#endif + +typedef enum { + /* Round towards zero. */ + _PyTime_ROUND_DOWN=0, + /* Round away from zero. */ + _PyTime_ROUND_UP +} _PyTime_round_t; + #ifdef HAVE_GETTIMEOFDAY typedef struct timeval _PyTime_timeval; #else @@ -30,41 +43,6 @@ typedef struct { double resolution; } _Py_clock_info_t; -/* Similar to POSIX gettimeofday but cannot fail. If system gettimeofday - * fails or is not available, fall back to lower resolution clocks. - */ -PyAPI_FUNC(void) _PyTime_gettimeofday(_PyTime_timeval *tp); - -/* Similar to _PyTime_gettimeofday() but retrieve also information on the - * clock used to get the current time. */ -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) - -typedef enum { - /* Round towards zero. */ - _PyTime_ROUND_DOWN=0, - /* Round away from zero. */ - _PyTime_ROUND_UP -} _PyTime_round_t; - -/* Convert a number of seconds, int or float, to time_t. */ -PyAPI_FUNC(int) _PyTime_ObjectToTime_t( - PyObject *obj, - time_t *sec, - _PyTime_round_t); - /* Convert a time_t to a PyLong. */ PyAPI_FUNC(PyObject *) _PyLong_FromTime_t( time_t sec); @@ -73,42 +51,77 @@ PyAPI_FUNC(PyObject *) _PyLong_FromTime_ PyAPI_FUNC(time_t) _PyLong_AsTime_t( PyObject *obj); -/* Convert a number of seconds, int or float, to a timeval structure. - usec is in the range [0; 999999] and rounded towards zero. - For example, -1.2 is converted to (-2, 800000). */ -PyAPI_FUNC(int) _PyTime_ObjectToTimeval( +/* XXX */ +PyAPI_FUNC(int) _PyTime_FromObject(_PyTime_t *t, PyObject *obj, - time_t *sec, - long *usec, - _PyTime_round_t); + _PyTime_round_t round); -/* Convert a number of seconds, int or float, to a timespec structure. - nsec is in the range [0; 999999999] and rounded towards zero. - For example, -1.2 is converted to (-2, 800000000). */ -PyAPI_FUNC(int) _PyTime_ObjectToTimespec( - PyObject *obj, - time_t *sec, - long *nsec, - _PyTime_round_t); +/* XXX */ +PyAPI_FUNC(int) _PyTime_FromTime_t(_PyTime_t *t, + time_t seconds); + +/* Get the current time from the system clock. + * The function cannot fail, the system clock was checked by _PyTime_Init(). + */ +PyAPI_FUNC(_PyTime_t) _PyTime_Get(void); + +/* Get the current time from the system clock. Fill clock information if + * 'info' is not NULL. + * Raise an exception and return -1 on error, return 0 on success. + */ +PyAPI_FUNC(int) _PyTime_GetWithInfo( + _PyTime_t *t, + _Py_clock_info_t *info); /* Get the time of a monotonic clock, i.e. a clock that cannot go backwards. The clock is not affected by system clock updates. The reference point of the returned value is undefined, so that only the difference between the results of consecutive calls is valid. - The function never fails. _PyTime_Init() ensures that a monotonic clock + The function cannot fail. _PyTime_Init() ensures that a monotonic clock is available and works. */ -PyAPI_FUNC(void) _PyTime_monotonic( - _PyTime_timeval *tp); +PyAPI_FUNC(_PyTime_t) _PyTime_Monotonic(void); -/* Similar to _PyTime_monotonic(), fill also info (if set) with information of +/* Similar to _PyTime_Monotonic(), fill also info (if set) with information of the function used to get the time. Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) _PyTime_monotonic_info( - _PyTime_timeval *tp, +PyAPI_FUNC(int) _PyTime_MonotonicWithInfo( + _PyTime_t *t, _Py_clock_info_t *info); +/* XXX */ +PyAPI_FUNC(int)_PyTime_AsTime_t(_PyTime_t t, + time_t *seconds_p, + _PyTime_round_t round); + +/* XXX */ +PyAPI_FUNC(double) _PyTime_AsDouble(_PyTime_t t); + +/* XXX */ +PyAPI_FUNC(int) _PyTime_AsTimeval(_PyTime_t t, + struct timeval *tv, + _PyTime_round_t round); + +/* XXX */ +PyAPI_FUNC(int) _PyTime_AsTimespec(_PyTime_t t, + struct timespec *ts, + _PyTime_round_t round); + +/* XXX */ +PyAPI_FUNC(_PyTime_t) +_PyTime_Multiply(_PyTime_t t, + unsigned int multiply, + _PyTime_round_t round); + +/* XXX */ +PyAPI_FUNC(int) +_PyTime_Divide(_PyTime_t t, + time_t *seconds, + unsigned int denominator, + unsigned int *numerator, + _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 -r e6cfbc3e2ed9 -r 8ea8efb67210 Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c Thu Sep 04 09:53:16 2014 +0200 +++ b/Modules/_datetimemodule.c Fri Sep 05 00:04:33 2014 +0200 @@ -2456,13 +2456,16 @@ date_new(PyTypeObject *type, PyObject *a static PyObject * date_local_from_object(PyObject *cls, PyObject *obj) { + _PyTime_t t; + time_t secs; struct tm *tm; - time_t t; - - if (_PyTime_ObjectToTime_t(obj, &t, _PyTime_ROUND_DOWN) == -1) + + if (_PyTime_FromObject(&t, obj, _PyTime_ROUND_DOWN) == -1) return NULL; - - tm = localtime(&t); + if (_PyTime_AsTime_t(t, &secs, _PyTime_ROUND_DOWN) == -1) + return NULL; + + tm = localtime(&secs); if (tm == NULL) { /* unconvertible time */ #ifdef EINVAL @@ -4044,12 +4047,18 @@ typedef struct tm *(*TM_FUNC)(const time * Pass localtime or gmtime for f, to control the interpretation of timet. */ static PyObject * -datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us, - PyObject *tzinfo) +datetime_from_pytime(PyObject *cls, TM_FUNC f, _PyTime_t t, + PyObject *tzinfo) { + time_t sec; + unsigned int us; struct tm *tm; - tm = f(&timet); + if (_PyTime_Divide(t, &sec, 1000 * 1000, &us, _PyTime_ROUND_DOWN) < 0) + return NULL; + assert(us <= INT_MAX); + + tm = f(&sec); if (tm == NULL) { #ifdef EINVAL if (errno == 0) @@ -4073,7 +4082,7 @@ datetime_from_timet_and_us(PyObject *cls tm->tm_hour, tm->tm_min, tm->tm_sec, - us, + (int)us, tzinfo); } @@ -4088,12 +4097,11 @@ static PyObject * datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp, PyObject *tzinfo) { - time_t timet; - long us; - - if (_PyTime_ObjectToTimeval(timestamp, &timet, &us, _PyTime_ROUND_DOWN) == -1) + _PyTime_t t; + + if (_PyTime_FromObject(&t, timestamp, _PyTime_ROUND_DOWN) == -1) return NULL; - return datetime_from_timet_and_us(cls, f, timet, (int)us, tzinfo); + return datetime_from_pytime(cls, f, t, tzinfo); } /* Internal helper. @@ -4103,10 +4111,9 @@ datetime_from_timestamp(PyObject *cls, T static PyObject * datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo) { - _PyTime_timeval t; - _PyTime_gettimeofday(&t); - return datetime_from_timet_and_us(cls, f, t.tv_sec, (int)t.tv_usec, - tzinfo); + _PyTime_t t; + t = _PyTime_Get(); + return datetime_from_pytime(cls, f, t, tzinfo); } /*[clinic input] diff -r e6cfbc3e2ed9 -r 8ea8efb67210 Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c Thu Sep 04 09:53:16 2014 +0200 +++ b/Modules/_testcapimodule.c Fri Sep 05 00:04:33 2014 +0200 @@ -2531,13 +2531,16 @@ static PyObject * test_pytime_object_to_time_t(PyObject *self, PyObject *args) { PyObject *obj; + _PyTime_t t; time_t sec; int round; if (!PyArg_ParseTuple(args, "Oi:pytime_object_to_time_t", &obj, &round)) return NULL; if (check_time_rounding(round) < 0) return NULL; - if (_PyTime_ObjectToTime_t(obj, &sec, round) == -1) + if (_PyTime_FromObject(&t, obj, round) == -1) + return NULL; + if (_PyTime_AsTime_t(t, &sec, round) == -1) return NULL; return _PyLong_FromTime_t(sec); } @@ -2546,32 +2549,36 @@ static PyObject * test_pytime_object_to_timeval(PyObject *self, PyObject *args) { PyObject *obj; - time_t sec; - long usec; + _PyTime_t t; + struct timeval tv; int round; if (!PyArg_ParseTuple(args, "Oi:pytime_object_to_timeval", &obj, &round)) return NULL; if (check_time_rounding(round) < 0) return NULL; - if (_PyTime_ObjectToTimeval(obj, &sec, &usec, round) == -1) + if (_PyTime_FromObject(&t, obj, round) < 0) return NULL; - return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), usec); + if (_PyTime_AsTimeval(t, &tv, round) < 0) + return NULL; + return Py_BuildValue("Nl", _PyLong_FromTime_t(tv.tv_sec), tv.tv_usec); } static PyObject * test_pytime_object_to_timespec(PyObject *self, PyObject *args) { PyObject *obj; - time_t sec; - long nsec; int round; + _PyTime_t t; + struct timespec ts; if (!PyArg_ParseTuple(args, "Oi:pytime_object_to_timespec", &obj, &round)) return NULL; if (check_time_rounding(round) < 0) return NULL; - if (_PyTime_ObjectToTimespec(obj, &sec, &nsec, round) == -1) + if (_PyTime_FromObject(&t, obj, round) == -1) return NULL; - return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), nsec); + if (_PyTime_AsTimespec(t, &ts, round) == -1) + return NULL; + return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec); } static void diff -r e6cfbc3e2ed9 -r 8ea8efb67210 Modules/_threadmodule.c --- a/Modules/_threadmodule.c Thu Sep 04 09:53:16 2014 +0200 +++ b/Modules/_threadmodule.c Fri Sep 05 00:04:33 2014 +0200 @@ -49,21 +49,25 @@ lock_dealloc(lockobject *self) * timeout. */ static PyLockStatus -acquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) +acquire_timed(PyThread_type_lock lock, _PyTime_t timeout) { PyLockStatus r; - _PyTime_timeval curtime; - _PyTime_timeval endtime; + _PyTime_t curtime, endtime, us; + PY_TIMEOUT_T microseconds; - - if (microseconds > 0) { - _PyTime_monotonic(&endtime); - endtime.tv_sec += microseconds / (1000 * 1000); - endtime.tv_usec += microseconds % (1000 * 1000); + if (timeout > 0) { + endtime = _PyTime_Monotonic() + timeout; } + do { + if (timeout >= 0) { + us = _PyTime_Multiply(timeout, 1000 * 1000, _PyTime_ROUND_UP); + /* acquire_parse_args() checked for overflow */ + microseconds = (PY_TIMEOUT_T)us; + } + else + microseconds = -1; - do { /* first a simple non-blocking try without releasing the GIL */ r = PyThread_acquire_lock_timed(lock, 0, 0); if (r == PY_LOCK_FAILURE && microseconds != 0) { @@ -82,14 +86,13 @@ acquire_timed(PyThread_type_lock lock, P /* If we're using a timeout, recompute the timeout after processing * signals, since those can take time. */ - if (microseconds > 0) { - _PyTime_monotonic(&curtime); - microseconds = ((endtime.tv_sec - curtime.tv_sec) * 1000000 + - (endtime.tv_usec - curtime.tv_usec)); + if (timeout > 0) { + curtime = _PyTime_Monotonic(); + timeout = endtime - curtime; /* Check for negative values, since those mean block forever. */ - if (microseconds <= 0) { + if (timeout <= 0) { r = PY_LOCK_FAILURE; } } @@ -99,44 +102,74 @@ acquire_timed(PyThread_type_lock lock, P return r; } +static int +acquire_parse_args(PyObject *args, PyObject *kwds, + int *blockingp, _PyTime_t *timeoutp) +{ + char *kwlist[] = {"blocking", "timeout", NULL}; + int blocking = 1; + PyObject *timeout_obj = NULL; + _PyTime_t timeout; + int timeout_set; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO:acquire", kwlist, + &blocking, &timeout_obj)) + return -1; + + if (timeout_obj != NULL) { + _PyTime_t minus_one; + if (_PyTime_FromObject(&timeout, timeout_obj, _PyTime_ROUND_UP) < 0) + return -1; + if (_PyTime_FromTime_t(&minus_one, -1) < 0) + return -1; + timeout_set = (timeout != minus_one); + } + else { + timeout = -1 * 1000 * 1000; + timeout_set = 0; + } + + if (!blocking && timeout_set) { + PyErr_SetString(PyExc_ValueError, "can't specify a timeout " + "for a non-blocking call"); + return -1; + } + if (timeout < 0 && timeout_set) { + PyErr_SetString(PyExc_ValueError, "timeout value must be " + "strictly positive"); + return -1; + } + if (!blocking) + timeout = 0; + else if (timeout_set) { + _PyTime_t us1; + PY_TIMEOUT_T us2; + /* ensure that the timeout fits into PY_TIMEOUT_T */ + us1 = _PyTime_Multiply(timeout, 1000 * 1000, _PyTime_ROUND_UP); + us2 = (PY_TIMEOUT_T)us1; + if ((_PyTime_t)us2 != us1) { + PyErr_SetString(PyExc_OverflowError, + "timeout value is too large"); + return -1; + } + } + + *blockingp = blocking; + *timeoutp = timeout; + return 0; +} + static PyObject * lock_PyThread_acquire_lock(lockobject *self, PyObject *args, PyObject *kwds) { - char *kwlist[] = {"blocking", "timeout", NULL}; - int blocking = 1; - double timeout = -1; - PY_TIMEOUT_T microseconds; + int blocking; + _PyTime_t timeout; PyLockStatus r; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|id:acquire", kwlist, - &blocking, &timeout)) + if (acquire_parse_args(args, kwds, &blocking, &timeout) < 0) return NULL; - if (!blocking && timeout != -1) { - PyErr_SetString(PyExc_ValueError, "can't specify a timeout " - "for a non-blocking call"); - return NULL; - } - if (timeout < 0 && timeout != -1) { - PyErr_SetString(PyExc_ValueError, "timeout value must be " - "strictly positive"); - return NULL; - } - if (!blocking) - microseconds = 0; - else if (timeout == -1) - microseconds = -1; - else { - timeout *= 1e6; - if (timeout >= (double) PY_TIMEOUT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "timeout value is too large"); - return NULL; - } - microseconds = (PY_TIMEOUT_T) timeout; - } - - r = acquire_timed(self->lock_lock, microseconds); + r = acquire_timed(self->lock_lock, timeout); if (r == PY_LOCK_INTR) { return NULL; } @@ -281,41 +314,14 @@ rlock_dealloc(rlockobject *self) static PyObject * rlock_acquire(rlockobject *self, PyObject *args, PyObject *kwds) { - char *kwlist[] = {"blocking", "timeout", NULL}; int blocking = 1; - double timeout = -1; - PY_TIMEOUT_T microseconds; + _PyTime_t timeout; long tid; PyLockStatus r = PY_LOCK_ACQUIRED; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|id:acquire", kwlist, - &blocking, &timeout)) + if (acquire_parse_args(args, kwds, &blocking, &timeout) < 0) return NULL; - if (!blocking && timeout != -1) { - PyErr_SetString(PyExc_ValueError, "can't specify a timeout " - "for a non-blocking call"); - return NULL; - } - if (timeout < 0 && timeout != -1) { - PyErr_SetString(PyExc_ValueError, "timeout value must be " - "strictly positive"); - return NULL; - } - if (!blocking) - microseconds = 0; - else if (timeout == -1) - microseconds = -1; - else { - timeout *= 1e6; - if (timeout >= (double) PY_TIMEOUT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "timeout value is too large"); - return NULL; - } - microseconds = (PY_TIMEOUT_T) timeout; - } - tid = PyThread_get_thread_ident(); if (self->rlock_count > 0 && tid == self->rlock_owner) { unsigned long count = self->rlock_count + 1; @@ -327,7 +333,7 @@ rlock_acquire(rlockobject *self, PyObjec self->rlock_count = count; Py_RETURN_TRUE; } - r = acquire_timed(self->rlock_lock, microseconds); + r = acquire_timed(self->rlock_lock, timeout); if (r == PY_LOCK_ACQUIRED) { assert(self->rlock_count == 0); self->rlock_owner = tid; diff -r e6cfbc3e2ed9 -r 8ea8efb67210 Modules/gcmodule.c --- a/Modules/gcmodule.c Thu Sep 04 09:53:16 2014 +0200 +++ b/Modules/gcmodule.c Fri Sep 05 00:04:33 2014 +0200 @@ -25,7 +25,7 @@ #include "Python.h" #include "frameobject.h" /* for PyFrame_ClearFreeList */ -#include "pytime.h" /* for _PyTime_monotonic, _PyTime_INTERVAL */ +#include "pytime.h" /* for _PyTime_Monotonic */ /* Get an object's GC head */ #define AS_GC(o) ((PyGC_Head *)(o)-1) @@ -908,7 +908,7 @@ collect(int generation, Py_ssize_t *n_co PyGC_Head unreachable; /* non-problematic unreachable trash */ PyGC_Head finalizers; /* objects with, & reachable from, __del__ */ PyGC_Head *gc; - _PyTime_timeval t1; + _PyTime_t t1; struct gc_generation_stats *stats = &generation_stats[generation]; @@ -919,7 +919,7 @@ collect(int generation, Py_ssize_t *n_co for (i = 0; i < NUM_GENERATIONS; i++) PySys_FormatStderr(" %zd", gc_list_size(GEN_HEAD(i))); - _PyTime_monotonic(&t1); + t1 = _PyTime_Monotonic(); PySys_WriteStderr("\n"); } @@ -1024,8 +1024,8 @@ collect(int generation, Py_ssize_t *n_co debug_cycle("uncollectable", FROM_GC(gc)); } if (debug & DEBUG_STATS) { - _PyTime_timeval t2; - _PyTime_monotonic(&t2); + _PyTime_t t2; + t2 = _PyTime_Monotonic(); if (m == 0 && n == 0) PySys_WriteStderr("gc: done"); @@ -1033,7 +1033,7 @@ collect(int generation, Py_ssize_t *n_co PySys_FormatStderr( "gc: done, %zd unreachable, %zd uncollectable", n+m, n); - PySys_WriteStderr(", %.4fs elapsed\n", _PyTime_INTERVAL(t1, t2)); + PySys_WriteStderr(", %.4fs elapsed\n", _PyTime_AsDouble(t2 - t1)); } /* Append instances in the uncollectable set to a Python diff -r e6cfbc3e2ed9 -r 8ea8efb67210 Modules/posixmodule.c --- a/Modules/posixmodule.c Thu Sep 04 09:53:16 2014 +0200 +++ b/Modules/posixmodule.c Fri Sep 05 00:04:33 2014 +0200 @@ -6309,8 +6309,9 @@ os_utime_impl(PyModuleDef *module, path_ } if (times && (times != Py_None)) { - time_t a_sec, m_sec; - long a_nsec, m_nsec; + _PyTime_t t; + struct timespec ts; + PyObject *obj; if (!PyTuple_CheckExact(times) || (PyTuple_Size(times) != 2)) { PyErr_SetString(PyExc_TypeError, "utime: 'times' must be either" @@ -6318,16 +6319,22 @@ os_utime_impl(PyModuleDef *module, path_ goto exit; } utime.now = 0; - if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 0), - &a_sec, &a_nsec, _PyTime_ROUND_DOWN) == -1 || - _PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 1), - &m_sec, &m_nsec, _PyTime_ROUND_DOWN) == -1) { + + obj = PyTuple_GET_ITEM(times, 0); + if (_PyTime_FromObject(&t, obj, _PyTime_ROUND_DOWN) < 0) goto exit; - } - utime.atime_s = a_sec; - utime.atime_ns = a_nsec; - utime.mtime_s = m_sec; - utime.mtime_ns = m_nsec; + if (_PyTime_AsTimespec(t, &ts, _PyTime_ROUND_DOWN) < 0) + goto exit; + utime.atime_s = ts.tv_sec; + utime.atime_ns = ts.tv_nsec; + + obj = PyTuple_GET_ITEM(times, 1); + if (_PyTime_FromObject(&t, obj, _PyTime_ROUND_DOWN) < 0) + goto exit; + if (_PyTime_AsTimespec(t, &ts, _PyTime_ROUND_DOWN) < 0) + goto exit; + utime.mtime_s = ts.tv_sec; + utime.mtime_ns = ts.tv_nsec; } else if (ns) { if (!PyTuple_CheckExact(ns) || (PyTuple_Size(ns) != 2)) { diff -r e6cfbc3e2ed9 -r 8ea8efb67210 Modules/selectmodule.c --- a/Modules/selectmodule.c Thu Sep 04 09:53:16 2014 +0200 +++ b/Modules/selectmodule.c Fri Sep 05 00:04:33 2014 +0200 @@ -212,32 +212,11 @@ select_select(PyObject *self, PyObject * return NULL; } else { - /* On OpenBSD 5.4, timeval.tv_sec is a long. - * Example: long is 64-bit, whereas time_t is 32-bit. */ - time_t sec; - /* On OS X 64-bit, timeval.tv_usec is an int (and thus still 4 - bytes as required), but no longer defined by a long. */ - long usec; - if (_PyTime_ObjectToTimeval(tout, &sec, &usec, - _PyTime_ROUND_UP) == -1) + _PyTime_t t; + if (_PyTime_FromObject(&t, tout, _PyTime_ROUND_UP) == -1) return NULL; -#ifdef MS_WINDOWS - /* On Windows, timeval.tv_sec is a long (32 bit), - * whereas time_t can be 64-bit. */ - assert(sizeof(tv.tv_sec) == sizeof(long)); -#if SIZEOF_TIME_T > SIZEOF_LONG - if (sec > LONG_MAX) { - PyErr_SetString(PyExc_OverflowError, - "timeout is too large"); + if (_PyTime_AsTimeval(t, &tv, _PyTime_ROUND_UP) == -1) return NULL; - } -#endif - tv.tv_sec = (long)sec; -#else - assert(sizeof(tv.tv_sec) >= sizeof(sec)); - tv.tv_sec = sec; -#endif - tv.tv_usec = usec; if (tv.tv_sec < 0) { PyErr_SetString(PyExc_ValueError, "timeout must be non-negative"); return NULL; @@ -2042,8 +2021,10 @@ kqueue_queue_control(kqueue_queue_Object ptimeoutspec = NULL; } else if (PyNumber_Check(otimeout)) { - if (_PyTime_ObjectToTimespec(otimeout, &timeout.tv_sec, - &timeout.tv_nsec, _PyTime_ROUND_UP) == -1) + _PyTime_t t; + if (_PyTime_FromObject(&t, otimeout, _PyTime_ROUND_UP) < 0) + return NULL; + if (_PyTime_AsTimespec(t, timeout, _PyTime_ROUND_UP) < 0) return NULL; if (timeout.tv_sec < 0) { diff -r e6cfbc3e2ed9 -r 8ea8efb67210 Modules/signalmodule.c --- a/Modules/signalmodule.c Thu Sep 04 09:53:16 2014 +0200 +++ b/Modules/signalmodule.c Fri Sep 05 00:04:33 2014 +0200 @@ -960,25 +960,23 @@ Returns a struct_siginfo containing info static PyObject * signal_sigtimedwait(PyObject *self, PyObject *args) { - PyObject *signals, *timeout; - struct timespec buf; + PyObject *signals, *timeout_obj; + _PyTime_t timeout; + struct timespec ts; sigset_t set; siginfo_t si; - time_t tv_sec; - long tv_nsec; int err; if (!PyArg_ParseTuple(args, "OO:sigtimedwait", - &signals, &timeout)) + &signals, &timeout_obj)) return NULL; - if (_PyTime_ObjectToTimespec(timeout, &tv_sec, &tv_nsec, - _PyTime_ROUND_DOWN) == -1) + if (_PyTime_FromObject(&timeout, timeout_obj, _PyTime_ROUND_DOWN) == -1) return NULL; - buf.tv_sec = tv_sec; - buf.tv_nsec = tv_nsec; + if (_PyTime_AsTimespec(timeout, &ts, _PyTime_ROUND_DOWN) == -1) + return NULL; - if (buf.tv_sec < 0 || buf.tv_nsec < 0) { + if (ts.tv_sec < 0 || ts.tv_nsec < 0) { PyErr_SetString(PyExc_ValueError, "timeout must be non-negative"); return NULL; } @@ -987,7 +985,7 @@ signal_sigtimedwait(PyObject *self, PyOb return NULL; Py_BEGIN_ALLOW_THREADS - err = sigtimedwait(&set, &si, &buf); + err = sigtimedwait(&set, &si, &ts); Py_END_ALLOW_THREADS if (err == -1) { if (errno == EAGAIN) diff -r e6cfbc3e2ed9 -r 8ea8efb67210 Modules/socketmodule.c --- a/Modules/socketmodule.c Thu Sep 04 09:53:16 2014 +0200 +++ b/Modules/socketmodule.c Fri Sep 05 00:04:33 2014 +0200 @@ -455,7 +455,7 @@ static PyTypeObject sock_type; #else /* If there's no timeout left, we don't have to call select, so it's a safe, * little white lie. */ -#define IS_SELECTABLE(s) (_PyIsSelectable_fd((s)->sock_fd) || (s)->sock_timeout <= 0.0) +#define IS_SELECTABLE(s) (_PyIsSelectable_fd((s)->sock_fd) || (s)->sock_timeout <= 0) #endif static PyObject* @@ -592,12 +592,12 @@ internal_setblocking(PySocketSockObject after they've reacquired the interpreter lock. Returns 1 on timeout, -1 on error, 0 otherwise. */ static int -internal_select_ex(PySocketSockObject *s, int writing, double interval) +internal_select_ex(PySocketSockObject *s, int writing, _PyTime_t interval) { int n; /* Nothing to do unless we're in timeout mode (not non-blocking) */ - if (s->sock_timeout <= 0.0) + if (s->sock_timeout <= 0) return 0; /* Guard against closed socket */ @@ -605,7 +605,7 @@ internal_select_ex(PySocketSockObject *s return 0; /* Handling this condition here simplifies the select loops */ - if (interval < 0.0) + if (interval < 0) return 1; /* Prefer poll, if available, since you can poll() any fd @@ -613,13 +613,13 @@ internal_select_ex(PySocketSockObject *s #ifdef HAVE_POLL { struct pollfd pollfd; - int timeout; + _PyTime_t timeout; pollfd.fd = s->sock_fd; pollfd.events = writing ? POLLOUT : POLLIN; /* s->sock_timeout is in seconds, timeout in ms */ - timeout = (int)(interval * 1000 + 0.5); + timeout = _PyTime_Multiply(interval, 1000, _PyTime_ROUND_UP); n = poll(&pollfd, 1, timeout); } #else @@ -676,13 +676,11 @@ internal_select(PySocketSockObject *s, i #define BEGIN_SELECT_LOOP(s) \ { \ - _PyTime_timeval now, deadline = {0, 0}; \ - double interval = s->sock_timeout; \ - int has_timeout = s->sock_timeout > 0.0; \ + _PyTime_t deadline = 0; \ + _PyTime_t interval = s->sock_timeout; \ + int has_timeout = s->sock_timeout > 0; \ if (has_timeout) { \ - _PyTime_monotonic(&now); \ - deadline = now; \ - _PyTime_ADD_SECONDS(deadline, s->sock_timeout); \ + deadline = _PyTime_Monotonic() + s->sock_timeout; \ } \ while (1) { \ errno = 0; \ @@ -691,14 +689,13 @@ internal_select(PySocketSockObject *s, i if (!has_timeout || \ (!CHECK_ERRNO(EWOULDBLOCK) && !CHECK_ERRNO(EAGAIN))) \ break; \ - _PyTime_monotonic(&now); \ - interval = _PyTime_INTERVAL(now, deadline); \ + interval = deadline - _PyTime_Monotonic(); \ } \ } \ /* Initialize a new socket object. */ -static double defaulttimeout = -1.0; /* Default timeout for new sockets */ +static _PyTime_t defaulttimeout = -1; /* Default timeout for new sockets */ static void init_sockobject(PySocketSockObject *s, @@ -712,12 +709,12 @@ init_sockobject(PySocketSockObject *s, s->errorhandler = &set_error; #ifdef SOCK_NONBLOCK if (type & SOCK_NONBLOCK) - s->sock_timeout = 0.0; + s->sock_timeout = 0; else #endif { s->sock_timeout = defaulttimeout; - if (defaulttimeout >= 0.0) + if (defaulttimeout >= 0) internal_setblocking(s, 0); } @@ -2134,7 +2131,7 @@ sock_setblocking(PySocketSockObject *s, if (block == -1 && PyErr_Occurred()) return NULL; - s->sock_timeout = block ? -1.0 : 0.0; + s->sock_timeout = block ? -1 : 0; internal_setblocking(s, block); Py_INCREF(Py_None); @@ -2148,6 +2145,32 @@ Set the socket to blocking (flag is true setblocking(True) is equivalent to settimeout(None);\n\ setblocking(False) is equivalent to settimeout(0.0)."); +static int +parse_timeout(PyObject *arg, _PyTime_t *timeout) +{ + struct timeval tv; + if (arg == Py_None) { + *timeout = -1; + return 0; + } + + if (_PyTime_FromObject(timeout, arg, _PyTime_ROUND_UP) < 0) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) + goto overflow; + return -1; + } + if (*timeout < 0) + goto overflow; + if (_PyTime_AsTimeval(*timeout, &tv, _PyTime_ROUND_UP) < 0) + goto overflow; + return 0; + +overflow: + PyErr_SetString(PyExc_ValueError, + "Timeout value out of range"); + return -1; +} + /* s.settimeout(timeout) method. Argument: None -- no timeout, blocking mode; same as setblocking(True) 0.0 -- non-blocking mode; same as setblocking(False) @@ -2157,22 +2180,13 @@ setblocking(False) is equivalent to sett static PyObject * sock_settimeout(PySocketSockObject *s, PyObject *arg) { - double timeout; - - if (arg == Py_None) - timeout = -1.0; - else { - timeout = PyFloat_AsDouble(arg); - if (timeout < 0.0) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_ValueError, - "Timeout value out of range"); - return NULL; - } - } + _PyTime_t timeout; + + if (parse_timeout(arg, &timeout) < 0) + return NULL; s->sock_timeout = timeout; - internal_setblocking(s, timeout < 0.0); + internal_setblocking(s, timeout < 0); Py_INCREF(Py_None); return Py_None; @@ -2191,12 +2205,14 @@ Setting a timeout of zero is the same as static PyObject * sock_gettimeout(PySocketSockObject *s) { - if (s->sock_timeout < 0.0) { + if (s->sock_timeout < 0) { Py_INCREF(Py_None); return Py_None; } - else - return PyFloat_FromDouble(s->sock_timeout); + else { + double d = _PyTime_AsDouble(s->sock_timeout); + return PyFloat_FromDouble(d); + } } PyDoc_STRVAR(gettimeout_doc, @@ -2377,15 +2393,16 @@ internal_connect(PySocketSockObject *s, #ifdef MS_WINDOWS - if (s->sock_timeout > 0.0) { + if (s->sock_timeout > 0) { if (res < 0 && WSAGetLastError() == WSAEWOULDBLOCK && IS_SELECTABLE(s)) { /* This is a mess. Best solution: trust select */ fd_set fds; fd_set fds_exc; struct timeval tv; - tv.tv_sec = (int)s->sock_timeout; - tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6); + int err; + err = _PyTime_AsTimeval(s->sock_timeout, &tv, _PyTime_ROUND_UP); + assert(!err); FD_ZERO(&fds); FD_SET(s->sock_fd, &fds); FD_ZERO(&fds_exc); @@ -2424,7 +2441,7 @@ internal_connect(PySocketSockObject *s, #else - if (s->sock_timeout > 0.0) { + if (s->sock_timeout > 0) { if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) { timeout = internal_select(s, 1); if (timeout == 0) { @@ -3901,11 +3918,18 @@ static PyMethodDef sock_methods[] = { /* SockObject members */ static PyMemberDef sock_memberlist[] = { - {"family", T_INT, offsetof(PySocketSockObject, sock_family), READONLY, "the socket family"}, - {"type", T_INT, offsetof(PySocketSockObject, sock_type), READONLY, "the socket type"}, - {"proto", T_INT, offsetof(PySocketSockObject, sock_proto), READONLY, "the socket protocol"}, - {"timeout", T_DOUBLE, offsetof(PySocketSockObject, sock_timeout), READONLY, "the socket timeout"}, - {0}, + {"family", T_INT, offsetof(PySocketSockObject, sock_family), READONLY, + PyDoc_STR("the socket family")}, + {"type", T_INT, offsetof(PySocketSockObject, sock_type), READONLY, + PyDoc_STR("the socket type")}, + {"proto", T_INT, offsetof(PySocketSockObject, sock_proto), READONLY, + PyDoc_STR("the socket protocol")}, + {0}, +}; + +static PyGetSetDef sock_getsetlist[] = { + {"timeout", (getter)sock_gettimeout, NULL, PyDoc_STR("the socket timeout")}, + {NULL} /* sentinel */ }; /* Deallocate a socket object in response to the last Py_DECREF(). @@ -3967,13 +3991,15 @@ static PyObject * sock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *new; + PySocketSockObject *sock; new = type->tp_alloc(type, 0); - if (new != NULL) { - ((PySocketSockObject *)new)->sock_fd = -1; - ((PySocketSockObject *)new)->sock_timeout = -1.0; - ((PySocketSockObject *)new)->errorhandler = &set_error; - } + if (new == NULL) + return NULL; + sock = (PySocketSockObject *)new; + sock->sock_fd = -1; + sock->sock_timeout = -1; + sock->errorhandler = &set_error; return new; } @@ -4154,7 +4180,7 @@ static PyTypeObject sock_type = { 0, /* tp_iternext */ sock_methods, /* tp_methods */ sock_memberlist, /* tp_members */ - 0, /* tp_getset */ + sock_getsetlist, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ @@ -5468,12 +5494,14 @@ Get host and port for a sockaddr."); static PyObject * socket_getdefaulttimeout(PyObject *self) { - if (defaulttimeout < 0.0) { + if (defaulttimeout < 0) { Py_INCREF(Py_None); return Py_None; } - else - return PyFloat_FromDouble(defaulttimeout); + else { + double d = _PyTime_AsDouble(defaulttimeout); + return PyFloat_FromDouble(d); + } } PyDoc_STRVAR(getdefaulttimeout_doc, @@ -5486,19 +5514,10 @@ When the socket module is first imported static PyObject * socket_setdefaulttimeout(PyObject *self, PyObject *arg) { - double timeout; - - if (arg == Py_None) - timeout = -1.0; - else { - timeout = PyFloat_AsDouble(arg); - if (timeout < 0.0) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_ValueError, - "Timeout value out of range"); - return NULL; - } - } + _PyTime_t timeout; + + if (parse_timeout(arg, &timeout) < 0) + return NULL; defaulttimeout = timeout; diff -r e6cfbc3e2ed9 -r 8ea8efb67210 Modules/socketmodule.h --- a/Modules/socketmodule.h Thu Sep 04 09:53:16 2014 +0200 +++ b/Modules/socketmodule.h Fri Sep 05 00:04:33 2014 +0200 @@ -167,7 +167,7 @@ typedef struct { PyObject *(*errorhandler)(void); /* Error handler; checks errno, returns NULL and sets a Python exception */ - double sock_timeout; /* Operation timeout in seconds; + _PyTime_t sock_timeout; /* Operation timeout in seconds; 0.0 means non-blocking */ } PySocketSockObject; diff -r e6cfbc3e2ed9 -r 8ea8efb67210 Modules/timemodule.c --- a/Modules/timemodule.c Thu Sep 04 09:53:16 2014 +0200 +++ b/Modules/timemodule.c Fri Sep 05 00:04:33 2014 +0200 @@ -177,20 +177,19 @@ time_clock_settime(PyObject *self, PyObj { int clk_id; PyObject *obj; - time_t tv_sec; - long tv_nsec; - struct timespec tp; + _PyTime_t t; + struct timespec ts; int ret; if (!PyArg_ParseTuple(args, "iO:clock_settime", &clk_id, &obj)) return NULL; - if (_PyTime_ObjectToTimespec(obj, &tv_sec, &tv_nsec, _PyTime_ROUND_DOWN) == -1) + if (_PyTime_FromObject(&t, obj, _PyTime_ROUND_DOWN) == -1) return NULL; - tp.tv_sec = tv_sec; - tp.tv_nsec = tv_nsec; + if (_PyTime_AsTimespec(t, &ts, _PyTime_ROUND_DOWN) == -1) + return NULL; - ret = clock_settime((clockid_t)clk_id, &tp); + ret = clock_settime((clockid_t)clk_id, &ts); if (ret != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; @@ -325,18 +324,21 @@ static int parse_time_t_args(PyObject *args, char *format, time_t *pwhen) { PyObject *ot = NULL; - time_t whent; + _PyTime_t t; + time_t seconds; if (!PyArg_ParseTuple(args, format, &ot)) return 0; if (ot == NULL || ot == Py_None) { - whent = time(NULL); + seconds = time(NULL); } else { - if (_PyTime_ObjectToTime_t(ot, &whent, _PyTime_ROUND_DOWN) == -1) + if (_PyTime_FromObject(&t, ot, _PyTime_ROUND_DOWN) < 0) + return 0; + if (_PyTime_AsTime_t(t, &seconds, _PyTime_ROUND_DOWN) < 0) return 0; } - *pwhen = whent; + *pwhen = seconds; return 1; } @@ -898,12 +900,14 @@ should not be relied on."); static PyObject * pymonotonic(_Py_clock_info_t *info) { - _PyTime_timeval tv; - if (_PyTime_monotonic_info(&tv, info) < 0) { + _PyTime_t t; + double d; + if (_PyTime_MonotonicWithInfo(&t, info) < 0) { assert(info != NULL); return NULL; } - return PyFloat_FromDouble((double)tv.tv_sec + tv.tv_usec * 1e-6); + d = _PyTime_AsDouble(t); + return PyFloat_FromDouble(d); } static PyObject * @@ -1390,12 +1394,14 @@ PyInit_time(void) static PyObject* floattime(_Py_clock_info_t *info) { - _PyTime_timeval t; - if (_PyTime_gettimeofday_info(&t, info) < 0) { + _PyTime_t t; + double d; + if (_PyTime_GetWithInfo(&t, info) < 0) { assert(info != NULL); return NULL; } - return PyFloat_FromDouble((double)t.tv_sec + t.tv_usec * 1e-6); + d = _PyTime_AsDouble(t); + return PyFloat_FromDouble(d); } diff -r e6cfbc3e2ed9 -r 8ea8efb67210 Python/pytime.c --- a/Python/pytime.c Thu Sep 04 09:53:16 2014 +0200 +++ b/Python/pytime.c Fri Sep 05 00:04:33 2014 +0200 @@ -11,25 +11,280 @@ static OSVERSIONINFOEX winver; #endif +#define MS_TO_NS (1000 * 1000) +#define US_TO_NS (1000) +#define SEC_TO_NS (1000 * 1000 * 1000) + +time_t +_PyLong_AsTime_t(PyObject *obj) +{ +#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG + PY_LONG_LONG val; + val = PyLong_AsLongLong(obj); +#else + long val; + assert(sizeof(time_t) <= sizeof(long)); + val = PyLong_AsLong(obj); +#endif + if (val == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "timestamp out of range for platform time_t"); + } + return -1; + } + return (time_t)val; +} + +static void +_PyTime_overflow(void) +{ + PyErr_SetString(PyExc_OverflowError, + "timestamp too large to convert to C _PyTime_t"); +} + +PyObject * +_PyLong_FromTime_t(time_t t) +{ +#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG + return PyLong_FromLongLong((PY_LONG_LONG)t); +#else + assert(sizeof(time_t) <= sizeof(long)); + return PyLong_FromLong((long)t); +#endif +} + +int +_PyTime_FromTime_t(_PyTime_t *t, time_t seconds) +{ + *t = (_PyTime_t)seconds * SEC_TO_NS; + if (*t / SEC_TO_NS != seconds) { + _PyTime_overflow(); + return -1; + } + return 0; +} + +#ifndef HAVE_CLOCK_GETTIME static int -pygettimeofday(_PyTime_timeval *tp, _Py_clock_info_t *info, int raise) +_PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv) +{ + _PyTime_t t; + + t = (_PyTime_t)tv->tv_sec * SEC_TO_NS; + if (t / SEC_TO_NS != ts->tv_sec) { + _PyTime_overflow(); + return -1; + } + + t += (_PyTime_t)ts->tv_usec * US_TO_NS; + + *tp = t; + return 0; +} +#endif + +#ifdef HAVE_CLOCK_GETTIME +static int +_PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts) +{ + _PyTime_t t; + t = (_PyTime_t)ts->tv_sec * SEC_TO_NS; + if (t / SEC_TO_NS != ts->tv_sec) { + _PyTime_overflow(); + return -1; + } + + t += ts->tv_nsec; + + *tp = t; + return 0; +} +#endif + +int +_PyTime_FromObject(_PyTime_t *t, PyObject *obj, _PyTime_round_t round) +{ + if (PyFloat_Check(obj)) { + double d, err; + + /* convert to a number of nanoseconds */ + d = PyFloat_AsDouble(obj); + d *= 1e9; + + /* FIXME: use sign */ + if (round == _PyTime_ROUND_UP) + d = ceil(d); + else + d = floor(d); + + *t = (_PyTime_t)d; + err = d - (double)*t; + if (fabs(err) >= 1.0) { + _PyTime_overflow(); + return -1; + } + return 0; + } + else { +#ifdef HAVE_LONG_LONG + PY_LONG_LONG sec; + sec = PyLong_AsLongLong(obj); + assert(sizeof(PY_LONG_LONG) <= sizeof(_PyTime_t)); +#else + long sec; + sec = PyLong_AsLong(obj); + assert(sizeof(PY_LONG_LONG) <= sizeof(_PyTime_t)); +#endif + if (sec == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) + _PyTime_overflow(); + return -1; + } + *t = sec * SEC_TO_NS; + if (*t / SEC_TO_NS != sec) { + _PyTime_overflow(); + return -1; + } + return 0; + } +} + +int +_PyTime_AsTime_t(_PyTime_t t, time_t *seconds_p, _PyTime_round_t round) +{ + _PyTime_t seconds; + if (round == _PyTime_ROUND_UP) + seconds = (t + SEC_TO_NS - 1) / SEC_TO_NS; + else + seconds = t / SEC_TO_NS; + *seconds_p = (time_t)seconds; + if ((_PyTime_t)*seconds_p != seconds) + return -1; + return 0; +} + +int +_PyTime_AsTimeval(_PyTime_t t, struct timeval *tv, _PyTime_round_t round) +{ + _PyTime_t secs, ns; + + secs = t / SEC_TO_NS; + ns = t % SEC_TO_NS; + +#ifdef MS_WINDOWS + /* On Windows, timeval.tv_sec is a long (32 bit), + whereas time_t can be 64-bit. */ + assert(sizeof(tv->tv_sec) == sizeof(long)); +#if SIZEOF_TIME_T > SIZEOF_LONG + if (secs > LONG_MAX) { + _PyTime_overflow(); + return NULL; + } +#endif + tv->tv_sec = (long)secs; +#else + /* On OpenBSD 5.4, timeval.tv_sec is a long. + Example: long is 64-bit, whereas time_t is 32-bit. */ + tv->tv_sec = secs; + if ((_PyTime_t)tv->tv_sec != secs) { + _PyTime_overflow(); + return -1; + } +#endif + + if (round == _PyTime_ROUND_UP) + tv->tv_usec = (int)((ns + US_TO_NS - 1) / US_TO_NS); + else + tv->tv_usec = (int)(ns / US_TO_NS); + return 0; +} + +int +_PyTime_AsTimespec(_PyTime_t t, struct timespec *ts, _PyTime_round_t round) +{ + _PyTime_t sec, nsec; + sec = t / SEC_TO_NS; + nsec = t % SEC_TO_NS; + ts->tv_sec = (time_t)sec; + if ((_PyTime_t)ts->tv_sec != sec) { + _PyTime_overflow(); + return -1; + } + ts->tv_nsec = nsec; + return 0; +} + +double +_PyTime_AsDouble(_PyTime_t t) +{ + _PyTime_t sec, ns; + /* Divide using integers to avoid rounding issues on the integer part. + 1e-9 cannot be stored exactly in IEEE 64-bit. */ + sec = t / SEC_TO_NS; + ns = t % SEC_TO_NS; + return (double)sec + (double)ns * 1e-9; +} + +_PyTime_t +_PyTime_Multiply(_PyTime_t t, unsigned int multiply, _PyTime_round_t round) +{ + _PyTime_t k; + assert(0 < multiply); + if (multiply < SEC_TO_NS) { + k = SEC_TO_NS / multiply; + if (round == _PyTime_ROUND_UP) + return (t + k - 1) / k; + else + return t / k; + } + else { + k = multiply / SEC_TO_NS; + return t * k; + } +} + +int +_PyTime_Divide(_PyTime_t t, time_t *seconds, + unsigned int denominator, unsigned int *numerator, + _PyTime_round_t round) +{ + _PyTime_t div, q, r, q2; + /* FIXME: handle denominator > SEC_TO_NS */ + assert(0 < denominator && denominator < SEC_TO_NS); + + q = t / SEC_TO_NS; + r = t % SEC_TO_NS; + *seconds = (time_t)q; + if (q != (_PyTime_t)*seconds) { + _PyTime_overflow(); + return -1; + } + + /* FIXME: support round */ + div = SEC_TO_NS / denominator; + q2 = r / div; + assert(0 <= q2 && q2 < UINT_MAX); + *numerator = (unsigned int)q2; + return 0; +} + +static int +pygettimeofday(_PyTime_t *tp, _Py_clock_info_t *info, int raise) { #ifdef MS_WINDOWS FILETIME system_time; ULARGE_INTEGER large; - ULONGLONG microseconds; assert(info == NULL || raise); GetSystemTimeAsFileTime(&system_time); large.u.LowPart = system_time.dwLowDateTime; large.u.HighPart = system_time.dwHighDateTime; - /* 11,644,473,600,000,000: number of microseconds between + /* 11,644,473,600,000,000,000: number of nanoseconds between the 1st january 1601 and the 1st january 1970 (369 years + 89 leap days). */ - microseconds = large.QuadPart / 10 - 11644473600000000; - tp->tv_sec = microseconds / 1000000; - tp->tv_usec = microseconds % 1000000; + *tp = large.QuadPart * 100 - 11644473600000000000; if (info) { DWORD timeAdjustment, timeIncrement; BOOL isTimeAdjustmentDisabled, ok; @@ -50,6 +305,8 @@ pygettimeofday(_PyTime_timeval *tp, _Py_ int err; #ifdef HAVE_CLOCK_GETTIME struct timespec ts; +#else + struct timeval tv; #endif assert(info == NULL || raise); @@ -61,8 +318,8 @@ pygettimeofday(_PyTime_timeval *tp, _Py_ PyErr_SetFromErrno(PyExc_OSError); return -1; } - tp->tv_sec = ts.tv_sec; - tp->tv_usec = ts.tv_nsec / 1000; + if (_PyTime_FromTimespec(tp, &ts) < 0) + return -1; if (info) { struct timespec res; @@ -78,15 +335,17 @@ pygettimeofday(_PyTime_timeval *tp, _Py_ /* test gettimeofday() */ #ifdef GETTIMEOFDAY_NO_TZ - err = gettimeofday(tp); + err = gettimeofday(&tv); #else - err = gettimeofday(tp, (struct timezone *)NULL); + err = gettimeofday(&tv, (struct timezone *)NULL); #endif if (err) { if (raise) PyErr_SetFromErrno(PyExc_OSError); return -1; } + if (_PyTime_FromTimeval(tp, &tv) < 0) + return -1; if (info) { info->implementation = "gettimeofday()"; @@ -96,32 +355,33 @@ pygettimeofday(_PyTime_timeval *tp, _Py_ } #endif /* !HAVE_CLOCK_GETTIME */ #endif /* !MS_WINDOWS */ - assert(0 <= tp->tv_usec && tp->tv_usec < 1000 * 1000); return 0; } -void -_PyTime_gettimeofday(_PyTime_timeval *tp) +_PyTime_t +_PyTime_Get(void) { - if (pygettimeofday(tp, NULL, 0) < 0) { + _PyTime_t t; + if (pygettimeofday(&t, NULL, 0) < 0) { /* cannot happen, _PyTime_Init() checks that pygettimeofday() works */ assert(0); - tp->tv_sec = 0; - tp->tv_usec = 0; + t = 0; } + return t; } int -_PyTime_gettimeofday_info(_PyTime_timeval *tp, _Py_clock_info_t *info) +_PyTime_GetWithInfo(_PyTime_t *t, _Py_clock_info_t *info) { - return pygettimeofday(tp, info, 1); + return pygettimeofday(t, info, 1); } static int -pymonotonic(_PyTime_timeval *tp, _Py_clock_info_t *info, int raise) +pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise) { #ifdef Py_DEBUG - static _PyTime_timeval last = {0, -1}; + static int last_set = 0; + static _PyTime_t last = 0; #endif #if defined(MS_WINDOWS) static ULONGLONG (*GetTickCount64) (void) = NULL; @@ -160,8 +420,15 @@ pymonotonic(_PyTime_timeval *tp, _Py_clo result += ticks; } - tp->tv_sec = result / 1000; - tp->tv_usec = (result % 1000) * 1000; + *tp = result * MS_TO_NS; + if (*tp / MS_TO_NS != result) { + if (raise) { + _PyTime_overflow(); + return -1; + } + /* Hello, time traveler! */ + assert(0); + } if (info) { DWORD timeAdjustment, timeIncrement; @@ -193,13 +460,11 @@ pymonotonic(_PyTime_timeval *tp, _Py_clo time = mach_absolute_time(); - /* nanoseconds => microseconds */ - time /= 1000; /* apply timebase factor */ time *= timebase.numer; time /= timebase.denom; - tp->tv_sec = time / (1000 * 1000); - tp->tv_usec = time % (1000 * 1000); + + *tp = time; if (info) { info->implementation = "mach_absolute_time()"; @@ -225,8 +490,6 @@ pymonotonic(_PyTime_timeval *tp, _Py_clo PyErr_SetFromErrno(PyExc_OSError); return -1; } - tp->tv_sec = 0; - tp->tv_usec = 0; return -1; } @@ -241,173 +504,40 @@ pymonotonic(_PyTime_timeval *tp, _Py_clo } info->resolution = res.tv_sec + res.tv_nsec * 1e-9; } - tp->tv_sec = ts.tv_sec; - tp->tv_usec = ts.tv_nsec / 1000; + if (_PyTime_FromTimespec(tp, &ts) < 0) + return -1; #endif - assert(0 <= tp->tv_usec && tp->tv_usec < 1000 * 1000); #ifdef Py_DEBUG /* monotonic clock cannot go backward */ - assert(last.tv_usec == -1 - || tp->tv_sec > last.tv_sec - || (tp->tv_sec == last.tv_sec && tp->tv_usec >= last.tv_usec)); + assert(!last_set || last <= *tp); last = *tp; + last_set = 1; #endif return 0; } -void -_PyTime_monotonic(_PyTime_timeval *tp) +_PyTime_t +_PyTime_Monotonic(void) { - if (pymonotonic(tp, NULL, 0) < 0) { + _PyTime_t t; + if (pymonotonic(&t, NULL, 0) < 0) { /* cannot happen, _PyTime_Init() checks that pymonotonic() works */ assert(0); - tp->tv_sec = 0; - tp->tv_usec = 0; + t = 0; } + return t; } int -_PyTime_monotonic_info(_PyTime_timeval *tp, _Py_clock_info_t *info) +_PyTime_MonotonicWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) { return pymonotonic(tp, info, 1); } -static void -error_time_t_overflow(void) -{ - PyErr_SetString(PyExc_OverflowError, - "timestamp out of range for platform time_t"); -} - -time_t -_PyLong_AsTime_t(PyObject *obj) -{ -#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG - PY_LONG_LONG val; - val = PyLong_AsLongLong(obj); -#else - long val; - assert(sizeof(time_t) <= sizeof(long)); - val = PyLong_AsLong(obj); -#endif - if (val == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - error_time_t_overflow(); - return -1; - } - return (time_t)val; -} - -PyObject * -_PyLong_FromTime_t(time_t t) -{ -#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG - return PyLong_FromLongLong((PY_LONG_LONG)t); -#else - assert(sizeof(time_t) <= sizeof(long)); - return PyLong_FromLong((long)t); -#endif -} - -static int -_PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator, - double denominator, _PyTime_round_t round) -{ - assert(denominator <= LONG_MAX); - if (PyFloat_Check(obj)) { - double d, intpart, err; - /* volatile avoids unsafe optimization on float enabled by gcc -O3 */ - volatile double floatpart; - - d = PyFloat_AsDouble(obj); - floatpart = modf(d, &intpart); - if (floatpart < 0) { - floatpart = 1.0 + floatpart; - intpart -= 1.0; - } - - floatpart *= denominator; - if (round == _PyTime_ROUND_UP) { - if (intpart >= 0) { - floatpart = ceil(floatpart); - if (floatpart >= denominator) { - floatpart = 0.0; - intpart += 1.0; - } - } - else { - floatpart = floor(floatpart); - } - } - - *sec = (time_t)intpart; - err = intpart - (double)*sec; - if (err <= -1.0 || err >= 1.0) { - error_time_t_overflow(); - return -1; - } - - *numerator = (long)floatpart; - return 0; - } - else { - *sec = _PyLong_AsTime_t(obj); - if (*sec == (time_t)-1 && PyErr_Occurred()) - return -1; - *numerator = 0; - return 0; - } -} - -int -_PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round) -{ - if (PyFloat_Check(obj)) { - double d, intpart, err; - - d = PyFloat_AsDouble(obj); - if (round == _PyTime_ROUND_UP) { - if (d >= 0) - d = ceil(d); - else - d = floor(d); - } - (void)modf(d, &intpart); - - *sec = (time_t)intpart; - err = intpart - (double)*sec; - if (err <= -1.0 || err >= 1.0) { - error_time_t_overflow(); - return -1; - } - return 0; - } - else { - *sec = _PyLong_AsTime_t(obj); - if (*sec == (time_t)-1 && PyErr_Occurred()) - return -1; - return 0; - } -} - -int -_PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec, - _PyTime_round_t round) -{ - return _PyTime_ObjectToDenominator(obj, sec, nsec, 1e9, round); -} - -int -_PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec, - _PyTime_round_t round) -{ - return _PyTime_ObjectToDenominator(obj, sec, usec, 1e6, round); -} - int _PyTime_Init(void) { - _PyTime_timeval tv; + _PyTime_t t; #ifdef MS_WINDOWS winver.dwOSVersionInfoSize = sizeof(winver); @@ -418,11 +548,11 @@ int #endif /* ensure that the system clock works */ - if (_PyTime_gettimeofday_info(&tv, NULL) < 0) + if (_PyTime_GetWithInfo(&t, NULL) < 0) return -1; /* ensure that the operating system provides a monotonic clock */ - if (_PyTime_monotonic_info(&tv, NULL) < 0) + if (_PyTime_MonotonicWithInfo(&t, NULL) < 0) return -1; return 0; }