bpo-32030: Split Py_Main() into subfunctions (#4399)

* Don't use "Python runtime" anymore to parse command line options or
  to get environment variables: pymain_init() is now a strict
  separation.
* Use an error message rather than "crashing" directly with
  Py_FatalError(). Limit the number of calls to Py_FatalError(). It
  prepares the code to handle errors more nicely later.
* Warnings options (-W, PYTHONWARNINGS) and "XOptions" (-X) are now
  only added to the sys module once Python core is properly
  initialized.
* _PyMain is now the well identified owner of some important strings
  like: warnings options, XOptions, and the "program name". The
  program name string is now properly freed at exit.
  pymain_free() is now responsible to free the "command" string.
* Rename most methods in Modules/main.c to use a "pymain_" prefix to
  avoid conflits and ease debug.
* Replace _Py_CommandLineDetails_INIT with memset(0)
* Reorder a lot of code to fix the initialization ordering. For
  example, initializing standard streams now comes before parsing
  PYTHONWARNINGS.
* Py_Main() now handles errors when adding warnings options and
  XOptions.
* Add _PyMem_GetDefaultRawAllocator() private function.
* Cleanup _PyMem_Initialize(): remove useless global constants: move
  them into _PyMem_Initialize().
* Call _PyRuntime_Initialize() as soon as possible:
  _PyRuntime_Initialize() now returns an error message on failure.
* Add _PyInitError structure and following macros:

  * _Py_INIT_OK()
  * _Py_INIT_ERR(msg)
  * _Py_INIT_USER_ERR(msg): "user" error, don't abort() in that case
  * _Py_INIT_FAILED(err)
This commit is contained in:
Victor Stinner 2017-11-15 15:48:08 -08:00 committed by GitHub
parent 43605e6bfa
commit f7e5b56c37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1346 additions and 657 deletions

View file

@ -1281,47 +1281,54 @@ PyInit_faulthandler(void)
return m;
}
static int
faulthandler_init_enable(void)
{
PyObject *module = PyImport_ImportModule("faulthandler");
if (module == NULL) {
return -1;
}
PyObject *res = _PyObject_CallMethodId(module, &PyId_enable, NULL);
Py_DECREF(module);
if (res == NULL) {
return -1;
}
Py_DECREF(res);
return 0;
}
/* Call faulthandler.enable() if the PYTHONFAULTHANDLER environment variable
is defined, or if sys._xoptions has a 'faulthandler' key. */
static int
faulthandler_env_options(void)
faulthandler_init_parse(void)
{
PyObject *xoptions, *key, *module, *res;
char *p;
if (!((p = Py_GETENV("PYTHONFAULTHANDLER")) && *p != '\0')) {
/* PYTHONFAULTHANDLER environment variable is missing
or an empty string */
int has_key;
xoptions = PySys_GetXOptions();
if (xoptions == NULL)
return -1;
key = PyUnicode_FromString("faulthandler");
if (key == NULL)
return -1;
has_key = PyDict_Contains(xoptions, key);
Py_DECREF(key);
if (has_key <= 0)
return has_key;
char *p = Py_GETENV("PYTHONFAULTHANDLER");
if (p && *p != '\0') {
return 1;
}
module = PyImport_ImportModule("faulthandler");
if (module == NULL) {
/* PYTHONFAULTHANDLER environment variable is missing
or an empty string */
PyObject *xoptions = PySys_GetXOptions();
if (xoptions == NULL) {
return -1;
}
res = _PyObject_CallMethodId(module, &PyId_enable, NULL);
Py_DECREF(module);
if (res == NULL)
PyObject *key = PyUnicode_FromString("faulthandler");
if (key == NULL) {
return -1;
Py_DECREF(res);
return 0;
}
int has_key = PyDict_Contains(xoptions, key);
Py_DECREF(key);
return has_key;
}
int _PyFaulthandler_Init(void)
_PyInitError
_PyFaulthandler_Init(void)
{
#ifdef HAVE_SIGALTSTACK
int err;
@ -1345,14 +1352,22 @@ int _PyFaulthandler_Init(void)
thread.cancel_event = PyThread_allocate_lock();
thread.running = PyThread_allocate_lock();
if (!thread.cancel_event || !thread.running) {
PyErr_SetString(PyExc_RuntimeError,
"could not allocate locks for faulthandler");
return -1;
return _Py_INIT_ERR("failed to allocate locks for faulthandler");
}
PyThread_acquire_lock(thread.cancel_event, 1);
#endif
return faulthandler_env_options();
int enable = faulthandler_init_parse();
if (enable < 0) {
return _Py_INIT_ERR("failed to parse faulthandler env var and cmdline");
}
if (enable) {
if (faulthandler_init_enable() < 0) {
return _Py_INIT_ERR("failed to enable faulthandler");
}
}
return _Py_INIT_OK();
}
void _PyFaulthandler_Fini(void)