diff options
author | Victor Stinner <vstinner@python.org> | 2022-01-21 01:52:43 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-21 01:52:43 (GMT) |
commit | 17f268a4ae6190b2659c89c6f32ad2d006e0e3c8 (patch) | |
tree | a823df3bef317346fdd1ae1fdc5b5095ad31133e /Modules/timemodule.c | |
parent | f389b37fb1cebe7ed66331cdd373a014695261f6 (diff) | |
download | cpython-17f268a4ae6190b2659c89c6f32ad2d006e0e3c8.zip cpython-17f268a4ae6190b2659c89c6f32ad2d006e0e3c8.tar.gz cpython-17f268a4ae6190b2659c89c6f32ad2d006e0e3c8.tar.bz2 |
bpo-46417: time module uses PyStructSequence_NewType() (GH-30734)
The time module now creates its struct_time type as a heap
type using PyStructSequence_NewType(), rather than using a static
type.
* Add a module state to the time module: add traverse, clear and free
functions.
* Use PyModule_AddType().
* Remove the 'initialized' variable.
Diffstat (limited to 'Modules/timemodule.c')
-rw-r--r-- | Modules/timemodule.c | 118 |
1 files changed, 81 insertions, 37 deletions
diff --git a/Modules/timemodule.c b/Modules/timemodule.c index dd81d35..35b8e14 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH +#include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_namespace.h" // _PyNamespace_New() #include <ctype.h> @@ -64,6 +65,19 @@ static int pysleep(_PyTime_t timeout); +typedef struct { + PyTypeObject *struct_time_type; +} time_module_state; + +static inline time_module_state* +get_time_state(PyObject *module) +{ + void *state = _PyModule_GetState(module); + assert(state != NULL); + return (time_module_state *)state; +} + + static PyObject* _PyFloat_FromPyTime(_PyTime_t t) { @@ -405,9 +419,6 @@ static PyStructSequence_Desc struct_time_type_desc = { 9, }; -static int initialized; -static PyTypeObject StructTimeType; - #if defined(MS_WINDOWS) #ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION #define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002 @@ -417,13 +428,13 @@ static DWORD timer_flags = (DWORD)-1; #endif static PyObject * -tmtotuple(struct tm *p +tmtotuple(time_module_state *state, struct tm *p #ifndef HAVE_STRUCT_TM_TM_ZONE , const char *zone, time_t gmtoff #endif ) { - PyObject *v = PyStructSequence_New(&StructTimeType); + PyObject *v = PyStructSequence_New(state->struct_time_type); if (v == NULL) return NULL; @@ -480,7 +491,7 @@ parse_time_t_args(PyObject *args, const char *format, time_t *pwhen) } static PyObject * -time_gmtime(PyObject *self, PyObject *args) +time_gmtime(PyObject *module, PyObject *args) { time_t when; struct tm buf; @@ -491,10 +502,12 @@ time_gmtime(PyObject *self, PyObject *args) errno = 0; if (_PyTime_gmtime(when, &buf) != 0) return NULL; + + time_module_state *state = get_time_state(module); #ifdef HAVE_STRUCT_TM_TM_ZONE - return tmtotuple(&buf); + return tmtotuple(state, &buf); #else - return tmtotuple(&buf, "UTC", 0); + return tmtotuple(state, &buf, "UTC", 0); #endif } @@ -522,7 +535,7 @@ If the platform supports the tm_gmtoff and tm_zone, they are available as\n\ attributes only."); static PyObject * -time_localtime(PyObject *self, PyObject *args) +time_localtime(PyObject *module, PyObject *args) { time_t when; struct tm buf; @@ -531,8 +544,10 @@ time_localtime(PyObject *self, PyObject *args) return NULL; if (_PyTime_localtime(when, &buf) != 0) return NULL; + + time_module_state *state = get_time_state(module); #ifdef HAVE_STRUCT_TM_TM_ZONE - return tmtotuple(&buf); + return tmtotuple(state, &buf); #else { struct tm local = buf; @@ -540,7 +555,7 @@ time_localtime(PyObject *self, PyObject *args) time_t gmtoff; strftime(zone, sizeof(zone), "%Z", &buf); gmtoff = timegm(&buf) - when; - return tmtotuple(&local, zone, gmtoff); + return tmtotuple(state, &local, zone, gmtoff); } #endif } @@ -560,7 +575,8 @@ When 'seconds' is not passed in, convert the current time instead."); * an exception and return 0 on error. */ static int -gettmarg(PyObject *args, struct tm *p, const char *format) +gettmarg(time_module_state *state, PyObject *args, + struct tm *p, const char *format) { int y; @@ -588,7 +604,7 @@ gettmarg(PyObject *args, struct tm *p, const char *format) p->tm_wday = (p->tm_wday + 1) % 7; p->tm_yday--; #ifdef HAVE_STRUCT_TM_TM_ZONE - if (Py_IS_TYPE(args, &StructTimeType)) { + if (Py_IS_TYPE(args, state->struct_time_type)) { PyObject *item; item = PyStructSequence_GET_ITEM(args, 9); if (item != Py_None) { @@ -729,7 +745,7 @@ the C library strftime function.\n" #endif static PyObject * -time_strftime(PyObject *self, PyObject *args) +time_strftime(PyObject *module, PyObject *args) { PyObject *tup = NULL; struct tm buf; @@ -753,12 +769,13 @@ time_strftime(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "U|O:strftime", &format_arg, &tup)) return NULL; + time_module_state *state = get_time_state(module); if (tup == NULL) { time_t tt = time(NULL); if (_PyTime_localtime(tt, &buf) != 0) return NULL; } - else if (!gettmarg(tup, &buf, + else if (!gettmarg(state, tup, &buf, "iiiiiiiii;strftime(): illegal time tuple argument") || !checktm(&buf)) { @@ -941,19 +958,21 @@ _asctime(struct tm *timeptr) } static PyObject * -time_asctime(PyObject *self, PyObject *args) +time_asctime(PyObject *module, PyObject *args) { PyObject *tup = NULL; struct tm buf; if (!PyArg_UnpackTuple(args, "asctime", 0, 1, &tup)) return NULL; + + time_module_state *state = get_time_state(module); if (tup == NULL) { time_t tt = time(NULL); if (_PyTime_localtime(tt, &buf) != 0) return NULL; } - else if (!gettmarg(tup, &buf, + else if (!gettmarg(state, tup, &buf, "iiiiiiiii;asctime(): illegal time tuple argument") || !checktm(&buf)) { @@ -990,12 +1009,13 @@ not present, current time as returned by localtime() is used."); #ifdef HAVE_MKTIME static PyObject * -time_mktime(PyObject *self, PyObject *tm_tuple) +time_mktime(PyObject *module, PyObject *tm_tuple) { struct tm tm; time_t tt; - if (!gettmarg(tm_tuple, &tm, + time_module_state *state = get_time_state(module); + if (!gettmarg(state, tm_tuple, &tm, "iiiiiiiii;mktime(): illegal time tuple argument")) { return NULL; @@ -1888,6 +1908,7 @@ if it is -1, mktime() should guess based on the date and time.\n"); static int time_exec(PyObject *module) { + time_module_state *state = get_time_state(module); #if defined(__APPLE__) && defined(HAVE_CLOCK_GETTIME) if (HAVE_CLOCK_GETTIME_RUNTIME) { /* pass: ^^^ cannot use '!' here */ @@ -2001,21 +2022,18 @@ time_exec(PyObject *module) #endif /* defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_CLOCK_GETRES) */ - if (!initialized) { - if (PyStructSequence_InitType2(&StructTimeType, - &struct_time_type_desc) < 0) { - return -1; - } - } if (PyModule_AddIntConstant(module, "_STRUCT_TM_ITEMS", 11)) { return -1; } - Py_INCREF(&StructTimeType); - if (PyModule_AddObject(module, "struct_time", (PyObject*) &StructTimeType)) { - Py_DECREF(&StructTimeType); + + // struct_time type + state->struct_time_type = PyStructSequence_NewType(&struct_time_type_desc); + if (state->struct_time_type == NULL) { + return -1; + } + if (PyModule_AddType(module, state->struct_time_type)) { return -1; } - initialized = 1; #if defined(__linux__) && !defined(__GLIBC__) struct tm tm; @@ -2044,6 +2062,32 @@ time_exec(PyObject *module) return 0; } + +static int +time_module_traverse(PyObject *module, visitproc visit, void *arg) +{ + time_module_state *state = get_time_state(module); + Py_VISIT(state->struct_time_type); + return 0; +} + + +static int +time_module_clear(PyObject *module) +{ + time_module_state *state = get_time_state(module); + Py_CLEAR(state->struct_time_type); + return 0; +} + + +static void +time_module_free(void *module) +{ + time_module_clear((PyObject *)module); +} + + static struct PyModuleDef_Slot time_slots[] = { {Py_mod_exec, time_exec}, {0, NULL} @@ -2051,14 +2095,14 @@ static struct PyModuleDef_Slot time_slots[] = { static struct PyModuleDef timemodule = { PyModuleDef_HEAD_INIT, - "time", - module_doc, - 0, - time_methods, - time_slots, - NULL, - NULL, - NULL + .m_name = "time", + .m_doc = module_doc, + .m_size = sizeof(time_module_state), + .m_methods = time_methods, + .m_slots = time_slots, + .m_traverse = time_module_traverse, + .m_clear = time_module_clear, + .m_free = time_module_free, }; PyMODINIT_FUNC |