Skip to content

Commit 17f268a

Browse files
authored
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.
1 parent f389b37 commit 17f268a

File tree

1 file changed

+81
-37
lines changed

1 file changed

+81
-37
lines changed

Modules/timemodule.c

Lines changed: 81 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "Python.h"
44
#include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH
5+
#include "pycore_moduleobject.h" // _PyModule_GetState()
56
#include "pycore_namespace.h" // _PyNamespace_New()
67

78
#include <ctype.h>
@@ -64,6 +65,19 @@
6465
static int pysleep(_PyTime_t timeout);
6566

6667

68+
typedef struct {
69+
PyTypeObject *struct_time_type;
70+
} time_module_state;
71+
72+
static inline time_module_state*
73+
get_time_state(PyObject *module)
74+
{
75+
void *state = _PyModule_GetState(module);
76+
assert(state != NULL);
77+
return (time_module_state *)state;
78+
}
79+
80+
6781
static PyObject*
6882
_PyFloat_FromPyTime(_PyTime_t t)
6983
{
@@ -405,9 +419,6 @@ static PyStructSequence_Desc struct_time_type_desc = {
405419
9,
406420
};
407421

408-
static int initialized;
409-
static PyTypeObject StructTimeType;
410-
411422
#if defined(MS_WINDOWS)
412423
#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
413424
#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002
@@ -417,13 +428,13 @@ static DWORD timer_flags = (DWORD)-1;
417428
#endif
418429

419430
static PyObject *
420-
tmtotuple(struct tm *p
431+
tmtotuple(time_module_state *state, struct tm *p
421432
#ifndef HAVE_STRUCT_TM_TM_ZONE
422433
, const char *zone, time_t gmtoff
423434
#endif
424435
)
425436
{
426-
PyObject *v = PyStructSequence_New(&StructTimeType);
437+
PyObject *v = PyStructSequence_New(state->struct_time_type);
427438
if (v == NULL)
428439
return NULL;
429440

@@ -480,7 +491,7 @@ parse_time_t_args(PyObject *args, const char *format, time_t *pwhen)
480491
}
481492

482493
static PyObject *
483-
time_gmtime(PyObject *self, PyObject *args)
494+
time_gmtime(PyObject *module, PyObject *args)
484495
{
485496
time_t when;
486497
struct tm buf;
@@ -491,10 +502,12 @@ time_gmtime(PyObject *self, PyObject *args)
491502
errno = 0;
492503
if (_PyTime_gmtime(when, &buf) != 0)
493504
return NULL;
505+
506+
time_module_state *state = get_time_state(module);
494507
#ifdef HAVE_STRUCT_TM_TM_ZONE
495-
return tmtotuple(&buf);
508+
return tmtotuple(state, &buf);
496509
#else
497-
return tmtotuple(&buf, "UTC", 0);
510+
return tmtotuple(state, &buf, "UTC", 0);
498511
#endif
499512
}
500513

@@ -522,7 +535,7 @@ If the platform supports the tm_gmtoff and tm_zone, they are available as\n\
522535
attributes only.");
523536

524537
static PyObject *
525-
time_localtime(PyObject *self, PyObject *args)
538+
time_localtime(PyObject *module, PyObject *args)
526539
{
527540
time_t when;
528541
struct tm buf;
@@ -531,16 +544,18 @@ time_localtime(PyObject *self, PyObject *args)
531544
return NULL;
532545
if (_PyTime_localtime(when, &buf) != 0)
533546
return NULL;
547+
548+
time_module_state *state = get_time_state(module);
534549
#ifdef HAVE_STRUCT_TM_TM_ZONE
535-
return tmtotuple(&buf);
550+
return tmtotuple(state, &buf);
536551
#else
537552
{
538553
struct tm local = buf;
539554
char zone[100];
540555
time_t gmtoff;
541556
strftime(zone, sizeof(zone), "%Z", &buf);
542557
gmtoff = timegm(&buf) - when;
543-
return tmtotuple(&local, zone, gmtoff);
558+
return tmtotuple(state, &local, zone, gmtoff);
544559
}
545560
#endif
546561
}
@@ -560,7 +575,8 @@ When 'seconds' is not passed in, convert the current time instead.");
560575
* an exception and return 0 on error.
561576
*/
562577
static int
563-
gettmarg(PyObject *args, struct tm *p, const char *format)
578+
gettmarg(time_module_state *state, PyObject *args,
579+
struct tm *p, const char *format)
564580
{
565581
int y;
566582

@@ -588,7 +604,7 @@ gettmarg(PyObject *args, struct tm *p, const char *format)
588604
p->tm_wday = (p->tm_wday + 1) % 7;
589605
p->tm_yday--;
590606
#ifdef HAVE_STRUCT_TM_TM_ZONE
591-
if (Py_IS_TYPE(args, &StructTimeType)) {
607+
if (Py_IS_TYPE(args, state->struct_time_type)) {
592608
PyObject *item;
593609
item = PyStructSequence_GET_ITEM(args, 9);
594610
if (item != Py_None) {
@@ -729,7 +745,7 @@ the C library strftime function.\n"
729745
#endif
730746

731747
static PyObject *
732-
time_strftime(PyObject *self, PyObject *args)
748+
time_strftime(PyObject *module, PyObject *args)
733749
{
734750
PyObject *tup = NULL;
735751
struct tm buf;
@@ -753,12 +769,13 @@ time_strftime(PyObject *self, PyObject *args)
753769
if (!PyArg_ParseTuple(args, "U|O:strftime", &format_arg, &tup))
754770
return NULL;
755771

772+
time_module_state *state = get_time_state(module);
756773
if (tup == NULL) {
757774
time_t tt = time(NULL);
758775
if (_PyTime_localtime(tt, &buf) != 0)
759776
return NULL;
760777
}
761-
else if (!gettmarg(tup, &buf,
778+
else if (!gettmarg(state, tup, &buf,
762779
"iiiiiiiii;strftime(): illegal time tuple argument") ||
763780
!checktm(&buf))
764781
{
@@ -941,19 +958,21 @@ _asctime(struct tm *timeptr)
941958
}
942959

943960
static PyObject *
944-
time_asctime(PyObject *self, PyObject *args)
961+
time_asctime(PyObject *module, PyObject *args)
945962
{
946963
PyObject *tup = NULL;
947964
struct tm buf;
948965

949966
if (!PyArg_UnpackTuple(args, "asctime", 0, 1, &tup))
950967
return NULL;
968+
969+
time_module_state *state = get_time_state(module);
951970
if (tup == NULL) {
952971
time_t tt = time(NULL);
953972
if (_PyTime_localtime(tt, &buf) != 0)
954973
return NULL;
955974
}
956-
else if (!gettmarg(tup, &buf,
975+
else if (!gettmarg(state, tup, &buf,
957976
"iiiiiiiii;asctime(): illegal time tuple argument") ||
958977
!checktm(&buf))
959978
{
@@ -990,12 +1009,13 @@ not present, current time as returned by localtime() is used.");
9901009

9911010
#ifdef HAVE_MKTIME
9921011
static PyObject *
993-
time_mktime(PyObject *self, PyObject *tm_tuple)
1012+
time_mktime(PyObject *module, PyObject *tm_tuple)
9941013
{
9951014
struct tm tm;
9961015
time_t tt;
9971016

998-
if (!gettmarg(tm_tuple, &tm,
1017+
time_module_state *state = get_time_state(module);
1018+
if (!gettmarg(state, tm_tuple, &tm,
9991019
"iiiiiiiii;mktime(): illegal time tuple argument"))
10001020
{
10011021
return NULL;
@@ -1888,6 +1908,7 @@ if it is -1, mktime() should guess based on the date and time.\n");
18881908
static int
18891909
time_exec(PyObject *module)
18901910
{
1911+
time_module_state *state = get_time_state(module);
18911912
#if defined(__APPLE__) && defined(HAVE_CLOCK_GETTIME)
18921913
if (HAVE_CLOCK_GETTIME_RUNTIME) {
18931914
/* pass: ^^^ cannot use '!' here */
@@ -2001,21 +2022,18 @@ time_exec(PyObject *module)
20012022

20022023
#endif /* defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_CLOCK_GETRES) */
20032024

2004-
if (!initialized) {
2005-
if (PyStructSequence_InitType2(&StructTimeType,
2006-
&struct_time_type_desc) < 0) {
2007-
return -1;
2008-
}
2009-
}
20102025
if (PyModule_AddIntConstant(module, "_STRUCT_TM_ITEMS", 11)) {
20112026
return -1;
20122027
}
2013-
Py_INCREF(&StructTimeType);
2014-
if (PyModule_AddObject(module, "struct_time", (PyObject*) &StructTimeType)) {
2015-
Py_DECREF(&StructTimeType);
2028+
2029+
// struct_time type
2030+
state->struct_time_type = PyStructSequence_NewType(&struct_time_type_desc);
2031+
if (state->struct_time_type == NULL) {
2032+
return -1;
2033+
}
2034+
if (PyModule_AddType(module, state->struct_time_type)) {
20162035
return -1;
20172036
}
2018-
initialized = 1;
20192037

20202038
#if defined(__linux__) && !defined(__GLIBC__)
20212039
struct tm tm;
@@ -2044,21 +2062,47 @@ time_exec(PyObject *module)
20442062
return 0;
20452063
}
20462064

2065+
2066+
static int
2067+
time_module_traverse(PyObject *module, visitproc visit, void *arg)
2068+
{
2069+
time_module_state *state = get_time_state(module);
2070+
Py_VISIT(state->struct_time_type);
2071+
return 0;
2072+
}
2073+
2074+
2075+
static int
2076+
time_module_clear(PyObject *module)
2077+
{
2078+
time_module_state *state = get_time_state(module);
2079+
Py_CLEAR(state->struct_time_type);
2080+
return 0;
2081+
}
2082+
2083+
2084+
static void
2085+
time_module_free(void *module)
2086+
{
2087+
time_module_clear((PyObject *)module);
2088+
}
2089+
2090+
20472091
static struct PyModuleDef_Slot time_slots[] = {
20482092
{Py_mod_exec, time_exec},
20492093
{0, NULL}
20502094
};
20512095

20522096
static struct PyModuleDef timemodule = {
20532097
PyModuleDef_HEAD_INIT,
2054-
"time",
2055-
module_doc,
2056-
0,
2057-
time_methods,
2058-
time_slots,
2059-
NULL,
2060-
NULL,
2061-
NULL
2098+
.m_name = "time",
2099+
.m_doc = module_doc,
2100+
.m_size = sizeof(time_module_state),
2101+
.m_methods = time_methods,
2102+
.m_slots = time_slots,
2103+
.m_traverse = time_module_traverse,
2104+
.m_clear = time_module_clear,
2105+
.m_free = time_module_free,
20622106
};
20632107

20642108
PyMODINIT_FUNC

0 commit comments

Comments
 (0)