[Python-checkins] bpo-46417: time module uses PyStructSequence_NewType() (GH-30734)

vstinner webhook-mailer at python.org
Thu Jan 20 20:52:51 EST 2022


https://github.com/python/cpython/commit/17f268a4ae6190b2659c89c6f32ad2d006e0e3c8
commit: 17f268a4ae6190b2659c89c6f32ad2d006e0e3c8
branch: main
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2022年01月21日T02:52:43+01:00
summary:
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.
files:
M Modules/timemodule.c
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
index dd81d352fd713..35b8e14e82711 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


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /