| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Testing module for single-phase initialization of extension modules
 | 
					
						
							| 
									
										
										
										
											2024-05-02 18:51:43 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-20 10:27:34 +02:00
										 |  |  | This file contains several distinct modules, meaning each as its own name | 
					
						
							| 
									
										
										
										
											2024-05-02 18:51:43 -06:00
										 |  |  | and its own init function (PyInit_...).  The default import system will | 
					
						
							|  |  |  | only find the one matching the filename: _testsinglephase.  To load the | 
					
						
							|  |  |  | others you must do so manually.  For example: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```python | 
					
						
							|  |  |  | name = '_testsinglephase_base_wrapper' | 
					
						
							|  |  |  | filename = _testsinglephase.__file__ | 
					
						
							|  |  |  | loader = importlib.machinery.ExtensionFileLoader(name, filename) | 
					
						
							|  |  |  | spec = importlib.util.spec_from_file_location(name, filename, loader=loader) | 
					
						
							|  |  |  | mod = importlib._bootstrap._load(spec) | 
					
						
							| 
									
										
										
										
											2024-09-20 10:27:34 +02:00
										 |  |  | loader.exec_module(module) | 
					
						
							|  |  |  | sys.modules[modname] = module | 
					
						
							| 
									
										
										
										
											2024-05-02 18:51:43 -06:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-20 10:27:34 +02:00
										 |  |  | (The last two lines are just for completeness.) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Here are the modules: | 
					
						
							| 
									
										
										
										
											2024-05-02 18:51:43 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | * _testsinglephase | 
					
						
							|  |  |  |    * def: _testsinglephase_basic, | 
					
						
							|  |  |  |       * m_name: "_testsinglephase" | 
					
						
							|  |  |  |       * m_size: -1 | 
					
						
							|  |  |  |    * state | 
					
						
							|  |  |  |       * process-global | 
					
						
							|  |  |  |          * <int> initialized_count  (default to -1; will never be 0) | 
					
						
							|  |  |  |          * <module_state> module  (see module state below) | 
					
						
							|  |  |  |       * module state: no | 
					
						
							|  |  |  |       * initial __dict__: see common initial __dict__ below | 
					
						
							|  |  |  |    * init function | 
					
						
							|  |  |  |       1. create module | 
					
						
							|  |  |  |       2. clear <global>.module | 
					
						
							|  |  |  |       3. initialize <global>.module: see module state below | 
					
						
							|  |  |  |       4. initialize module: set initial __dict__ | 
					
						
							|  |  |  |       5. increment <global>.initialized_count | 
					
						
							|  |  |  |    * functions | 
					
						
							|  |  |  |       * (3 common, see below) | 
					
						
							|  |  |  |       * initialized_count() - return <global>.module.initialized_count | 
					
						
							|  |  |  |    * import system | 
					
						
							|  |  |  |       * caches | 
					
						
							|  |  |  |          * global extensions cache: yes | 
					
						
							|  |  |  |          * def.m_base.m_copy: yes | 
					
						
							|  |  |  |          * def.m_base.m_init: no | 
					
						
							|  |  |  |          * per-interpreter cache: yes  (all single-phase init modules) | 
					
						
							|  |  |  |       * load in main interpreter | 
					
						
							|  |  |  |          * initial  (not already in global cache) | 
					
						
							|  |  |  |             1. get init function from shared object file | 
					
						
							|  |  |  |             2. run init function | 
					
						
							|  |  |  |             3. copy __dict__ into def.m_base.m_copy | 
					
						
							|  |  |  |             4. set entry in global cache | 
					
						
							|  |  |  |             5. set entry in per-interpreter cache | 
					
						
							|  |  |  |             6. set entry in sys.modules | 
					
						
							|  |  |  |          * reload  (already in sys.modules) | 
					
						
							|  |  |  |             1. get def from global cache | 
					
						
							|  |  |  |             2. get module from sys.modules | 
					
						
							|  |  |  |             3. update module with contents of def.m_base.m_copy | 
					
						
							|  |  |  |          * already loaded in other interpreter  (already in global cache) | 
					
						
							|  |  |  |             * same as reload, but create new module and update *it* | 
					
						
							|  |  |  |          * not in any sys.modules, still in global cache | 
					
						
							|  |  |  |             * same as already loaded | 
					
						
							|  |  |  |       * load in legacy (non-isolated) interpreter | 
					
						
							|  |  |  |          * same as main interpreter | 
					
						
							|  |  |  |       * unload: never  (all single-phase init modules) | 
					
						
							|  |  |  | * _testsinglephase_basic_wrapper | 
					
						
							|  |  |  |    * identical to _testsinglephase except module name | 
					
						
							|  |  |  | * _testsinglephase_basic_copy | 
					
						
							|  |  |  |    * def: static local variable in init function | 
					
						
							|  |  |  |       * m_name: "_testsinglephase_basic_copy" | 
					
						
							|  |  |  |       * m_size: -1 | 
					
						
							|  |  |  |    * state: same as _testsinglephase | 
					
						
							|  |  |  |    * init function: same as _testsinglephase | 
					
						
							|  |  |  |    * functions: same as _testsinglephase | 
					
						
							|  |  |  |    * import system: same as _testsinglephase | 
					
						
							|  |  |  | * _testsinglephase_with_reinit | 
					
						
							|  |  |  |    * def: _testsinglephase_with_reinit, | 
					
						
							|  |  |  |       * m_name: "_testsinglephase_with_reinit" | 
					
						
							|  |  |  |       * m_size: 0 | 
					
						
							|  |  |  |    * state | 
					
						
							|  |  |  |       * process-global state: no | 
					
						
							|  |  |  |       * module state: no | 
					
						
							|  |  |  |       * initial __dict__: see common initial __dict__ below | 
					
						
							|  |  |  |    * init function | 
					
						
							|  |  |  |       1. create module | 
					
						
							|  |  |  |       2. initialize temporary module state (local var): see module state below | 
					
						
							|  |  |  |       3. initialize module: set initial __dict__ | 
					
						
							|  |  |  |    * functions: see common functions below | 
					
						
							|  |  |  |    * import system | 
					
						
							|  |  |  |       * caches | 
					
						
							|  |  |  |          * global extensions cache: only if loaded in main interpreter | 
					
						
							|  |  |  |          * def.m_base.m_copy: no | 
					
						
							|  |  |  |          * def.m_base.m_init: only if loaded in the main interpreter | 
					
						
							|  |  |  |          * per-interpreter cache: yes  (all single-phase init modules) | 
					
						
							|  |  |  |       * load in main interpreter | 
					
						
							|  |  |  |          * initial  (not already in global cache) | 
					
						
							|  |  |  |             * (same as _testsinglephase except step 3) | 
					
						
							|  |  |  |             1. get init function from shared object file | 
					
						
							|  |  |  |             2. run init function | 
					
						
							|  |  |  |             3. set def.m_base.m_init to the init function | 
					
						
							|  |  |  |             4. set entry in global cache | 
					
						
							|  |  |  |             5. set entry in per-interpreter cache | 
					
						
							|  |  |  |             6. set entry in sys.modules | 
					
						
							|  |  |  |          * reload  (already in sys.modules) | 
					
						
							|  |  |  |             1. get def from global cache | 
					
						
							|  |  |  |             2. call def->m_base.m_init to get a new module object | 
					
						
							|  |  |  |             3. replace the existing module in sys.modules | 
					
						
							|  |  |  |          * already loaded in other interpreter  (already in global cache) | 
					
						
							|  |  |  |             * same as reload (since will only be in cache for main interp) | 
					
						
							|  |  |  |          * not in any sys.modules, still in global cache | 
					
						
							|  |  |  |             * same as already loaded | 
					
						
							|  |  |  |       * load in legacy (non-isolated) interpreter | 
					
						
							|  |  |  |          * initial  (not already in global cache) | 
					
						
							|  |  |  |             * (same as main interpreter except skip steps 3 & 4 there) | 
					
						
							|  |  |  |             1. get init function from shared object file | 
					
						
							|  |  |  |             2. run init function | 
					
						
							|  |  |  |             ... | 
					
						
							|  |  |  |             5. set entry in per-interpreter cache | 
					
						
							|  |  |  |             6. set entry in sys.modules | 
					
						
							|  |  |  |          * reload  (already in sys.modules) | 
					
						
							|  |  |  |             * same as initial  (load from scratch) | 
					
						
							|  |  |  |          * already loaded in other interpreter  (already in global cache) | 
					
						
							|  |  |  |             * same as initial  (load from scratch) | 
					
						
							|  |  |  |          * not in any sys.modules, still in global cache | 
					
						
							|  |  |  |             * same as initial  (load from scratch) | 
					
						
							|  |  |  |       * unload: never  (all single-phase init modules) | 
					
						
							|  |  |  | * _testsinglephase_with_state | 
					
						
							|  |  |  |    * def: _testsinglephase_with_state, | 
					
						
							|  |  |  |       * m_name: "_testsinglephase_with_state" | 
					
						
							|  |  |  |       * m_size: sizeof(module_state) | 
					
						
							|  |  |  |    * state | 
					
						
							|  |  |  |       * process-global: no | 
					
						
							|  |  |  |       * module state: see module state below | 
					
						
							|  |  |  |       * initial __dict__: see common initial __dict__ below | 
					
						
							|  |  |  |    * init function | 
					
						
							|  |  |  |       1. create module | 
					
						
							|  |  |  |       3. initialize module state: see module state below | 
					
						
							|  |  |  |       4. initialize module: set initial __dict__ | 
					
						
							|  |  |  |       5. increment <global>.initialized_count | 
					
						
							|  |  |  |    * functions: see common functions below | 
					
						
							|  |  |  |    * import system: same as _testsinglephase_basic_copy | 
					
						
							| 
									
										
										
										
											2024-05-25 15:30:48 -04:00
										 |  |  | * _testsinglephase_check_cache_first | 
					
						
							|  |  |  |    * def: _testsinglepahse_check_cache_first | 
					
						
							|  |  |  |       * m_name: "_testsinglephase_check_cache_first" | 
					
						
							|  |  |  |       * m_size: -1 | 
					
						
							|  |  |  |    * state: none | 
					
						
							|  |  |  |    * init function: | 
					
						
							|  |  |  |       * tries PyState_FindModule() first | 
					
						
							|  |  |  |       * otherwise creates empty module | 
					
						
							|  |  |  |    * functions: none | 
					
						
							|  |  |  |    * import system: same as _testsinglephase | 
					
						
							|  |  |  | * _testsinglephase_with_reinit_check_cache_first | 
					
						
							|  |  |  |    * def: _testsinglepahse_with_reinit_check_cache_first | 
					
						
							|  |  |  |       * m_name: "_testsinglephase_with_reinit_check_cache_first" | 
					
						
							|  |  |  |       * m_size: 0 | 
					
						
							|  |  |  |    * state: none | 
					
						
							|  |  |  |    * init function: same as _testsinglephase_check_cache_first | 
					
						
							|  |  |  |    * functions: none | 
					
						
							|  |  |  |    * import system: same as _testsinglephase_with_reinit | 
					
						
							|  |  |  | * _testsinglephase_with_state_check_cache_first | 
					
						
							|  |  |  |    * def: _testsinglepahse_with_state_check_cache_first | 
					
						
							|  |  |  |       * m_name: "_testsinglephase_with_state_check_cache_first" | 
					
						
							|  |  |  |       * m_size: 42 | 
					
						
							|  |  |  |    * state: none | 
					
						
							|  |  |  |    * init function: same as _testsinglephase_check_cache_first | 
					
						
							|  |  |  |    * functions: none | 
					
						
							|  |  |  |    * import system: same as _testsinglephase_with_state | 
					
						
							| 
									
										
										
										
											2024-05-02 18:51:43 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-20 10:27:34 +02:00
										 |  |  | * _testsinglephase_circular | 
					
						
							|  |  |  |    Regression test for gh-123880. | 
					
						
							|  |  |  |    Does not have the common attributes & methods. | 
					
						
							|  |  |  |    See test_singlephase_circular test.test_import.SinglephaseInitTests. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 18:51:43 -06:00
										 |  |  | Module state: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * fields | 
					
						
							|  |  |  |    * <PyTime_t> initialized - when the module was first initialized | 
					
						
							|  |  |  |    * <PyObject> *error | 
					
						
							|  |  |  |    * <PyObject> *int_const | 
					
						
							|  |  |  |    * <PyObject> *str_const | 
					
						
							|  |  |  | * initialization | 
					
						
							|  |  |  |    1. set state.initialized to the current time | 
					
						
							|  |  |  |    2. set state.error to a new exception class | 
					
						
							|  |  |  |    3. set state->int_const to int(1969) | 
					
						
							|  |  |  |    4. set state->str_const to "something different" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Common initial __dict__: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * error: state.error | 
					
						
							|  |  |  | * int_const: state.int_const | 
					
						
							|  |  |  | * str_const: state.str_const | 
					
						
							|  |  |  | * _module_initialized: state.initialized | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Common functions: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * look_up_self() - return the module from the per-interpreter "by-index" cache | 
					
						
							|  |  |  | * sum() - return a + b | 
					
						
							|  |  |  | * state_initialized() - return state->initialized (or None if m_size == 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | See Python/import.c, especially the long comments, for more about | 
					
						
							|  |  |  | single-phase init modules. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | #ifndef Py_BUILD_CORE_BUILTIN
 | 
					
						
							|  |  |  | #  define Py_BUILD_CORE_MODULE 1
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | //#include <time.h>
 | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | #include "Python.h"
 | 
					
						
							|  |  |  | #include "pycore_namespace.h"     // _PyNamespace_New()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2024-02-20 16:02:27 +01:00
										 |  |  |     PyTime_t initialized; | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     PyObject *error; | 
					
						
							|  |  |  |     PyObject *int_const; | 
					
						
							|  |  |  |     PyObject *str_const; | 
					
						
							|  |  |  | } module_state; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-15 16:05:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | /* Process-global state is only used by _testsinglephase
 | 
					
						
							|  |  |  |    since it's the only one that does not support re-init. */ | 
					
						
							|  |  |  | static struct { | 
					
						
							|  |  |  |     int initialized_count; | 
					
						
							|  |  |  |     module_state module; | 
					
						
							| 
									
										
										
										
											2023-02-15 16:05:07 -07:00
										 |  |  | } global_state = { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define NOT_INITIALIZED -1
 | 
					
						
							|  |  |  |     .initialized_count = NOT_INITIALIZED, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void clear_state(module_state *state); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | clear_global_state(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     clear_state(&global_state.module); | 
					
						
							|  |  |  |     global_state.initialized_count = NOT_INITIALIZED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | static inline module_state * | 
					
						
							|  |  |  | get_module_state(PyObject *module) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyModuleDef *def = PyModule_GetDef(module); | 
					
						
							|  |  |  |     if (def->m_size == -1) { | 
					
						
							|  |  |  |         return &global_state.module; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (def->m_size == 0) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         module_state *state = (module_state*)PyModule_GetState(module); | 
					
						
							|  |  |  |         assert(state != NULL); | 
					
						
							|  |  |  |         return state; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | clear_state(module_state *state) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     state->initialized = 0; | 
					
						
							|  |  |  |     Py_CLEAR(state->error); | 
					
						
							|  |  |  |     Py_CLEAR(state->int_const); | 
					
						
							|  |  |  |     Py_CLEAR(state->str_const); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2024-02-20 16:02:27 +01:00
										 |  |  | _set_initialized(PyTime_t *initialized) | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | { | 
					
						
							|  |  |  |     /* We go strictly monotonic to ensure each time is unique. */ | 
					
						
							| 
									
										
										
										
											2024-02-20 16:02:27 +01:00
										 |  |  |     PyTime_t prev; | 
					
						
							| 
									
										
										
										
											2024-02-21 00:31:30 +01:00
										 |  |  |     if (PyTime_Monotonic(&prev) != 0) { | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* We do a busy sleep since the interval should be super short. */ | 
					
						
							| 
									
										
										
										
											2024-02-20 16:02:27 +01:00
										 |  |  |     PyTime_t t; | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     do { | 
					
						
							| 
									
										
										
										
											2024-02-21 00:31:30 +01:00
										 |  |  |         if (PyTime_Monotonic(&t) != 0) { | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } while (t == prev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *initialized = t; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | init_state(module_state *state) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(state->initialized == 0 && | 
					
						
							|  |  |  |            state->error == NULL && | 
					
						
							|  |  |  |            state->int_const == NULL && | 
					
						
							|  |  |  |            state->str_const == NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (_set_initialized(&state->initialized) != 0) { | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     assert(state->initialized > 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Add an exception type */ | 
					
						
							|  |  |  |     state->error = PyErr_NewException("_testsinglephase.error", NULL, NULL); | 
					
						
							|  |  |  |     if (state->error == NULL) { | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     state->int_const = PyLong_FromLong(1969); | 
					
						
							|  |  |  |     if (state->int_const == NULL) { | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     state->str_const = PyUnicode_FromString("something different"); | 
					
						
							|  |  |  |     if (state->str_const == NULL) { | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							|  |  |  |     clear_state(state); | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-15 16:05:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | static int | 
					
						
							|  |  |  | init_module(PyObject *module, module_state *state) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (PyModule_AddObjectRef(module, "error", state->error) != 0) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (PyModule_AddObjectRef(module, "int_const", state->int_const) != 0) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (PyModule_AddObjectRef(module, "str_const", state->str_const) != 0) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-15 16:05:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-21 00:31:30 +01:00
										 |  |  |     double d = PyTime_AsSecondsDouble(state->initialized); | 
					
						
							| 
									
										
										
										
											2023-07-18 23:59:53 +03:00
										 |  |  |     if (PyModule_Add(module, "_module_initialized", PyFloat_FromDouble(d)) < 0) { | 
					
						
							| 
									
										
										
										
											2023-02-15 16:05:07 -07:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-27 09:21:18 -07:00
										 |  |  | PyDoc_STRVAR(common_state_initialized_doc, | 
					
						
							|  |  |  | "state_initialized()\n\
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | \n\ | 
					
						
							| 
									
										
										
										
											2023-02-27 09:21:18 -07:00
										 |  |  | Return the seconds-since-epoch when the module state was initialized."); | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2023-02-27 09:21:18 -07:00
										 |  |  | common_state_initialized(PyObject *self, PyObject *Py_UNUSED(ignored)) | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | { | 
					
						
							|  |  |  |     module_state *state = get_module_state(self); | 
					
						
							|  |  |  |     if (state == NULL) { | 
					
						
							|  |  |  |         Py_RETURN_NONE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-02-21 00:31:30 +01:00
										 |  |  |     double d = PyTime_AsSecondsDouble(state->initialized); | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     return PyFloat_FromDouble(d); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-27 09:21:18 -07:00
										 |  |  | #define STATE_INITIALIZED_METHODDEF \
 | 
					
						
							|  |  |  |     {"state_initialized", common_state_initialized, METH_NOARGS, \ | 
					
						
							|  |  |  |      common_state_initialized_doc} | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(common_look_up_self_doc, | 
					
						
							|  |  |  | "look_up_self()\n\
 | 
					
						
							|  |  |  | \n\ | 
					
						
							|  |  |  | Return the module associated with this module's def.m_base.m_index."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | common_look_up_self(PyObject *self, PyObject *Py_UNUSED(ignored)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyModuleDef *def = PyModule_GetDef(self); | 
					
						
							|  |  |  |     if (def == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return Py_NewRef( | 
					
						
							|  |  |  |             PyState_FindModule(def)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define LOOK_UP_SELF_METHODDEF \
 | 
					
						
							|  |  |  |     {"look_up_self", common_look_up_self, METH_NOARGS, common_look_up_self_doc} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | /* Function of two integers returning integer */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | PyDoc_STRVAR(common_sum_doc, | 
					
						
							|  |  |  | "sum(i,j)\n\
 | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | \n\ | 
					
						
							|  |  |  | Return the sum of i and j."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | common_sum(PyObject *self, PyObject *args) | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | { | 
					
						
							|  |  |  |     long i, j; | 
					
						
							|  |  |  |     long res; | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     if (!PyArg_ParseTuple(args, "ll:sum", &i, &j)) | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     res = i + j; | 
					
						
							|  |  |  |     return PyLong_FromLong(res); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | #define SUM_METHODDEF \
 | 
					
						
							|  |  |  |     {"sum", common_sum, METH_VARARGS, common_sum_doc} | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | PyDoc_STRVAR(basic_initialized_count_doc, | 
					
						
							|  |  |  | "initialized_count()\n\
 | 
					
						
							|  |  |  | \n\ | 
					
						
							|  |  |  | Return how many times the module has been initialized."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | basic_initialized_count(PyObject *self, PyObject *Py_UNUSED(ignored)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(PyModule_GetDef(self)->m_size == -1); | 
					
						
							|  |  |  |     return PyLong_FromLong(global_state.initialized_count); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define INITIALIZED_COUNT_METHODDEF \
 | 
					
						
							| 
									
										
										
										
											2023-02-15 16:05:07 -07:00
										 |  |  |     {"initialized_count", basic_initialized_count, METH_NOARGS, \ | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |      basic_initialized_count_doc} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-15 16:05:07 -07:00
										 |  |  | PyDoc_STRVAR(basic__clear_globals_doc, | 
					
						
							|  |  |  | "_clear_globals()\n\
 | 
					
						
							|  |  |  | \n\ | 
					
						
							|  |  |  | Free all global state and set it to uninitialized."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | basic__clear_globals(PyObject *self, PyObject *Py_UNUSED(ignored)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(PyModule_GetDef(self)->m_size == -1); | 
					
						
							|  |  |  |     clear_global_state(); | 
					
						
							|  |  |  |     Py_RETURN_NONE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define _CLEAR_GLOBALS_METHODDEF \
 | 
					
						
							|  |  |  |     {"_clear_globals", basic__clear_globals, METH_NOARGS, \ | 
					
						
							|  |  |  |      basic__clear_globals_doc} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-01 05:12:10 +08:00
										 |  |  | PyDoc_STRVAR(basic__clear_module_state_doc, "_clear_module_state()\n\
 | 
					
						
							|  |  |  | \n\ | 
					
						
							|  |  |  | Free the module state and set it to uninitialized."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | basic__clear_module_state(PyObject *self, PyObject *Py_UNUSED(ignored)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     module_state *state = get_module_state(self); | 
					
						
							|  |  |  |     if (state != NULL) { | 
					
						
							|  |  |  |         clear_state(state); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_RETURN_NONE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define _CLEAR_MODULE_STATE_METHODDEF \
 | 
					
						
							|  |  |  |     {"_clear_module_state", basic__clear_module_state, METH_NOARGS, \ | 
					
						
							|  |  |  |      basic__clear_module_state_doc} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | /*********************************************/ | 
					
						
							|  |  |  | /* the _testsinglephase module (and aliases) */ | 
					
						
							|  |  |  | /*********************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* This ia more typical of legacy extensions in the wild:
 | 
					
						
							|  |  |  |    - single-phase init | 
					
						
							|  |  |  |    - no module state | 
					
						
							|  |  |  |    - does not support repeated initialization | 
					
						
							|  |  |  |     (so m_copy is used) | 
					
						
							|  |  |  |    - the module def is cached in _PyRuntime.extensions | 
					
						
							|  |  |  |      (by name/filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Also note that, because the module has single-phase init, | 
					
						
							|  |  |  |    it is cached in interp->module_by_index (using mod->md_def->m_base.m_index). | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | static PyMethodDef TestMethods_Basic[] = { | 
					
						
							|  |  |  |     LOOK_UP_SELF_METHODDEF, | 
					
						
							|  |  |  |     SUM_METHODDEF, | 
					
						
							| 
									
										
										
										
											2023-02-27 09:21:18 -07:00
										 |  |  |     STATE_INITIALIZED_METHODDEF, | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     INITIALIZED_COUNT_METHODDEF, | 
					
						
							| 
									
										
										
										
											2023-02-15 16:05:07 -07:00
										 |  |  |     _CLEAR_GLOBALS_METHODDEF, | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     {NULL, NULL}           /* sentinel */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyModuleDef _testsinglephase_basic = { | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  |     PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |     .m_name = "_testsinglephase", | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     .m_doc = PyDoc_STR("Test module _testsinglephase"), | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  |     .m_size = -1,  // no module state
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     .m_methods = TestMethods_Basic, | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | static PyObject * | 
					
						
							|  |  |  | init__testsinglephase_basic(PyModuleDef *def) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (global_state.initialized_count == -1) { | 
					
						
							|  |  |  |         global_state.initialized_count = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyObject *module = PyModule_Create(def); | 
					
						
							|  |  |  |     if (module == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-05-03 08:30:55 -07:00
										 |  |  | #ifdef Py_GIL_DISABLED
 | 
					
						
							| 
									
										
										
										
											2024-05-06 18:59:36 +02:00
										 |  |  |     PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED); | 
					
						
							| 
									
										
										
										
											2024-05-03 08:30:55 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     module_state *state = &global_state.module; | 
					
						
							|  |  |  |     // It may have been set by a previous run or under a different name.
 | 
					
						
							|  |  |  |     clear_state(state); | 
					
						
							|  |  |  |     if (init_state(state) < 0) { | 
					
						
							|  |  |  |         Py_CLEAR(module); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (init_module(module, state) < 0) { | 
					
						
							|  |  |  |         Py_CLEAR(module); | 
					
						
							|  |  |  |         goto finally; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     global_state.initialized_count++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | finally: | 
					
						
							|  |  |  |     return module; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__testsinglephase(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     return init__testsinglephase_basic(&_testsinglephase_basic); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__testsinglephase_basic_wrapper(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return PyInit__testsinglephase(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__testsinglephase_basic_copy(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     static struct PyModuleDef def = { | 
					
						
							|  |  |  |         PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |         .m_name = "_testsinglephase_basic_copy", | 
					
						
							|  |  |  |         .m_doc = PyDoc_STR("Test module _testsinglephase_basic_copy"), | 
					
						
							|  |  |  |         .m_size = -1,  // no module state
 | 
					
						
							|  |  |  |         .m_methods = TestMethods_Basic, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     return init__testsinglephase_basic(&def); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*******************************************/ | 
					
						
							|  |  |  | /* the _testsinglephase_with_reinit module */ | 
					
						
							|  |  |  | /*******************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* This ia less typical of legacy extensions in the wild:
 | 
					
						
							|  |  |  |    - single-phase init  (same as _testsinglephase above) | 
					
						
							|  |  |  |    - no module state | 
					
						
							|  |  |  |    - supports repeated initialization | 
					
						
							|  |  |  |      (so m_copy is not used) | 
					
						
							|  |  |  |    - the module def is not cached in _PyRuntime.extensions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    At this point most modules would reach for multi-phase init (PEP 489). | 
					
						
							|  |  |  |    However, module state has been around a while (PEP 3121), | 
					
						
							|  |  |  |    and most extensions predate multi-phase init. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    (This module is basically the same as _testsinglephase, | 
					
						
							|  |  |  |     but supports repeated initialization.) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyMethodDef TestMethods_Reinit[] = { | 
					
						
							|  |  |  |     LOOK_UP_SELF_METHODDEF, | 
					
						
							|  |  |  |     SUM_METHODDEF, | 
					
						
							| 
									
										
										
										
											2023-02-27 09:21:18 -07:00
										 |  |  |     STATE_INITIALIZED_METHODDEF, | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     {NULL, NULL}           /* sentinel */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyModuleDef _testsinglephase_with_reinit = { | 
					
						
							|  |  |  |     PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |     .m_name = "_testsinglephase_with_reinit", | 
					
						
							|  |  |  |     .m_doc = PyDoc_STR("Test module _testsinglephase_with_reinit"), | 
					
						
							|  |  |  |     .m_size = 0, | 
					
						
							|  |  |  |     .m_methods = TestMethods_Reinit, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__testsinglephase_with_reinit(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /* We purposefully do not try PyState_FindModule() first here
 | 
					
						
							|  |  |  |        since we want to check the behavior of re-loading the module. */ | 
					
						
							|  |  |  |     PyObject *module = PyModule_Create(&_testsinglephase_with_reinit); | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  |     if (module == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-05-03 08:30:55 -07:00
										 |  |  | #ifdef Py_GIL_DISABLED
 | 
					
						
							| 
									
										
										
										
											2024-05-06 18:59:36 +02:00
										 |  |  |     PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED); | 
					
						
							| 
									
										
										
										
											2024-05-03 08:30:55 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     assert(get_module_state(module) == NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     module_state state = {0}; | 
					
						
							|  |  |  |     if (init_state(&state) < 0) { | 
					
						
							|  |  |  |         Py_CLEAR(module); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (init_module(module, &state) < 0) { | 
					
						
							|  |  |  |         Py_CLEAR(module); | 
					
						
							|  |  |  |         goto finally; | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | finally: | 
					
						
							|  |  |  |     /* We only needed the module state for setting the module attrs. */ | 
					
						
							|  |  |  |     clear_state(&state); | 
					
						
							|  |  |  |     return module; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /******************************************/ | 
					
						
							|  |  |  | /* the _testsinglephase_with_state module */ | 
					
						
							|  |  |  | /******************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-01 05:12:10 +08:00
										 |  |  | /* This is less typical of legacy extensions in the wild:
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |    - single-phase init  (same as _testsinglephase above) | 
					
						
							|  |  |  |    - has some module state | 
					
						
							|  |  |  |    - supports repeated initialization | 
					
						
							|  |  |  |      (so m_copy is not used) | 
					
						
							|  |  |  |    - the module def is not cached in _PyRuntime.extensions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    At this point most modules would reach for multi-phase init (PEP 489). | 
					
						
							|  |  |  |    However, module state has been around a while (PEP 3121), | 
					
						
							|  |  |  |    and most extensions predate multi-phase init. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyMethodDef TestMethods_WithState[] = { | 
					
						
							|  |  |  |     LOOK_UP_SELF_METHODDEF, | 
					
						
							|  |  |  |     SUM_METHODDEF, | 
					
						
							| 
									
										
										
										
											2023-02-27 09:21:18 -07:00
										 |  |  |     STATE_INITIALIZED_METHODDEF, | 
					
						
							| 
									
										
										
										
											2023-06-01 05:12:10 +08:00
										 |  |  |     _CLEAR_MODULE_STATE_METHODDEF, | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     {NULL, NULL}           /* sentinel */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyModuleDef _testsinglephase_with_state = { | 
					
						
							|  |  |  |     PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |     .m_name = "_testsinglephase_with_state", | 
					
						
							|  |  |  |     .m_doc = PyDoc_STR("Test module _testsinglephase_with_state"), | 
					
						
							|  |  |  |     .m_size = sizeof(module_state), | 
					
						
							|  |  |  |     .m_methods = TestMethods_WithState, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__testsinglephase_with_state(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /* We purposefully do not try PyState_FindModule() first here
 | 
					
						
							|  |  |  |        since we want to check the behavior of re-loading the module. */ | 
					
						
							|  |  |  |     PyObject *module = PyModule_Create(&_testsinglephase_with_state); | 
					
						
							|  |  |  |     if (module == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-05-03 08:30:55 -07:00
										 |  |  | #ifdef Py_GIL_DISABLED
 | 
					
						
							| 
									
										
										
										
											2024-05-06 18:59:36 +02:00
										 |  |  |     PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED); | 
					
						
							| 
									
										
										
										
											2024-05-03 08:30:55 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     module_state *state = get_module_state(module); | 
					
						
							|  |  |  |     assert(state != NULL); | 
					
						
							|  |  |  |     if (init_state(state) < 0) { | 
					
						
							|  |  |  |         Py_CLEAR(module); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  |     if (init_module(module, state) < 0) { | 
					
						
							|  |  |  |         clear_state(state); | 
					
						
							|  |  |  |         Py_CLEAR(module); | 
					
						
							|  |  |  |         goto finally; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:26:03 -07:00
										 |  |  | finally: | 
					
						
							|  |  |  |     return module; | 
					
						
							| 
									
										
										
										
											2022-11-08 09:58:11 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2024-05-25 15:30:48 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /****************************************************/ | 
					
						
							|  |  |  | /* the _testsinglephase_*_check_cache_first modules */ | 
					
						
							|  |  |  | /****************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-27 15:35:30 -04:00
										 |  |  | /* Each of these modules should only be freshly loaded.  That means
 | 
					
						
							|  |  |  |    clearing the caches and each module def's m_base after each load. */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-25 15:30:48 -04:00
										 |  |  | static struct PyModuleDef _testsinglephase_check_cache_first = { | 
					
						
							|  |  |  |     PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |     .m_name = "_testsinglephase_check_cache_first", | 
					
						
							|  |  |  |     .m_doc = PyDoc_STR("Test module _testsinglephase_check_cache_first"), | 
					
						
							|  |  |  |     .m_size = -1,  // no module state
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__testsinglephase_check_cache_first(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(_testsinglephase_check_cache_first.m_base.m_index == 0); | 
					
						
							|  |  |  |     PyObject *mod = PyState_FindModule(&_testsinglephase_check_cache_first); | 
					
						
							|  |  |  |     if (mod != NULL) { | 
					
						
							|  |  |  |         return Py_NewRef(mod); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return PyModule_Create(&_testsinglephase_check_cache_first); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyModuleDef _testsinglephase_with_reinit_check_cache_first = { | 
					
						
							|  |  |  |     PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |     .m_name = "_testsinglephase_with_reinit_check_cache_first", | 
					
						
							|  |  |  |     .m_doc = PyDoc_STR("Test module _testsinglephase_with_reinit_check_cache_first"), | 
					
						
							|  |  |  |     .m_size = 0,  // no module state
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__testsinglephase_with_reinit_check_cache_first(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(_testsinglephase_with_reinit_check_cache_first.m_base.m_index == 0); | 
					
						
							|  |  |  |     PyObject *mod = PyState_FindModule(&_testsinglephase_with_reinit_check_cache_first); | 
					
						
							|  |  |  |     if (mod != NULL) { | 
					
						
							|  |  |  |         return Py_NewRef(mod); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return PyModule_Create(&_testsinglephase_with_reinit_check_cache_first); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyModuleDef _testsinglephase_with_state_check_cache_first = { | 
					
						
							|  |  |  |     PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |     .m_name = "_testsinglephase_with_state_check_cache_first", | 
					
						
							|  |  |  |     .m_doc = PyDoc_STR("Test module _testsinglephase_with_state_check_cache_first"), | 
					
						
							|  |  |  |     .m_size = 42,  // not used
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__testsinglephase_with_state_check_cache_first(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(_testsinglephase_with_state_check_cache_first.m_base.m_index == 0); | 
					
						
							|  |  |  |     PyObject *mod = PyState_FindModule(&_testsinglephase_with_state_check_cache_first); | 
					
						
							|  |  |  |     if (mod != NULL) { | 
					
						
							|  |  |  |         return Py_NewRef(mod); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return PyModule_Create(&_testsinglephase_with_state_check_cache_first); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-09-20 10:27:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /****************************************/ | 
					
						
							|  |  |  | /* the _testsinglephase_circular module */ | 
					
						
							|  |  |  | /****************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject *static_module_circular; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | circularmod_clear_static_var(PyObject *self, PyObject *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyObject *result = static_module_circular; | 
					
						
							|  |  |  |     static_module_circular = NULL; | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyModuleDef _testsinglephase_circular = { | 
					
						
							|  |  |  |     PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |     .m_name = "_testsinglephase_circular", | 
					
						
							|  |  |  |     .m_doc = PyDoc_STR("Test module _testsinglephase_circular"), | 
					
						
							|  |  |  |     .m_methods = (PyMethodDef[]) { | 
					
						
							|  |  |  |         {"clear_static_var", circularmod_clear_static_var, METH_NOARGS, | 
					
						
							|  |  |  |          "Clear the static variable and return its previous value."}, | 
					
						
							|  |  |  |         {NULL, NULL}           /* sentinel */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__testsinglephase_circular(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!static_module_circular) { | 
					
						
							|  |  |  |         static_module_circular = PyModule_Create(&_testsinglephase_circular); | 
					
						
							|  |  |  |         if (!static_module_circular) { | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     static const char helper_mod_name[] = ( | 
					
						
							|  |  |  |         "test.test_import.data.circular_imports.singlephase"); | 
					
						
							|  |  |  |     PyObject *helper_mod = PyImport_ImportModule(helper_mod_name); | 
					
						
							|  |  |  |     Py_XDECREF(helper_mod); | 
					
						
							|  |  |  |     if (!helper_mod) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if(PyModule_AddStringConstant(static_module_circular, | 
					
						
							|  |  |  |                                   "helper_mod_name", | 
					
						
							|  |  |  |                                   helper_mod_name) < 0) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return Py_NewRef(static_module_circular); | 
					
						
							|  |  |  | } |