Skip to content

Commit c10d4db

Browse files
committed
Hold current module until interp-end
1 parent 97a6d0d commit c10d4db

File tree

2 files changed

+55
-126
lines changed

2 files changed

+55
-126
lines changed

Include/internal/pycore_interp_structs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,8 @@ struct _is {
947947
_Py_hashtable_t *closed_stackrefs_table;
948948
# endif
949949
#endif
950+
951+
void *datetime_module_state;
950952
};
951953

952954

Modules/_datetimemodule.c

Lines changed: 53 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ typedef struct {
4949

5050
/* The interned Unix epoch datetime instance */
5151
PyObject *epoch;
52+
53+
/* Reference to the interpreter's dict where the current module will be
54+
* reserved even after the referent dict becomes NULL at shutdown. */
55+
PyObject *interp_dict;
5256
} datetime_state;
5357

5458
/* The module has a fixed number of static objects, due to being exposed
@@ -133,18 +137,13 @@ get_current_module(PyInterpreterState *interp, int *p_reloading)
133137
if (dict == NULL) {
134138
goto error;
135139
}
136-
PyObject *ref = NULL;
137-
if (PyDict_GetItemRef(dict, INTERP_KEY, &ref) < 0) {
140+
if (PyDict_GetItemRef(dict, INTERP_KEY, &mod) < 0) {
138141
goto error;
139142
}
140-
if (ref != NULL) {
143+
if (mod != NULL) {
141144
reloading = 1;
142-
if (ref != Py_None) {
143-
(void)PyWeakref_GetRef(ref, &mod);
144-
if (mod == Py_None) {
145-
Py_CLEAR(mod);
146-
}
147-
Py_DECREF(ref);
145+
if (mod == Py_None) {
146+
mod = NULL;
148147
}
149148
}
150149
if (p_reloading != NULL) {
@@ -159,124 +158,59 @@ get_current_module(PyInterpreterState *interp, int *p_reloading)
159158

160159
static PyModuleDef datetimemodule;
161160

162-
static datetime_state *
163-
_get_current_state(PyObject **p_mod)
161+
static inline datetime_state *
162+
get_current_state()
164163
{
165164
PyInterpreterState *interp = PyInterpreterState_Get();
166-
PyObject *mod = get_current_module(interp, NULL);
167-
if (mod == NULL) {
168-
assert(!PyErr_Occurred());
169-
if (PyErr_Occurred()) {
170-
return NULL;
171-
}
172-
/* The static types can outlive the module,
173-
* so we must re-import the module. */
174-
mod = PyImport_ImportModule("_datetime");
175-
if (mod == NULL) {
176-
PyErr_Clear();
177-
/* Create a module at shutdown */
178-
PyObject *dict = PyInterpreterState_GetDict(interp);
179-
if (dict == NULL) {
180-
return NULL;
181-
}
182-
PyObject *spec;
183-
if (PyDict_GetItemStringRef(dict, "datetime_module_spec", &spec) != 1) {
184-
return NULL;
185-
}
186-
mod = PyModule_FromDefAndSpec(&datetimemodule, spec);
187-
if (mod == NULL) {
188-
Py_DECREF(spec);
189-
return NULL;
190-
}
191-
Py_DECREF(spec);
192-
193-
/* The module will be held by heaptypes. Prefer
194-
* it not to be stored in the interpreter's dict. */
195-
if (PyModule_ExecDef(mod, &datetimemodule) < 0) {
196-
return NULL;
197-
}
198-
}
199-
}
200-
datetime_state *st = get_module_state(mod);
201-
*p_mod = mod;
202-
return st;
165+
void *state = interp->datetime_module_state;
166+
assert(state != NULL);
167+
return (datetime_state *)state;
203168
}
204169

