diff options
Diffstat (limited to 'Python/pylifecycle.c')
| -rw-r--r-- | Python/pylifecycle.c | 176 | 
1 files changed, 125 insertions, 51 deletions
| diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index ce52990..a4f7f82 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -31,6 +31,9 @@  #ifdef MS_WINDOWS  #undef BYTE  #include "windows.h" + +extern PyTypeObject PyWindowsConsoleIO_Type; +#define PyWindowsConsoleIO_Check(op) (PyObject_TypeCheck((op), &PyWindowsConsoleIO_Type))  #endif  _Py_IDENTIFIER(flush); @@ -90,6 +93,10 @@ int Py_NoUserSiteDirectory = 0; /* for -s and site.py */  int Py_UnbufferedStdioFlag = 0; /* Unbuffered binary std{in,out,err} */  int Py_HashRandomizationFlag = 0; /* for -R and PYTHONHASHSEED */  int Py_IsolatedFlag = 0; /* for -I, isolate from user's env */ +#ifdef MS_WINDOWS +int Py_LegacyWindowsFSEncodingFlag = 0; /* Uses mbcs instead of utf-8 */ +int Py_LegacyWindowsStdioFlag = 0; /* Uses FileIO instead of WindowsConsoleIO */ +#endif  PyThreadState *_Py_Finalizing = NULL; @@ -151,11 +158,17 @@ Py_SetStandardStreamEncoding(const char *encoding, const char *errors)              return -3;          }      } +#ifdef MS_WINDOWS +    if (_Py_StandardStreamEncoding) { +        /* Overriding the stream encoding implies legacy streams */ +        Py_LegacyWindowsStdioFlag = 1; +    } +#endif      return 0;  } -/* Global initializations.  Can be undone by Py_Finalize().  Don't -   call this twice without an intervening Py_Finalize() call.  When +/* Global initializations.  Can be undone by Py_FinalizeEx().  Don't +   call this twice without an intervening Py_FinalizeEx() call.  When     initializations fail, a fatal error is issued and the function does     not return.  On return, the first thread and interpreter state have     been created. @@ -192,7 +205,7 @@ get_codec_name(const char *encoding)      if (!name)          goto error; -    name_utf8 = _PyUnicode_AsString(name); +    name_utf8 = PyUnicode_AsUTF8(name);      if (name_utf8 == NULL)          goto error;      name_str = _PyMem_RawStrdup(name_utf8); @@ -223,6 +236,8 @@ get_locale_encoding(void)          return NULL;      }      return get_codec_name(codeset); +#elif defined(__ANDROID__) +    return get_codec_name("UTF-8");  #else      PyErr_SetNone(PyExc_NotImplementedError);      return NULL; @@ -252,6 +267,11 @@ import_init(PyInterpreterState *interp, PyObject *sysmod)      interp->importlib = importlib;      Py_INCREF(interp->importlib); +    interp->import_func = PyDict_GetItemString(interp->builtins, "__import__"); +    if (interp->import_func == NULL) +        Py_FatalError("Py_Initialize: __import__ not found"); +    Py_INCREF(interp->import_func); +      /* Import the _imp module */      impmod = PyInit_imp();      if (impmod == NULL) { @@ -295,7 +315,7 @@ _Py_InitializeEx_Private(int install_sigs, int install_importlib)      initialized = 1;      _Py_Finalizing = NULL; -#if defined(HAVE_LANGINFO_H) && defined(HAVE_SETLOCALE) +#ifdef HAVE_SETLOCALE      /* Set up the LC_CTYPE locale, so we can obtain         the locale's charset without having to switch         locales. */ @@ -314,6 +334,12 @@ _Py_InitializeEx_Private(int install_sigs, int install_importlib)         check its value further. */      if ((p = Py_GETENV("PYTHONHASHSEED")) && *p != '\0')          Py_HashRandomizationFlag = add_flag(Py_HashRandomizationFlag, p); +#ifdef MS_WINDOWS +    if ((p = Py_GETENV("PYTHONLEGACYWINDOWSFSENCODING")) && *p != '\0') +        Py_LegacyWindowsFSEncodingFlag = add_flag(Py_LegacyWindowsFSEncodingFlag, p); +    if ((p = Py_GETENV("PYTHONLEGACYWINDOWSSTDIO")) && *p != '\0') +        Py_LegacyWindowsStdioFlag = add_flag(Py_LegacyWindowsStdioFlag, p); +#endif      _PyRandom_Init(); @@ -327,11 +353,11 @@ _Py_InitializeEx_Private(int install_sigs, int install_importlib)      (void) PyThreadState_Swap(tstate);  #ifdef WITH_THREAD -    /* We can't call _PyEval_FiniThreads() in Py_Finalize because +    /* We can't call _PyEval_FiniThreads() in Py_FinalizeEx because         destroying the GIL might fail when it is being referenced from         another running thread (see issue #9901).         Instead we destroy the previously created GIL here, which ensures -       that we can call Py_Initialize / Py_Finalize multiple times. */ +       that we can call Py_Initialize / Py_FinalizeEx multiple times. */      _PyEval_FiniThreads();      /* Auto-thread-state API */ @@ -477,28 +503,35 @@ file_is_closed(PyObject *fobj)      return r > 0;  } -static void +static int  flush_std_files(void)  {      PyObject *fout = _PySys_GetObjectId(&PyId_stdout);      PyObject *ferr = _PySys_GetObjectId(&PyId_stderr);      PyObject *tmp; +    int status = 0;      if (fout != NULL && fout != Py_None && !file_is_closed(fout)) { -        tmp = _PyObject_CallMethodId(fout, &PyId_flush, ""); -        if (tmp == NULL) +        tmp = _PyObject_CallMethodId(fout, &PyId_flush, NULL); +        if (tmp == NULL) {              PyErr_WriteUnraisable(fout); +            status = -1; +        }          else              Py_DECREF(tmp);      }      if (ferr != NULL && ferr != Py_None && !file_is_closed(ferr)) { -        tmp = _PyObject_CallMethodId(ferr, &PyId_flush, ""); -        if (tmp == NULL) +        tmp = _PyObject_CallMethodId(ferr, &PyId_flush, NULL); +        if (tmp == NULL) {              PyErr_Clear(); +            status = -1; +        }          else              Py_DECREF(tmp);      } + +    return status;  }  /* Undo the effect of Py_Initialize(). @@ -515,14 +548,15 @@ flush_std_files(void)  */ -void -Py_Finalize(void) +int +Py_FinalizeEx(void)  {      PyInterpreterState *interp;      PyThreadState *tstate; +    int status = 0;      if (!initialized) -        return; +        return status;      wait_for_thread_shutdown(); @@ -547,7 +581,9 @@ Py_Finalize(void)      initialized = 0;      /* Flush sys.stdout and sys.stderr */ -    flush_std_files(); +    if (flush_std_files() < 0) { +        status = -1; +    }      /* Disable signal handling */      PyOS_FiniInterrupts(); @@ -564,19 +600,21 @@ Py_Finalize(void)       * XXX but I'm unclear on exactly how that one happens.  In any case,       * XXX I haven't seen a real-life report of either of these.       */ -    PyGC_Collect(); +    _PyGC_CollectIfEnabled();  #ifdef COUNT_ALLOCS      /* With COUNT_ALLOCS, it helps to run GC multiple times:         each collection might release some types from the type         list, so they become garbage. */ -    while (PyGC_Collect() > 0) +    while (_PyGC_CollectIfEnabled() > 0)          /* nothing */;  #endif      /* Destroy all modules */      PyImport_Cleanup();      /* Flush sys.stdout and sys.stderr (again, in case more was printed) */ -    flush_std_files(); +    if (flush_std_files() < 0) { +        status = -1; +    }      /* Collect final garbage.  This disposes of cycles created by       * class definitions, for example. @@ -594,7 +632,7 @@ Py_Finalize(void)       * XXX Python code getting called.       */  #if 0 -    PyGC_Collect(); +    _PyGC_CollectIfEnabled();  #endif      /* Disable tracemalloc after all Python objects have been destroyed, @@ -612,7 +650,7 @@ Py_Finalize(void)      /* Debugging stuff */  #ifdef COUNT_ALLOCS -    dump_counts(stdout); +    dump_counts(stderr);  #endif      /* dump hash stats */      _PyHash_Fini(); @@ -655,6 +693,8 @@ Py_Finalize(void)      PySlice_Fini();      _PyGC_Fini();      _PyRandom_Fini(); +    _PyArg_Fini(); +    PyAsyncGen_Fini();      /* Cleanup Unicode implementation */      _PyUnicode_Fini(); @@ -680,6 +720,7 @@ Py_Finalize(void)      /* Delete current thread. After this, many C API calls become crashy. */      PyThreadState_Swap(NULL); +      PyInterpreterState_Delete(interp);  #ifdef Py_TRACE_REFS @@ -690,12 +731,22 @@ Py_Finalize(void)      if (Py_GETENV("PYTHONDUMPREFS"))          _Py_PrintReferenceAddresses(stderr);  #endif /* Py_TRACE_REFS */ -#ifdef PYMALLOC_DEBUG -    if (Py_GETENV("PYTHONMALLOCSTATS")) -        _PyObject_DebugMallocStats(stderr); +#ifdef WITH_PYMALLOC +    if (_PyMem_PymallocEnabled()) { +        char *opt = Py_GETENV("PYTHONMALLOCSTATS"); +        if (opt != NULL && *opt != '\0') +            _PyObject_DebugMallocStats(stderr); +    }  #endif      call_ll_exitfuncs(); +    return status; +} + +void +Py_Finalize(void) +{ +    Py_FinalizeEx();  }  /* Create and initialize a new interpreter and thread, and return the @@ -721,6 +772,12 @@ Py_NewInterpreter(void)      if (!initialized)          Py_FatalError("Py_NewInterpreter: call Py_Initialize first"); +#ifdef WITH_THREAD +    /* Issue #10915, #15751: The GIL API doesn't work with multiple +       interpreters: disable PyGILState_Check(). */ +    _PyGILState_check_enabled = 0; +#endif +      interp = PyInterpreterState_New();      if (interp == NULL)          return NULL; @@ -777,7 +834,7 @@ Py_NewInterpreter(void)          if (initstdio() < 0)              Py_FatalError( -            "Py_Initialize: can't initialize sys standard streams"); +                "Py_Initialize: can't initialize sys standard streams");          initmain(interp);          if (!Py_NoSiteFlag)              initsite(); @@ -803,7 +860,7 @@ handle_error:     frames, and that it is its interpreter's only remaining thread.     It is a fatal error to violate these constraints. -   (Py_Finalize() doesn't have these constraints -- it zaps +   (Py_FinalizeEx() doesn't have these constraints -- it zaps     everything, regardless.)     Locking: as above. @@ -881,11 +938,17 @@ Py_GetPythonHome(void)  static void  initmain(PyInterpreterState *interp)  { -    PyObject *m, *d, *loader; +    PyObject *m, *d, *loader, *ann_dict;      m = PyImport_AddModule("__main__");      if (m == NULL)          Py_FatalError("can't create __main__ module");      d = PyModule_GetDict(m); +    ann_dict = PyDict_New(); +    if ((ann_dict == NULL) || +        (PyDict_SetItemString(d, "__annotations__", ann_dict) < 0)) { +        Py_FatalError("Failed to initialize __main__.__annotations__"); +    } +    Py_DECREF(ann_dict);      if (PyDict_GetItemString(d, "__builtins__") == NULL) {          PyObject *bimod = PyImport_ImportModule("builtins");          if (bimod == NULL) { @@ -921,6 +984,18 @@ initfsencoding(PyInterpreterState *interp)  {      PyObject *codec; +#ifdef MS_WINDOWS +    if (Py_LegacyWindowsFSEncodingFlag) +    { +        Py_FileSystemDefaultEncoding = "mbcs"; +        Py_FileSystemDefaultEncodeErrors = "replace"; +    } +    else +    { +        Py_FileSystemDefaultEncoding = "utf-8"; +        Py_FileSystemDefaultEncodeErrors = "surrogatepass"; +    } +#else      if (Py_FileSystemDefaultEncoding == NULL)      {          Py_FileSystemDefaultEncoding = get_locale_encoding(); @@ -931,6 +1006,7 @@ initfsencoding(PyInterpreterState *interp)          interp->fscodec_initialized = 1;          return 0;      } +#endif      /* the encoding is mbcs, utf-8 or ascii */      codec = _PyCodec_Lookup(Py_FileSystemDefaultEncoding); @@ -969,9 +1045,12 @@ static int  is_valid_fd(int fd)  {      int fd2; -    if (fd < 0 || !_PyVerify_fd(fd)) +    if (fd < 0)          return 0;      _Py_BEGIN_SUPPRESS_IPH +    /* Prefer dup() over fstat(). fstat() can require input/output whereas +       dup() doesn't, there is a low risk of EMFILE/ENFILE at Python +       startup. */      fd2 = dup(fd);      if (fd2 >= 0)          close(fd2); @@ -982,8 +1061,8 @@ is_valid_fd(int fd)  /* returns Py_None if the fd is not valid */  static PyObject*  create_stdio(PyObject* io, -    int fd, int write_mode, char* name, -    char* encoding, char* errors) +    int fd, int write_mode, const char* name, +    const char* encoding, const char* errors)  {      PyObject *buf = NULL, *stream = NULL, *text = NULL, *raw = NULL, *res;      const char* mode; @@ -1013,7 +1092,8 @@ create_stdio(PyObject* io,          mode = "rb";      buf = _PyObject_CallMethodId(io, &PyId_open, "isiOOOi",                                   fd, mode, buffering, -                                 Py_None, Py_None, Py_None, 0); +                                 Py_None, Py_None, /* encoding, errors */ +                                 Py_None, 0); /* newline, closefd */      if (buf == NULL)          goto error; @@ -1028,10 +1108,16 @@ create_stdio(PyObject* io,          Py_INCREF(raw);      } +#ifdef MS_WINDOWS +    /* Windows console IO is always UTF-8 encoded */ +    if (PyWindowsConsoleIO_Check(raw)) +        encoding = "utf-8"; +#endif +      text = PyUnicode_FromString(name);      if (text == NULL || _PyObject_SetAttrId(raw, &PyId_name, text) < 0)          goto error; -    res = _PyObject_CallMethodId(raw, &PyId_isatty, ""); +    res = _PyObject_CallMethodId(raw, &PyId_isatty, NULL);      if (res == NULL)          goto error;      isatty = PyObject_IsTrue(res); @@ -1199,7 +1285,7 @@ initstdio(void)      encoding_attr = PyObject_GetAttrString(std, "encoding");      if (encoding_attr != NULL) {          const char * std_encoding; -        std_encoding = _PyUnicode_AsString(encoding_attr); +        std_encoding = PyUnicode_AsUTF8(encoding_attr);          if (std_encoding != NULL) {              PyObject *codec_info = _PyCodec_Lookup(std_encoding);              Py_XDECREF(codec_info); @@ -1243,25 +1329,11 @@ initstdio(void)  static void  _Py_FatalError_DumpTracebacks(int fd)  { -    PyThreadState *tstate; - -#ifdef WITH_THREAD -    /* PyGILState_GetThisThreadState() works even if the GIL was released */ -    tstate = PyGILState_GetThisThreadState(); -#else -    tstate = PyThreadState_GET(); -#endif -    if (tstate == NULL) { -        /* _Py_DumpTracebackThreads() requires the thread state to display -         * frames */ -        return; -    } -      fputc('\n', stderr);      fflush(stderr);      /* display the current Python stack */ -    _Py_DumpTracebackThreads(fd, tstate->interp, tstate); +    _Py_DumpTracebackThreads(fd, NULL, NULL);  }  /* Print the current exception (if an exception is set) with its traceback, @@ -1316,7 +1388,7 @@ _Py_FatalError_PrintExc(int fd)      Py_XDECREF(tb);      /* sys.stderr may be buffered: call sys.stderr.flush() */ -    res = _PyObject_CallMethodId(ferr, &PyId_flush, ""); +    res = _PyObject_CallMethodId(ferr, &PyId_flush, NULL);      if (res == NULL)          PyErr_Clear();      else @@ -1388,7 +1460,7 @@ exit:  /* Clean up and exit */  #ifdef WITH_THREAD -#include "pythread.h" +#  include "pythread.h"  #endif  static void (*pyexitfunc)(void) = NULL; @@ -1426,7 +1498,7 @@ wait_for_thread_shutdown(void)          PyErr_Clear();          return;      } -    result = _PyObject_CallMethodId(threading, &PyId__shutdown, ""); +    result = _PyObject_CallMethodId(threading, &PyId__shutdown, NULL);      if (result == NULL) {          PyErr_WriteUnraisable(threading);      } @@ -1462,7 +1534,9 @@ call_ll_exitfuncs(void)  void  Py_Exit(int sts)  { -    Py_Finalize(); +    if (Py_FinalizeEx() < 0) { +        sts = 120; +    }      exit(sts);  } | 
