# HG changeset patch # User Oleg Oshmyan # Date 1394810706 0 # Node ID d06e57b182a9af8e221b0f36ed16d84c3ed0a027 # Parent 756dacca888aa995b2a9bd9f4dff195dc30aaff8 Embraced clock_gettime and mach_absolute_time in _unix Also made _unix wall clock time reports more precise; this was necessitated by the main changes. diff -r 756dacca888a -r d06e57b182a9 upreckon/_unixmodule.cpp --- a/upreckon/_unixmodule.cpp Sun Jan 19 01:32:21 2014 +0000 +++ b/upreckon/_unixmodule.cpp Fri Mar 14 15:25:06 2014 +0000 @@ -1,4 +1,4 @@ -// Copyright (c) 2011 Chortos-2 +// Copyright (c) 2011-2014 Chortos-2 #include #include @@ -13,6 +13,10 @@ #include +#ifdef __APPLE__ +#include +#endif + #ifdef HAVE_SIGNAL_H #include #endif @@ -36,6 +40,10 @@ #include #endif +#ifdef HAVE_CLOCK_GETTIME +#include +#endif + #if !(defined __cplusplus) && !(defined bool) #ifdef HAVE_C99_BOOL #define bool _Bool @@ -74,12 +82,40 @@ #ifndef Py_PYTIME_H typedef struct timeval _PyTime_timeval; #ifndef GETTIMEOFDAY_NO_TZ -#define _PyTime_gettimeofday(tvp) gettimeofday((tvp), NULL) +#define _PyTime_gettimeofday(tvp) gettimeofday(tvp, NULL) #else -#define _PyTime_gettimeofday(tvp) gettimeofday((tvp)) +#define _PyTime_gettimeofday(tvp) gettimeofday(tvp) #endif #endif +static inline void timerget(_PyTime_timeval *tvp) +{ +#if defined HAVE_CLOCK_GETTIME && (defined CLOCK_MONOTONIC_RAW || defined CLOCK_HIGHRES || defined CLOCK_MONOTONIC) + struct timespec ts; +#ifdef CLOCK_MONOTONIC_RAW + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); +#elif defined CLOCK_HIGHRES + clock_gettime(CLOCK_HIGHRES, &ts); +#else + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif + tvp->tv_sec = ts.tv_sec; + tvp->tv_usec = ts.tv_nsec / 1000; +#elif defined __APPLE__ + static mach_timebase_info_data_t base; + if (!base.numer) + { + mach_timebase_info(&base); + base.denom *= 1000; + } + uint64_t t = mach_absolute_time() * base.numer / base.denom; + tvp->tv_sec = t / 1000000; + tvp->tv_usec = t % 1000000; +#else + _PyTime_gettimeofday(tvp); +#endif +} + #if PY_MAJOR_VERSION >= 3 #define PyInt_AsLong PyLong_AsLong #define PyInt_FromLong PyLong_FromLong @@ -479,7 +515,7 @@ { #endif spawn_errno = posix_spawnp(&pid, argv[0], NULL, NULL, argv, environ); - _PyTime_gettimeofday(&tvstart); + timerget(&tvstart); if (spawn_errno) { @@ -512,7 +548,7 @@ } else { - _PyTime_gettimeofday(&tvstart); + timerget(&tvstart); } } #endif @@ -529,7 +565,7 @@ while (wait(&status) != pid); #endif - _PyTime_gettimeofday(&tvend); + timerget(&tvend); #if defined HAVE_SYS_RESOURCE_H && !(defined HAVE_WAIT4 || defined HAVE_WAIT3) getrusage(RUSAGE_CHILDREN, &rusage); #endif @@ -673,32 +709,31 @@ static two_chars is_int(...); #endif -static inline bool timeval_to_attr(_PyTime_timeval *ptv, PyObject *obj, const char *attr) +static inline PyObject *timeval_to_obj(const _PyTime_timeval *ptv) { - PyObject *value; #ifdef __cplusplus // If tv_sec has an integral type and !tv_usec, try to create a Python int if (sizeof is_int(ptv->tv_sec) == sizeof(char) && !ptv->tv_usec) { if (ptv->tv_sec <= LONG_MAX) { - value = PyInt_FromLong(ptv->tv_sec); + return PyInt_FromLong(ptv->tv_sec); } // FIXME: signed/unsigned comparisons ruin everything #ifdef HAVE_LONG_LONG else// if (ptv->tv_sec <= ULLONG_MAX) { - value = PyLong_FromUnsignedLongLong(ptv->tv_sec); + return PyLong_FromUnsignedLongLong(ptv->tv_sec); } #else // else if (ptv->tv_sec <= ULONG_MAX) // { -// value = PyLong_FromUnsignedLong(ptv->tv_sec); +// return PyLong_FromUnsignedLong(ptv->tv_sec); // } //#endif else { - value = PyFloat_FromDouble(ptv->tv_sec); + return PyFloat_FromDouble(ptv->tv_sec); } // #endif @@ -708,8 +743,13 @@ #endif { // TODO: use decimal.Decimal or fractions.Fraction - value = PyFloat_FromDouble(ptv->tv_sec + ptv->tv_usec * 0.000001); + return PyFloat_FromDouble(ptv->tv_sec + ptv->tv_usec * 0.000001); } +} + +static inline bool timeval_to_attr(const _PyTime_timeval *ptv, PyObject *obj, const char *attr) +{ + PyObject *value = timeval_to_obj(ptv); if (value == NULL) { return false; @@ -724,8 +764,6 @@ /* TODO/FIXME: -* Replace timeval->timespec and select->pselect if pselect is available - (preferably only if pselect is not a wrapper around select). * File descriptors might be >= FD_SETSIZE? */ static PyObject *_unix_call(PyObject *self, PyObject *args, PyObject *kwds) @@ -739,7 +777,7 @@ size_t stats_read = 0; fd_set readfds; char c; - bool have_maxwalltime; + bool have_maxwalltime, wall_time_exceeded; if (kwds != NULL) { @@ -999,7 +1037,7 @@ if (have_maxwalltime) { - _PyTime_gettimeofday(&now); + timerget(&now); if (timercmp(&time_end, &now, <)) { timerclear(&timeout); @@ -1016,6 +1054,7 @@ close(c2ppipe[0]); TERM_TESTEE; Py_BLOCK_THREADS + timeval_to_attr(&now, testcase, "time_stopped"); Py_DECREF(testcase); PyErr_SetObject(WallTimeLimitExceeded, NULL); return NULL; @@ -1197,13 +1236,6 @@ return NULL; } - if (timerisset(&maxwalltime) && timercmp(&stats.walltime, &maxwalltime, >)) - { - Py_DECREF(testcase); - PyErr_SetObject(WallTimeLimitExceeded, NULL); - return NULL; - } - obj = PyInt_FromLong(0); if (obj == NULL) { @@ -1217,8 +1249,9 @@ } Py_DECREF(obj); + wall_time_exceeded = timerisset(&maxwalltime) && timercmp(&stats.walltime, &maxwalltime, >); #if defined HAVE_SYS_RESOURCE_H || defined HAVE_WAIT4 || defined HAVE_WAIT3 - if (timerisset(&maxcputime) || !timerisset(&maxwalltime)) + if (!wall_time_exceeded && (timerisset(&maxcputime) || !timerisset(&maxwalltime))) { PyObject *cputls; if (!timeval_to_attr(&stats.cputime, testcase, "time_stopped")) @@ -1253,6 +1286,12 @@ Py_DECREF(testcase); return NULL; } + if (wall_time_exceeded) + { + Py_DECREF(testcase); + PyErr_SetObject(WallTimeLimitExceeded, NULL); + return NULL; + } } #if defined HAVE_SYS_RESOURCE_H || defined HAVE_WAIT4 || defined HAVE_WAIT3 @@ -1276,6 +1315,13 @@ Py_RETURN_NONE; } +static PyObject *_unix_clock(PyObject *self) +{ + _PyTime_timeval tv; + timerget(&tv); + return timeval_to_obj(&tv); +} + static PyObject *_unix_pause(PyObject *self) { #ifdef HAVE_TERMIOS_H @@ -1300,6 +1346,7 @@ static PyMethodDef _unixMethods[] = { { "call", (PyCFunction) _unix_call, METH_VARARGS | METH_KEYWORDS, "Call a process." }, + { "clock", (PyCFunction) _unix_clock, METH_NOARGS, "Return the current time in seconds since an unspecified reference point." }, { "pause", (PyCFunction) _unix_pause, METH_NOARGS, "Block until a key is pressed." }, { NULL } };