(root)/
Python-3.12.0/
Modules/
_testsinglephase.c
       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  }