Skip to content

bpo-46417: time module uses PyStructSequence_NewType() #30734

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 21, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 81 additions & 37 deletions Modules/timemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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
}

Expand Down Expand Up @@ -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;
Expand All @@ -531,16 +544,18 @@ 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;
char zone[100];
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
}
Expand All @@ -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;

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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))
{
Expand Down Expand Up @@ -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))
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -2044,21 +2062,47 @@ 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}
};

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
Expand Down