/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│ │vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Python 3 │ │ https://docs.python.org/3/license.html │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/dce.h" #include "libc/fmt/conv.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/sysv/consts/sig.h" #include "libc/unicode/locale.h" #include "third_party/python/Include/Python-ast.h" #include "third_party/python/Include/abstract.h" #include "third_party/python/Include/ast.h" #include "third_party/python/Include/boolobject.h" #include "third_party/python/Include/code.h" #include "third_party/python/Include/codecs.h" #include "third_party/python/Include/cosmo.h" #include "third_party/python/Include/dictobject.h" #include "third_party/python/Include/errcode.h" #include "third_party/python/Include/fileobject.h" #include "third_party/python/Include/grammar.h" #include "third_party/python/Include/import.h" #include "third_party/python/Include/intrcheck.h" #include "third_party/python/Include/marshal.h" #include "third_party/python/Include/modsupport.h" #include "third_party/python/Include/node.h" #include "third_party/python/Include/objimpl.h" #include "third_party/python/Include/osdefs.h" #include "third_party/python/Include/parsetok.h" #include "third_party/python/Include/pydebug.h" #include "third_party/python/Include/pyerrors.h" #include "third_party/python/Include/pylifecycle.h" #include "third_party/python/Include/pymem.h" #include "third_party/python/Include/pystrcmp.h" #include "third_party/python/Include/pytime.h" #include "third_party/python/Include/symtable.h" #include "third_party/python/Include/sysmodule.h" #include "third_party/python/Include/token.h" #include "third_party/python/Include/traceback.h" #include "third_party/python/Include/unicodeobject.h" #include "third_party/python/Include/warnings.h" #include "third_party/python/Include/yoink.h" #include "third_party/python/pyconfig.h" /* clang-format off */ /* Python interpreter top-level routines, including init/exit */ _Py_IDENTIFIER(name); _Py_IDENTIFIER(flush); _Py_IDENTIFIER(stdout); _Py_IDENTIFIER(stderr); /* Forward */ static void wait_for_thread_shutdown(void); #ifdef WITH_THREAD extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *); extern void _PyGILState_Fini(void); #endif /* WITH_THREAD */ /* Hack to force loading of object files */ int (*_PyOS_mystrnicmp_hack)(const char *, const char *, Py_ssize_t) = \ PyOS_mystrnicmp; /* Python/pystrcmp.o */ /* Helper to allow an embedding application to override the normal * mechanism that attempts to figure out an appropriate IO encoding */ int Py_SetStandardStreamEncoding(const char *encoding, const char *errors) { if (Py_IsInitialized()) { /* This is too late to have any effect */ return -1; } /* Can't call PyErr_NoMemory() on errors, as Python hasn't been * initialised yet. * * However, the raw memory allocators are initialised appropriately * as C static variables, so _PyMem_RawStrdup is OK even though * Py_Initialize hasn't been called yet. */ if (encoding) { _Py_StandardStreamEncoding = _PyMem_RawStrdup(encoding); if (!_Py_StandardStreamEncoding) { return -2; } } if (errors) { _Py_StandardStreamErrors = _PyMem_RawStrdup(errors); if (!_Py_StandardStreamErrors) { if (_Py_StandardStreamEncoding) { PyMem_RawFree(_Py_StandardStreamEncoding); } 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_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. Locking: you must hold the interpreter lock while calling this. (If the lock has not yet been initialized, that's equivalent to having the lock, but you cannot use multiple threads.) */ static int add_flag(int flag, const char *envs) { int env = atoi(envs); if (flag < env) flag = env; if (flag < 1) flag = 1; return flag; } void _Py_InitializeEx_Private(int install_sigs, int install_importlib) { PyInterpreterState *interp; PyThreadState *tstate; PyObject *bimod, *sysmod, *pstderr; char *p; if (_Py_initialized) return; _Py_initialized = 1; _Py_Finalizing = NULL; #ifdef HAVE_SETLOCALE /* Set up the LC_CTYPE locale, so we can obtain the locale's charset without having to switch locales. */ setlocale(LC_CTYPE, ""); #endif if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '\0') Py_DebugFlag = add_flag(Py_DebugFlag, p); if ((p = Py_GETENV("PYTHONVERBOSE")) && *p != '\0') Py_VerboseFlag = add_flag(Py_VerboseFlag, p); if ((p = Py_GETENV("PYTHONOPTIMIZE")) && *p != '\0') Py_OptimizeFlag = add_flag(Py_OptimizeFlag, p); if ((p = Py_GETENV("PYTHONDONTWRITEBYTECODE")) && *p != '\0') Py_DontWriteBytecodeFlag = add_flag(Py_DontWriteBytecodeFlag, 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(); interp = PyInterpreterState_New(); if (interp == NULL) Py_FatalError("Py_Initialize: can't make first interpreter"); tstate = PyThreadState_New(interp); if (tstate == NULL) Py_FatalError("Py_Initialize: can't make first thread"); (void) PyThreadState_Swap(tstate); #ifdef WITH_THREAD /* 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_FinalizeEx multiple times. */ _PyEval_FiniThreads(); /* Auto-thread-state API */ _PyGILState_Init(interp, tstate); #endif /* WITH_THREAD */ _Py_ReadyTypes(); if (!_PyFrame_Init()) Py_FatalError("Py_Initialize: can't init frames"); if (!_PyLong_Init()) Py_FatalError("Py_Initialize: can't init longs"); if (!PyByteArray_Init()) Py_FatalError("Py_Initialize: can't init bytearray"); if (!_PyFloat_Init()) Py_FatalError("Py_Initialize: can't init float"); interp->modules = PyDict_New(); if (interp->modules == NULL) Py_FatalError("Py_Initialize: can't make modules dictionary"); /* Init Unicode implementation; relies on the codec registry */ if (_PyUnicode_Init() < 0) Py_FatalError("Py_Initialize: can't initialize unicode"); if (_PyStructSequence_Init() < 0) Py_FatalError("Py_Initialize: can't initialize structseq"); bimod = _PyBuiltin_Init(); if (bimod == NULL) Py_FatalError("Py_Initialize: can't initialize builtins modules"); _PyImport_FixupBuiltin(bimod, "builtins"); interp->builtins = PyModule_GetDict(bimod); if (interp->builtins == NULL) Py_FatalError("Py_Initialize: can't initialize builtins dict"); Py_INCREF(interp->builtins); /* initialize builtin exceptions */ _PyExc_Init(bimod); sysmod = _PySys_Init(); if (sysmod == NULL) Py_FatalError("Py_Initialize: can't initialize sys"); interp->sysdict = PyModule_GetDict(sysmod); if (interp->sysdict == NULL) Py_FatalError("Py_Initialize: can't initialize sys dict"); Py_INCREF(interp->sysdict); _PyImport_FixupBuiltin(sysmod, "sys"); PySys_SetPath(Py_GetPath()); PyDict_SetItemString(interp->sysdict, "modules", interp->modules); /* Set up a preliminary stderr printer until we have enough infrastructure for the io module in place. */ pstderr = PyFile_NewStdPrinter(fileno(stderr)); if (pstderr == NULL) Py_FatalError("Py_Initialize: can't set preliminary stderr"); _PySys_SetObjectId(&PyId_stderr, pstderr); PySys_SetObject("__stderr__", pstderr); Py_DECREF(pstderr); _PyImportLookupTables_Init(); _PyImport_Init(); _PyImportHooks_Init(); /* Initialize _warnings. */ _PyWarnings_Init(); if (!install_importlib) return; if (_PyTime_Init() < 0) Py_FatalError("Py_Initialize: can't initialize time"); _Py_InitImport(interp, sysmod); /* initialize the faulthandler module */ if (_PyFaulthandler_Init()) Py_FatalError("Py_Initialize: can't initialize faulthandler"); if (_Py_InitFsEncoding(interp) < 0) Py_FatalError("Py_Initialize: unable to load the file system codec"); if (install_sigs) _Py_InitSigs(); /* Signal handling stuff, including initintr() */ #if IsModeDbg() if (_PyTraceMalloc_Init() < 0) Py_FatalError("Py_Initialize: can't initialize tracemalloc"); #endif _Py_InitMain(interp); /* Module __main__ */ if (_Py_InitStdio() < 0) { Py_FatalError( "Py_Initialize: can't initialize sys standard streams"); } /* Initialize warnings. */ if (PySys_HasWarnOptions()) { PyObject *warnings_module = PyImport_ImportModule("warnings"); if (warnings_module == NULL) { fputs("'import warnings' failed; traceback:\n", stderr); PyErr_Print(); } Py_XDECREF(warnings_module); } _PyImportZip_Init(); if (!Py_NoSiteFlag) _Py_InitSite(); /* Module site */ } void Py_InitializeEx(int install_sigs) { _Py_InitializeEx_Private(install_sigs, 1); } void Py_Initialize(void) { Py_InitializeEx(1); } #ifdef COUNT_ALLOCS extern void dump_counts(FILE*); #endif /* Create and initialize a new interpreter and thread, and return the new thread. This requires that Py_Initialize() has been called first. Unsuccessful initialization yields a NULL pointer. Note that *no* exception information is available even in this case -- the exception information is held in the thread, and there is no thread. Locking: as above. */ PyThreadState * Py_NewInterpreter(void) { PyInterpreterState *interp; PyThreadState *tstate, *save_tstate; PyObject *bimod, *sysmod; if (!_Py_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; tstate = PyThreadState_New(interp); if (tstate == NULL) { PyInterpreterState_Delete(interp); return NULL; } save_tstate = PyThreadState_Swap(tstate); /* XXX The following is lax in error checking */ interp->modules = PyDict_New(); bimod = _PyImport_FindBuiltin("builtins"); if (bimod != NULL) { interp->builtins = PyModule_GetDict(bimod); if (interp->builtins == NULL) goto handle_error; Py_INCREF(interp->builtins); } else if (PyErr_Occurred()) { goto handle_error; } /* initialize builtin exceptions */ _PyExc_Init(bimod); sysmod = _PyImport_FindBuiltin("sys"); if (bimod != NULL && sysmod != NULL) { PyObject *pstderr; interp->sysdict = PyModule_GetDict(sysmod); if (interp->sysdict == NULL) goto handle_error; Py_INCREF(interp->sysdict); PySys_SetPath(Py_GetPath()); PyDict_SetItemString(interp->sysdict, "modules", interp->modules); /* Set up a preliminary stderr printer until we have enough infrastructure for the io module in place. */ pstderr = PyFile_NewStdPrinter(fileno(stderr)); if (pstderr == NULL) Py_FatalError("Py_Initialize: can't set preliminary stderr"); _PySys_SetObjectId(&PyId_stderr, pstderr); PySys_SetObject("__stderr__", pstderr); Py_DECREF(pstderr); _PyImportHooks_Init(); _Py_InitImport(interp, sysmod); if (_Py_InitFsEncoding(interp) < 0) goto handle_error; if (_Py_InitStdio() < 0) Py_FatalError( "Py_Initialize: can't initialize sys standard streams"); _Py_InitMain(interp); if (!Py_NoSiteFlag) _Py_InitSite(); } if (!PyErr_Occurred()) return tstate; handle_error: /* Oops, it didn't work. Undo it all. */ PyErr_PrintEx(0); PyThreadState_Clear(tstate); PyThreadState_Swap(save_tstate); PyThreadState_Delete(tstate); PyInterpreterState_Delete(interp); return NULL; } /* Delete an interpreter and its last thread. This requires that the given thread state is current, that the thread has no remaining frames, and that it is its interpreter's only remaining thread. It is a fatal error to violate these constraints. (Py_FinalizeEx() doesn't have these constraints -- it zaps everything, regardless.) Locking: as above. */ void Py_EndInterpreter(PyThreadState *tstate) { PyInterpreterState *interp = tstate->interp; if (tstate != PyThreadState_GET()) Py_FatalError("Py_EndInterpreter: thread is not current"); if (tstate->frame != NULL) Py_FatalError("Py_EndInterpreter: thread still has a frame"); wait_for_thread_shutdown(); if (tstate != interp->tstate_head || tstate->next != NULL) Py_FatalError("Py_EndInterpreter: not the last thread"); PyImport_Cleanup(); PyInterpreterState_Clear(interp); PyThreadState_Swap(NULL); PyInterpreterState_Delete(interp); } /* Clean up and exit */ #ifdef WITH_THREAD #include "third_party/python/Include/pythread.h" #endif /* Wait until threading._shutdown completes, provided the threading module was imported in the first place. The shutdown routine will wait until all non-daemon "threading" threads have completed. */ static void wait_for_thread_shutdown(void) { #ifdef WITH_THREAD _Py_IDENTIFIER(_shutdown); PyObject *result; PyThreadState *tstate = PyThreadState_GET(); PyObject *threading = PyMapping_GetItemString(tstate->interp->modules, "threading"); if (threading == NULL) { /* threading not imported */ PyErr_Clear(); return; } result = _PyObject_CallMethodId(threading, &PyId__shutdown, NULL); if (result == NULL) { PyErr_WriteUnraisable(threading); } else { Py_DECREF(result); } Py_DECREF(threading); #endif } void Py_Exit(int sts) { if (Py_FinalizeEx() < 0) { sts = 120; } exit(sts); }