gh-110850: Add PyTime_t C API (GH-115215)

* gh-110850: Add PyTime_t C API

Add PyTime_t API:

* PyTime_t type.
* PyTime_MIN and PyTime_MAX constants.
* PyTime_AsSecondsDouble(), PyTime_Monotonic(),
  PyTime_PerfCounter() and PyTime_GetSystemClock() functions.

Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
Petr Viktorin 2024-02-12 18:13:10 +01:00 • committed by GitHub
parent c39272e143
commit 879f4546bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 448 additions and 114 deletions

View file

@ -162,7 +162,7 @@
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/bytearray.c _testcapi/bytes.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/pyos.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c _testcapi/sys.c _testcapi/hash.c
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/bytearray.c _testcapi/bytes.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/pyos.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c _testcapi/sys.c _testcapi/hash.c _testcapi/time.c
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c

View file

@ -262,7 +262,7 @@ random_seed_urandom(RandomObject *self)
static void
random_seed_time_pid(RandomObject *self)
{
_PyTime_t now;
PyTime_t now;
uint32_t key[5];
now = _PyTime_GetSystemClock();

View file

@ -59,6 +59,7 @@ int _PyTestCapi_Init_Immortal(PyObject *module);
int _PyTestCapi_Init_GC(PyObject *module);
int _PyTestCapi_Init_Sys(PyObject *module);
int _PyTestCapi_Init_Hash(PyObject *module);
int _PyTestCapi_Init_Time(PyObject *module);
int _PyTestCapi_Init_VectorcallLimited(PyObject *module);
int _PyTestCapi_Init_HeaptypeRelative(PyObject *module);

105
Modules/_testcapi/time.c Normal file
View file

@ -0,0 +1,105 @@
#include "parts.h"
static int
pytime_from_nanoseconds(PyTime_t *tp, PyObject *obj)
{
if (!PyLong_Check(obj)) {
PyErr_Format(PyExc_TypeError, "expect int, got %s",
Py_TYPE(obj)->tp_name);
return -1;
}
long long nsec = PyLong_AsLongLong(obj);
if (nsec == -1 && PyErr_Occurred()) {
return -1;
}
Py_BUILD_ASSERT(sizeof(long long) == sizeof(PyTime_t));
*tp = (PyTime_t)nsec;
return 0;
}
static PyObject *
test_pytime_assecondsdouble(PyObject *Py_UNUSED(self), PyObject *args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O", &obj)) {
return NULL;
}
PyTime_t ts;
if (pytime_from_nanoseconds(&ts, obj) < 0) {
return NULL;
}
double d = PyTime_AsSecondsDouble(ts);
return PyFloat_FromDouble(d);
}
static PyObject*
pytime_as_float(PyTime_t t)
{
return PyFloat_FromDouble(PyTime_AsSecondsDouble(t));
}
static PyObject*
test_pytime_monotonic(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
{
PyTime_t t;
if (PyTime_Monotonic(&t) < 0) {
return NULL;
}
return pytime_as_float(t);
}
static PyObject*
test_pytime_perf_counter(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
{
PyTime_t t;
if (PyTime_PerfCounter(&t) < 0) {
return NULL;
}
return pytime_as_float(t);
}
static PyObject*
test_pytime_time(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
{
PyTime_t t;
if (PyTime_Time(&t) < 0) {
printf("ERR! %d\n", (int)t);
return NULL;
}
printf("... %d\n", (int)t);
return pytime_as_float(t);
}
static PyMethodDef test_methods[] = {
{"PyTime_AsSecondsDouble", test_pytime_assecondsdouble, METH_VARARGS},
{"PyTime_Monotonic", test_pytime_monotonic, METH_NOARGS},
{"PyTime_PerfCounter", test_pytime_perf_counter, METH_NOARGS},
{"PyTime_Time", test_pytime_time, METH_NOARGS},
{NULL},
};
int
_PyTestCapi_Init_Time(PyObject *m)
{
if (PyModule_AddFunctions(m, test_methods) < 0) {
return -1;
}
Py_BUILD_ASSERT(sizeof(long long) == sizeof(PyTime_t));
if (PyModule_AddObject(m, "PyTime_MIN", PyLong_FromLongLong(PyTime_MIN)) < 0) {
return 1;
}
if (PyModule_AddObject(m, "PyTime_MAX", PyLong_FromLongLong(PyTime_MAX)) < 0) {
return 1;
}
return 0;
}

View file

@ -4107,6 +4107,9 @@ PyInit__testcapi(void)
if (_PyTestCapi_Init_Hash(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Time(m) < 0) {
return NULL;
}
PyState_AddModule(m, &_testcapimodule);
return m;

View file

@ -52,21 +52,6 @@ test_pytime_fromsecondsobject(PyObject *self, PyObject *args)
return _PyTime_AsNanosecondsObject(ts);
}
static PyObject *
test_pytime_assecondsdouble(PyObject *self, PyObject *args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O", &obj)) {
return NULL;
}
_PyTime_t ts;
if (_PyTime_FromNanosecondsObject(&ts, obj) < 0) {
return NULL;
}
double d = _PyTime_AsSecondsDouble(ts);
return PyFloat_FromDouble(d);
}
static PyObject *
test_PyTime_AsTimeval(PyObject *self, PyObject *args)
{
@ -254,7 +239,6 @@ test_pytime_object_to_timespec(PyObject *self, PyObject *args)
static PyMethodDef TestMethods[] = {
{"_PyTime_AsMicroseconds", test_PyTime_AsMicroseconds, METH_VARARGS},
{"_PyTime_AsMilliseconds", test_PyTime_AsMilliseconds, METH_VARARGS},
{"_PyTime_AsSecondsDouble", test_pytime_assecondsdouble, METH_VARARGS},
#ifdef HAVE_CLOCK_GETTIME
{"_PyTime_AsTimespec", test_PyTime_AsTimespec, METH_VARARGS},
{"_PyTime_AsTimespec_clamp", test_PyTime_AsTimespec_clamp, METH_VARARGS},