diff options
Diffstat (limited to 'Python/pylifecycle.c')
-rw-r--r-- | Python/pylifecycle.c | 164 |
1 files changed, 119 insertions, 45 deletions
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index ce52990496..f93afd234d 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. @@ -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) { @@ -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(); @@ -576,7 +612,9 @@ Py_Finalize(void) 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. @@ -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); @@ -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); } |