205-
#define GET_CURRENT_STATE(MOD_VAR) \
206-
_get_current_state(&MOD_VAR)
207-
#define RELEASE_CURRENT_STATE(ST_VAR, MOD_VAR) \
208-
Py_DECREF(MOD_VAR)
209-
210170
static int
211-
set_current_module(PyInterpreterState *interp, PyObject *mod)
171+
set_current_module(datetime_state *st,
172+
PyInterpreterState *interp, PyObject *mod)
212173
{
213174
assert(mod != NULL);
214-
PyObject *dict = PyInterpreterState_GetDict(interp);
175+
PyObject *dict = st->interp_dict;
215176
if (dict == NULL) {
216177
return -1;
217178
}
218-
PyObject *ref = PyWeakref_NewRef(mod, NULL);
219-
if (ref == NULL) {
220-
return -1;
221-
}
222-
if (PyDict_SetItem(dict, INTERP_KEY, ref) < 0) {
223-
Py_DECREF(ref);
224-
return -1;
225-
}
226-
Py_DECREF(ref);
227-
228-
/* Make the module spec remain in the interpreter's dict. Not required,
229-
* but reserve the new one for memory efficiency. */
230-
PyObject *mod_dict = PyModule_GetDict(mod);
231-
if (mod_dict == NULL) {
232-
return -1;
233-
}
234-
PyObject *spec;
235-
if (PyDict_GetItemRef(mod_dict, &_Py_ID(__spec__), &spec) != 1) {
236-
return -1;
237-
}
238-
if (PyDict_SetItemString(dict, "datetime_module_spec", spec) < 0) {
239-
Py_DECREF(spec);
179+
if (PyDict_SetItem(dict, INTERP_KEY, mod) < 0) {
240180
return -1;
241181
}
242-
Py_DECREF(spec);
182+
interp->datetime_module_state = st;
243183
return 0;
244184
}
245185

246186
static void
247-
clear_current_module(PyInterpreterState *interp, PyObject *expected)
187+
clear_current_module(datetime_state *st,
188+
PyInterpreterState *interp, PyObject *expected)
248189
{
249-
PyObject *exc = PyErr_GetRaisedException();
250-
251-
PyObject *dict = PyInterpreterState_GetDict(interp);
190+
PyObject *dict = st->interp_dict;
252191
if (dict == NULL) {
253-
goto error;
192+
return; /* Already cleared */
254193
}
255194

195+
PyObject *exc = PyErr_GetRaisedException();
196+
256197
if (expected != NULL) {
257-
PyObject *ref = NULL;
258-
if (PyDict_GetItemRef(dict, INTERP_KEY, &ref) < 0) {
198+
PyObject *current;
199+
if (PyDict_GetItemRef(dict, INTERP_KEY, &current) < 0) {
259200
goto error;
260201
}
261-
if (ref != NULL) {
262-
PyObject *current = NULL;
263-
int rc = PyWeakref_GetRef(ref, &current);
264-
/* We only need "current" for pointer comparison. */
265-
Py_XDECREF(current);
266-
Py_DECREF(ref);
267-
if (rc < 0) {
268-
goto error;
269-
}
270-
if (current != expected) {
271-
goto finally;
272-
}
202+
/* We only need "current" for pointer comparison. */
203+
Py_XDECREF(current);
204+
if (current != expected) {
205+
goto finally;
273206
}
274207
}
275208

276209
/* We use None to identify that the module was previously loaded. */
277210
if (PyDict_SetItem(dict, INTERP_KEY, Py_None) < 0) {
278211
goto error;
279212
}
213+
interp->datetime_module_state = NULL;
280214

281215
goto finally;
282216

@@ -2147,8 +2081,7 @@ delta_to_microseconds(PyDateTime_Delta *self)
21472081
PyObject *x3 = NULL;
21482082
PyObject *result = NULL;
21492083

2150-
PyObject *current_mod = NULL;
2151-
datetime_state *st = GET_CURRENT_STATE(current_mod);
2084+
datetime_state *st = get_current_state();
21522085

21532086
x1 = PyLong_FromLong(GET_TD_DAYS(self));
21542087
if (x1 == NULL)
@@ -2186,7 +2119,6 @@ delta_to_microseconds(PyDateTime_Delta *self)
21862119
Py_XDECREF(x1);
21872120
Py_XDECREF(x2);
21882121
Py_XDECREF(x3);
2189-
RELEASE_CURRENT_STATE(st, current_mod);
21902122
return result;
21912123
}
21922124

@@ -2226,8 +2158,7 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type)
22262158
PyObject *num = NULL;
22272159
PyObject *result = NULL;
22282160

2229-
PyObject *current_mod = NULL;
2230-
datetime_state *st = GET_CURRENT_STATE(current_mod);
2161+
datetime_state *st = get_current_state();
22312162

22322163
tuple = checked_divmod(pyus, CONST_US_PER_SECOND(st));
22332164
if (tuple == NULL) {
@@ -2272,7 +2203,6 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type)
22722203
Done:
22732204
Py_XDECREF(tuple);
22742205
Py_XDECREF(num);
2275-
RELEASE_CURRENT_STATE(st, current_mod);
22762206
return result;
22772207

22782208
BadDivmod:
@@ -2811,8 +2741,7 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw)
28112741
{
28122742
PyObject *self = NULL;
28132743

2814-
PyObject *current_mod = NULL;
2815-
datetime_state *st = GET_CURRENT_STATE(current_mod);
2744+
datetime_state *st = get_current_state();
28162745

28172746
/* Argument objects. */
28182747
PyObject *day = NULL;
@@ -2917,7 +2846,6 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw)
29172846
Py_DECREF(x);
29182847

29192848
Done:
2920-
RELEASE_CURRENT_STATE(st, current_mod);
29212849
return self;
29222850

29232851
#undef CLEANUP
@@ -3030,12 +2958,10 @@ delta_total_seconds(PyObject *op, PyObject *Py_UNUSED(dummy))
30302958
if (total_microseconds == NULL)
30312959
return NULL;
30322960

3033-
PyObject *current_mod = NULL;
3034-
datetime_state *st = GET_CURRENT_STATE(current_mod);
2961+
datetime_state *st = get_current_state();
30352962

30362963
total_seconds = PyNumber_TrueDivide(total_microseconds, CONST_US_PER_SECOND(st));
30372964

3038-
RELEASE_CURRENT_STATE(st, current_mod);
30392965
Py_DECREF(total_microseconds);
30402966
return total_seconds;
30412967
}
@@ -3813,12 +3739,10 @@ date_isocalendar(PyObject *self, PyObject *Py_UNUSED(dummy))
38133739
week = 0;
38143740
}
38153741

