1
2 /* Testing module for single-phase initialization of extension modules
3 */
4 #ifndef Py_BUILD_CORE_BUILTIN
5 # define Py_BUILD_CORE_MODULE 1
6 #endif
7
8 //#include <time.h>
9 #include "Python.h"
10 #include "pycore_namespace.h" // _PyNamespace_New()
11
12
13 typedef struct {
14 _PyTime_t initialized;
15 PyObject *error;
16 PyObject *int_const;
17 PyObject *str_const;
18 } module_state;
19
20
21 /* Process-global state is only used by _testsinglephase
22 since it's the only one that does not support re-init. */
23 static struct {
24 int initialized_count;
25 module_state module;
26 } global_state = {
27
28 #define NOT_INITIALIZED -1
29 .initialized_count = NOT_INITIALIZED,
30 };
31
32 static void clear_state(module_state *state);
33
34 static void
35 clear_global_state(void)
36 {
37 clear_state(&global_state.module);
38 global_state.initialized_count = NOT_INITIALIZED;
39 }
40
41
42 static inline module_state *
43 get_module_state(PyObject *module)
44 {
45 PyModuleDef *def = PyModule_GetDef(module);
46 if (def->m_size == -1) {
47 return &global_state.module;
48 }
49 else if (def->m_size == 0) {
50 return NULL;
51 }
52 else {
53 module_state *state = (module_state*)PyModule_GetState(module);
54 assert(state != NULL);
55 return state;
56 }
57 }
58
59 static void
60 clear_state(module_state *state)
61 {
62 state->initialized = 0;
63 Py_CLEAR(state->error);
64 Py_CLEAR(state->int_const);
65 Py_CLEAR(state->str_const);
66 }
67
68 static int
69 _set_initialized(_PyTime_t *initialized)
70 {
71 /* We go strictly monotonic to ensure each time is unique. */
72 _PyTime_t prev;
73 if (_PyTime_GetMonotonicClockWithInfo(&prev, NULL) != 0) {
74 return -1;
75 }
76 /* We do a busy sleep since the interval should be super short. */
77 _PyTime_t t;
78 do {
79 if (_PyTime_GetMonotonicClockWithInfo(&t, NULL) != 0) {
80 return -1;
81 }
82 } while (t == prev);
83
84 *initialized = t;
85 return 0;
86 }
87
88 static int
89 init_state(module_state *state)
90 {
91 assert(state->initialized == 0 &&
92 state->error == NULL &&
93 state->int_const == NULL &&
94 state->str_const == NULL);
95
96 if (_set_initialized(&state->initialized) != 0) {
97 goto error;
98 }
99 assert(state->initialized > 0);
100
101 /* Add an exception type */
102 state->error = PyErr_NewException("_testsinglephase.error", NULL, NULL);
103 if (state->error == NULL) {
104 goto error;
105 }
106
107 state->int_const = PyLong_FromLong(1969);
108 if (state->int_const == NULL) {
109 goto error;
110 }
111
112 state->str_const = PyUnicode_FromString("something different");
113 if (state->str_const == NULL) {
114 goto error;
115 }
116
117 return 0;
118
119 error:
120 clear_state(state);
121 return -1;
122 }
123
124
125 static int
126 init_module(PyObject *module, module_state *state)
127 {
128 if (PyModule_AddObjectRef(module, "error", state->error) != 0) {
129 return -1;
130 }
131 if (PyModule_AddObjectRef(module, "int_const", state->int_const) != 0) {
132 return -1;
133 }
134 if (PyModule_AddObjectRef(module, "str_const", state->str_const) != 0) {
135 return -1;
136 }
137
138 double d = _PyTime_AsSecondsDouble(state->initialized);
139 PyObject *initialized = PyFloat_FromDouble(d);
140 if (initialized == NULL) {
141 return -1;
142 }
143 int rc = PyModule_AddObjectRef(module, "_module_initialized", initialized);
144 Py_DECREF(initialized);
145 if (rc < 0) {
146 return -1;
147 }
148
149 return 0;
150 }
151
152
153 PyDoc_STRVAR(common_state_initialized_doc,
154 "state_initialized()\n\
155 \n\
156 Return the seconds-since-epoch when the module state was initialized.");
157
158 static PyObject *
159 common_state_initialized(PyObject *self, PyObject *Py_UNUSED(ignored))
160 {
161 module_state *state = get_module_state(self);
162 if (state == NULL) {
163 Py_RETURN_NONE;
164 }
165 double d = _PyTime_AsSecondsDouble(state->initialized);
166 return PyFloat_FromDouble(d);
167 }
168
169 #define STATE_INITIALIZED_METHODDEF \
170 {"state_initialized", common_state_initialized, METH_NOARGS, \
171 common_state_initialized_doc}
172
173
174 PyDoc_STRVAR(common_look_up_self_doc,
175 "look_up_self()\n\
176 \n\
177 Return the module associated with this module's def.m_base.m_index.");
178
179 static PyObject *
180 common_look_up_self(PyObject *self, PyObject *Py_UNUSED(ignored))
181 {
182 PyModuleDef *def = PyModule_GetDef(self);
183 if (def == NULL) {
184 return NULL;
185 }
186 return Py_NewRef(
187 PyState_FindModule(def));
188 }
189
190 #define LOOK_UP_SELF_METHODDEF \
191 {"look_up_self", common_look_up_self, METH_NOARGS, common_look_up_self_doc}
192
193
194 /* Function of two integers returning integer */
195
196 PyDoc_STRVAR(common_sum_doc,
197 "sum(i,j)\n\
198 \n\
199 Return the sum of i and j.");
200
201 static PyObject *
202 common_sum(PyObject *self, PyObject *args)
203 {
204 long i, j;
205 long res;
206 if (!PyArg_ParseTuple(args, "ll:sum", &i, &j))
207 return NULL;
208 res = i + j;
209 return PyLong_FromLong(res);
210 }
211
212 #define SUM_METHODDEF \
213 {"sum", common_sum, METH_VARARGS, common_sum_doc}
214
215
216 PyDoc_STRVAR(basic_initialized_count_doc,
217 "initialized_count()\n\
218 \n\
219 Return how many times the module has been initialized.");
220
221 static PyObject *
222 basic_initialized_count(PyObject *self, PyObject *Py_UNUSED(ignored))
223 {
224 assert(PyModule_GetDef(self)->m_size == -1);
225 return PyLong_FromLong(global_state.initialized_count);
226 }
227
228 #define INITIALIZED_COUNT_METHODDEF \
229 {"initialized_count", basic_initialized_count, METH_NOARGS, \
230 basic_initialized_count_doc}
231
232
233 PyDoc_STRVAR(basic__clear_globals_doc,
234 "_clear_globals()\n\
235 \n\
236 Free all global state and set it to uninitialized.");
237
238 static PyObject *
239 basic__clear_globals(PyObject *self, PyObject *Py_UNUSED(ignored))
240 {
241 assert(PyModule_GetDef(self)->m_size == -1);
242 clear_global_state();
243 Py_RETURN_NONE;
244 }
245
246 #define _CLEAR_GLOBALS_METHODDEF \
247 {"_clear_globals", basic__clear_globals, METH_NOARGS, \
248 basic__clear_globals_doc}
249
250
251 PyDoc_STRVAR(basic__clear_module_state_doc, "_clear_module_state()\n\
252 \n\
253 Free the module state and set it to uninitialized.");
254
255 static PyObject *
256 basic__clear_module_state(PyObject *self, PyObject *Py_UNUSED(ignored))
257 {
258 module_state *state = get_module_state(self);
259 if (state != NULL) {
260 clear_state(state);
261 }
262 Py_RETURN_NONE;
263 }
264
265 #define _CLEAR_MODULE_STATE_METHODDEF \
266 {"_clear_module_state", basic__clear_module_state, METH_NOARGS, \
267 basic__clear_module_state_doc}
268
269
270 /*********************************************/
271 /* the _testsinglephase module (and aliases) */
272 /*********************************************/
273
274 /* This ia more typical of legacy extensions in the wild:
275 - single-phase init
276 - no module state
277 - does not support repeated initialization
278 (so m_copy is used)
279 - the module def is cached in _PyRuntime.extensions
280 (by name/filename)
281
282 Also note that, because the module has single-phase init,
283 it is cached in interp->module_by_index (using mod->md_def->m_base.m_index).
284 */
285
286 static PyMethodDef TestMethods_Basic[] = {
287 LOOK_UP_SELF_METHODDEF,
288 SUM_METHODDEF,
289 STATE_INITIALIZED_METHODDEF,
290 INITIALIZED_COUNT_METHODDEF,
291 _CLEAR_GLOBALS_METHODDEF,
292 {NULL, NULL} /* sentinel */
293 };
294
295 static struct PyModuleDef _testsinglephase_basic = {
296 PyModuleDef_HEAD_INIT,
297 .m_name = "_testsinglephase",
298 .m_doc = PyDoc_STR("Test module _testsinglephase"),
299 .m_size = -1, // no module state
300 .m_methods = TestMethods_Basic,
301 };
302
303 static PyObject *
304 init__testsinglephase_basic(PyModuleDef *def)
305 {
306 if (global_state.initialized_count == -1) {
307 global_state.initialized_count = 0;
308 }
309
310 PyObject *module = PyModule_Create(def);
311 if (module == NULL) {
312 return NULL;
313 }
314
315 module_state *state = &global_state.module;
316 // It may have been set by a previous run or under a different name.
317 clear_state(state);
318 if (init_state(state) < 0) {
319 Py_CLEAR(module);
320 return NULL;
321 }
322
323 if (init_module(module, state) < 0) {
324 Py_CLEAR(module);
325 goto finally;
326 }
327
328 global_state.initialized_count++;
329
330 finally:
331 return module;
332 }
333
334 PyMODINIT_FUNC
335 PyInit__testsinglephase(void)
336 {
337 return init__testsinglephase_basic(&_testsinglephase_basic);
338 }
339
340
341 PyMODINIT_FUNC
342 PyInit__testsinglephase_basic_wrapper(void)
343 {
344 return PyInit__testsinglephase();
345 }
346
347
348 PyMODINIT_FUNC
349 PyInit__testsinglephase_basic_copy(void)
350 {
351 static struct PyModuleDef def = {
352 PyModuleDef_HEAD_INIT,
353 .m_name = "_testsinglephase_basic_copy",
354 .m_doc = PyDoc_STR("Test module _testsinglephase_basic_copy"),
355 .m_size = -1, // no module state
356 .m_methods = TestMethods_Basic,
357 };
358 return init__testsinglephase_basic(&def);
359 }
360
361
362 /*******************************************/
363 /* the _testsinglephase_with_reinit module */
364 /*******************************************/
365
366 /* This ia less typical of legacy extensions in the wild:
367 - single-phase init (same as _testsinglephase above)
368 - no module state
369 - supports repeated initialization
370 (so m_copy is not used)
371 - the module def is not cached in _PyRuntime.extensions
372
373 At this point most modules would reach for multi-phase init (PEP 489).
374 However, module state has been around a while (PEP 3121),
375 and most extensions predate multi-phase init.
376
377 (This module is basically the same as _testsinglephase,
378 but supports repeated initialization.)
379 */
380
381 static PyMethodDef TestMethods_Reinit[] = {
382 LOOK_UP_SELF_METHODDEF,
383 SUM_METHODDEF,
384 STATE_INITIALIZED_METHODDEF,
385 {NULL, NULL} /* sentinel */
386 };
387
388 static struct PyModuleDef _testsinglephase_with_reinit = {
389 PyModuleDef_HEAD_INIT,
390 .m_name = "_testsinglephase_with_reinit",
391 .m_doc = PyDoc_STR("Test module _testsinglephase_with_reinit"),
392 .m_size = 0,
393 .m_methods = TestMethods_Reinit,
394 };
395
396 PyMODINIT_FUNC
397 PyInit__testsinglephase_with_reinit(void)
398 {
399 /* We purposefully do not try PyState_FindModule() first here
400 since we want to check the behavior of re-loading the module. */
401 PyObject *module = PyModule_Create(&_testsinglephase_with_reinit);
402 if (module == NULL) {
403 return NULL;
404 }
405
406 assert(get_module_state(module) == NULL);
407
408 module_state state = {0};
409 if (init_state(&state) < 0) {
410 Py_CLEAR(module);
411 return NULL;
412 }
413
414 if (init_module(module, &state) < 0) {
415 Py_CLEAR(module);
416 goto finally;
417 }
418
419 finally:
420 /* We only needed the module state for setting the module attrs. */
421 clear_state(&state);
422 return module;
423 }
424
425
426 /******************************************/
427 /* the _testsinglephase_with_state module */
428 /******************************************/
429
430 /* This is less typical of legacy extensions in the wild:
431 - single-phase init (same as _testsinglephase above)
432 - has some module state
433 - supports repeated initialization
434 (so m_copy is not used)
435 - the module def is not cached in _PyRuntime.extensions
436
437 At this point most modules would reach for multi-phase init (PEP 489).
438 However, module state has been around a while (PEP 3121),
439 and most extensions predate multi-phase init.
440 */
441
442 static PyMethodDef TestMethods_WithState[] = {
443 LOOK_UP_SELF_METHODDEF,
444 SUM_METHODDEF,
445 STATE_INITIALIZED_METHODDEF,
446 _CLEAR_MODULE_STATE_METHODDEF,
447 {NULL, NULL} /* sentinel */
448 };
449
450 static struct PyModuleDef _testsinglephase_with_state = {
451 PyModuleDef_HEAD_INIT,
452 .m_name = "_testsinglephase_with_state",
453 .m_doc = PyDoc_STR("Test module _testsinglephase_with_state"),
454 .m_size = sizeof(module_state),
455 .m_methods = TestMethods_WithState,
456 };
457
458 PyMODINIT_FUNC
459 PyInit__testsinglephase_with_state(void)
460 {
461 /* We purposefully do not try PyState_FindModule() first here
462 since we want to check the behavior of re-loading the module. */
463 PyObject *module = PyModule_Create(&_testsinglephase_with_state);
464 if (module == NULL) {
465 return NULL;
466 }
467
468 module_state *state = get_module_state(module);
469 assert(state != NULL);
470 if (init_state(state) < 0) {
471 Py_CLEAR(module);
472 return NULL;
473 }
474
475 if (init_module(module, state) < 0) {
476 clear_state(state);
477 Py_CLEAR(module);
478 goto finally;
479 }
480
481 finally:
482 return module;
483 }