summaryrefslogtreecommitdiffstats
path: root/Modules/timemodule.c
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2022-01-21 01:52:43 (GMT)
committerGitHub <noreply@github.com>2022-01-21 01:52:43 (GMT)
commit17f268a4ae6190b2659c89c6f32ad2d006e0e3c8 (patch)
treea823df3bef317346fdd1ae1fdc5b5095ad31133e /Modules/timemodule.c
parentf389b37fb1cebe7ed66331cdd373a014695261f6 (diff)
downloadcpython-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.c118
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