3816-
PyObject *current_mod = NULL;
3817-
datetime_state *st = GET_CURRENT_STATE(current_mod);
3742+
datetime_state *st = get_current_state();
38183743

38193744
PyObject *v = iso_calendar_date_new_impl(ISOCALENDAR_DATE_TYPE(st),
38203745
year, week + 1, day + 1);
3821-
RELEASE_CURRENT_STATE(st, current_mod);
38223746
if (v == NULL) {
38233747
return NULL;
38243748
}
@@ -6638,11 +6562,9 @@ local_timezone(PyDateTime_DateTime *utc_time)
66386562
PyObject *one_second;
66396563
PyObject *seconds;
66406564

6641-
PyObject *current_mod = NULL;
6642-
datetime_state *st = GET_CURRENT_STATE(current_mod);
6565+
datetime_state *st = get_current_state();
66436566

66446567
delta = datetime_subtract((PyObject *)utc_time, CONST_EPOCH(st));
6645-
RELEASE_CURRENT_STATE(st, current_mod);
66466568
if (delta == NULL)
66476569
return NULL;
66486570

@@ -6882,12 +6804,10 @@ datetime_timestamp(PyObject *op, PyObject *Py_UNUSED(dummy))
68826804
PyObject *result;
68836805

68846806
if (HASTZINFO(self) && self->tzinfo != Py_None) {
6885-
PyObject *current_mod = NULL;
6886-
datetime_state *st = GET_CURRENT_STATE(current_mod);
6807+
datetime_state *st = get_current_state();
68876808

68886809
PyObject *delta;
68896810
delta = datetime_subtract(op, CONST_EPOCH(st));
6890-
RELEASE_CURRENT_STATE(st, current_mod);
68916811
if (delta == NULL)
68926812
return NULL;
68936813
result = delta_total_seconds(delta, NULL);
@@ -7252,8 +7172,15 @@ create_timezone_from_delta(int days, int sec, int ms, int normalize)
72527172
*/
72537173

72547174
static int
7255-
init_state(datetime_state *st, PyObject *module, PyObject *old_module)
7175+
init_state(datetime_state *st,
7176+
PyInterpreterState *interp, PyObject *module, PyObject *old_module)
72567177
{
7178+
PyObject *dict = PyInterpreterState_GetDict(interp);
7179+
if (dict == NULL) {
7180+
return -1;
7181+
}
7182+
st->interp_dict = Py_NewRef(dict);
7183+
72577184
/* Each module gets its own heap types. */
72587185
#define ADD_TYPE(FIELD, SPEC, BASE) \
72597186
do { \
@@ -7272,6 +7199,7 @@ init_state(datetime_state *st, PyObject *module, PyObject *old_module)
72727199
assert(old_module != module);
72737200
datetime_state *st_old = get_module_state(old_module);
72747201
*st = (datetime_state){
7202+
.interp_dict = st->interp_dict,
72757203
.isocalendar_date_type = st->isocalendar_date_type,
72767204
.us_per_ms = Py_NewRef(st_old->us_per_ms),
72777205
.us_per_second = Py_NewRef(st_old->us_per_second),
@@ -7331,9 +7259,8 @@ init_state(datetime_state *st, PyObject *module, PyObject *old_module)
73317259
static int
73327260
traverse_state(datetime_state *st, visitproc visit, void *arg)
73337261
{
7334-
/* heap types */
73357262
Py_VISIT(st->isocalendar_date_type);
7336-
7263+
Py_VISIT(st->interp_dict);
73377264
return 0;
73387265
}
73397266

@@ -7349,6 +7276,7 @@ clear_state(datetime_state *st)
73497276
Py_CLEAR(st->us_per_week);
73507277
Py_CLEAR(st->seconds_per_day);
73517278
Py_CLEAR(st->epoch);
7279+
Py_CLEAR(st->interp_dict);
73527280
return 0;
73537281
}
73547282

@@ -7416,7 +7344,7 @@ _datetime_exec(PyObject *module)
74167344
}
74177345
}
74187346

7419-
if (init_state(st, module, old_module) < 0) {
7347+
if (init_state(st, interp, module, old_module) < 0) {
74207348
goto error;
74217349
}
74227350

@@ -7522,7 +7450,7 @@ _datetime_exec(PyObject *module)
75227450
static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
75237451
assert(DI100Y == days_before_year(100+1));
75247452

7525-
if (set_current_module(interp, module) < 0) {
7453+
if (set_current_module(st, interp, module) < 0) {
75267454
goto error;
75277455
}
75287456

@@ -7556,10 +7484,9 @@ static int
75567484
module_clear(PyObject *mod)
75577485
{
75587486
datetime_state *st = get_module_state(mod);
7559-
clear_state(st);
7560-
75617487
PyInterpreterState *interp = PyInterpreterState_Get();
7562-
clear_current_module(interp, mod);
7488+
clear_current_module(st, interp, mod);
7489+
clear_state(st);
75637490

75647491
// The runtime takes care of the static types for us.
75657492
// See _PyTypes_FiniExtTypes()..

0 commit comments

Comments
 (0)