From 25ce566661c1b7446b3ddb4076513a62f93ce08d Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 2 Aug 1997 03:10:38 +0000 Subject: The last of the mass checkins for separate (sub)interpreters. Everything should now work again. See the comments for the .h files mass checkin (e.g. pystate.h) for more detail. --- Python/bltinmodule.c | 121 +++++++++++++++---------- Python/ceval.c | 29 ++++-- Python/import.c | 166 +++++++++++++++++++++++---------- Python/importdl.c | 14 ++- Python/pystate.c | 128 ++++++++++++++++++++------ Python/pythonrun.c | 252 +++++++++++++++++++++++++++++++++++++++------------ Python/sysmodule.c | 50 +++++----- 7 files changed, 542 insertions(+), 218 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 245d31e..439498d 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -1668,21 +1668,6 @@ static PyMethodDef builtin_methods[] = { {NULL, NULL}, }; -static PyObject *builtin_mod; -static PyObject *builtin_dict; - -PyObject * -PyBuiltin_GetModule() -{ - return builtin_mod; -} - -PyObject * -PyBuiltin_GetDict() -{ - return builtin_dict; -} - /* Predefined exceptions */ PyObject *PyExc_AccessError; @@ -1707,54 +1692,90 @@ PyObject *PyExc_ValueError; PyObject *PyExc_ZeroDivisionError; static PyObject * -newstdexception(name) +newstdexception(dict, name) + PyObject *dict; char *name; { PyObject *v = PyString_FromString(name); - if (v == NULL || PyDict_SetItemString(builtin_dict, name, v) != 0) + if (v == NULL || PyDict_SetItemString(dict, name, v) != 0) Py_FatalError("no mem for new standard exception"); return v; } static void -initerrors() +initerrors(dict) + PyObject *dict; { - PyExc_AccessError = newstdexception("AccessError"); - PyExc_AssertionError = newstdexception("AssertionError"); - PyExc_AttributeError = newstdexception("AttributeError"); - PyExc_EOFError = newstdexception("EOFError"); - PyExc_FloatingPointError = newstdexception("FloatingPointError"); - PyExc_IOError = newstdexception("IOError"); - PyExc_ImportError = newstdexception("ImportError"); - PyExc_IndexError = newstdexception("IndexError"); - PyExc_KeyError = newstdexception("KeyError"); - PyExc_KeyboardInterrupt = newstdexception("KeyboardInterrupt"); - PyExc_MemoryError = newstdexception("MemoryError"); - PyExc_NameError = newstdexception("NameError"); - PyExc_OverflowError = newstdexception("OverflowError"); - PyExc_RuntimeError = newstdexception("RuntimeError"); - PyExc_SyntaxError = newstdexception("SyntaxError"); - PyExc_SystemError = newstdexception("SystemError"); - PyExc_SystemExit = newstdexception("SystemExit"); - PyExc_TypeError = newstdexception("TypeError"); - PyExc_ValueError = newstdexception("ValueError"); - PyExc_ZeroDivisionError = newstdexception("ZeroDivisionError"); + PyExc_AccessError = newstdexception(dict, "AccessError"); + PyExc_AssertionError = newstdexception(dict, "AssertionError"); + PyExc_AttributeError = newstdexception(dict, "AttributeError"); + PyExc_EOFError = newstdexception(dict, "EOFError"); + PyExc_FloatingPointError = newstdexception(dict, "FloatingPointError"); + PyExc_IOError = newstdexception(dict, "IOError"); + PyExc_ImportError = newstdexception(dict, "ImportError"); + PyExc_IndexError = newstdexception(dict, "IndexError"); + PyExc_KeyError = newstdexception(dict, "KeyError"); + PyExc_KeyboardInterrupt = newstdexception(dict, "KeyboardInterrupt"); + PyExc_MemoryError = newstdexception(dict, "MemoryError"); + PyExc_NameError = newstdexception(dict, "NameError"); + PyExc_OverflowError = newstdexception(dict, "OverflowError"); + PyExc_RuntimeError = newstdexception(dict, "RuntimeError"); + PyExc_SyntaxError = newstdexception(dict, "SyntaxError"); + PyExc_SystemError = newstdexception(dict, "SystemError"); + PyExc_SystemExit = newstdexception(dict, "SystemExit"); + PyExc_TypeError = newstdexception(dict, "TypeError"); + PyExc_ValueError = newstdexception(dict, "ValueError"); + PyExc_ZeroDivisionError = newstdexception(dict, "ZeroDivisionError"); +} + +static void +finierrors() +{ + Py_XDECREF(PyExc_AccessError); PyExc_AccessError = NULL; + Py_XDECREF(PyExc_AssertionError); PyExc_AssertionError = NULL; + Py_XDECREF(PyExc_AttributeError); PyExc_AttributeError = NULL; + Py_XDECREF(PyExc_EOFError); PyExc_EOFError = NULL; + Py_XDECREF(PyExc_FloatingPointError); PyExc_FloatingPointError = NULL; + Py_XDECREF(PyExc_IOError); PyExc_IOError = NULL; + Py_XDECREF(PyExc_ImportError); PyExc_ImportError = NULL; + Py_XDECREF(PyExc_IndexError); PyExc_IndexError = NULL; + Py_XDECREF(PyExc_KeyError); PyExc_KeyError = NULL; + Py_XDECREF(PyExc_KeyboardInterrupt); PyExc_KeyboardInterrupt = NULL; + Py_XDECREF(PyExc_MemoryError); PyExc_MemoryError = NULL; + Py_XDECREF(PyExc_NameError); PyExc_NameError = NULL; + Py_XDECREF(PyExc_OverflowError); PyExc_OverflowError = NULL; + Py_XDECREF(PyExc_RuntimeError); PyExc_RuntimeError = NULL; + Py_XDECREF(PyExc_SyntaxError); PyExc_SyntaxError = NULL; + Py_XDECREF(PyExc_SystemError); PyExc_SystemError = NULL; + Py_XDECREF(PyExc_SystemExit); PyExc_SystemExit = NULL; + Py_XDECREF(PyExc_TypeError); PyExc_TypeError = NULL; + Py_XDECREF(PyExc_ValueError); PyExc_ValueError = NULL; + Py_XDECREF(PyExc_ZeroDivisionError); PyExc_ZeroDivisionError = NULL; +} + +PyObject * +_PyBuiltin_Init() +{ + PyObject *mod, *dict; + mod = Py_InitModule("__builtin__", builtin_methods); + if (mod == NULL) + return NULL; + dict = PyModule_GetDict(mod); + initerrors(dict); + if (PyDict_SetItemString(dict, "None", Py_None) < 0) + return NULL; + if (PyDict_SetItemString(dict, "Ellipsis", Py_Ellipsis) < 0) + return NULL; + if (PyDict_SetItemString(dict, "__debug__", + PyInt_FromLong(Py_OptimizeFlag == 0)) < 0) + return NULL; + return mod; } void -PyBuiltin_Init() +_PyBuiltin_Fini() { - builtin_mod = Py_InitModule("__builtin__", builtin_methods); - builtin_dict = PyModule_GetDict(builtin_mod); - Py_INCREF(builtin_dict); - initerrors(); - (void) PyDict_SetItemString(builtin_dict, "None", Py_None); - (void) PyDict_SetItemString(builtin_dict, "Ellipsis", Py_Ellipsis); - (void) PyDict_SetItemString(builtin_dict, "__debug__", - PyInt_FromLong(Py_OptimizeFlag == 0)); - if (PyErr_Occurred()) - Py_FatalError( - "error creating None/Ellipsis/__debug__ in __builtin__"); + finierrors(); } diff --git a/Python/ceval.c b/Python/ceval.c index 205d8d4..bb0fb65 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -130,6 +130,18 @@ PyEval_InitThreads() } void +PyEval_AcquireLock() +{ + acquire_lock(interpreter_lock, 1); +} + +void +PyEval_ReleaseLock() +{ + release_lock(interpreter_lock); +} + +void PyEval_AcquireThread(tstate) PyThreadState *tstate; { @@ -402,9 +414,6 @@ eval_code2(co, globals, locals, /* Start of code */ - if (tstate == NULL) - Py_FatalError("eval_code2 called without a current thread"); - #ifdef USE_STACKCHECK if (tstate->recursion_depth%10 == 0 && PyOS_CheckStack()) { PyErr_SetString(PyExc_MemoryError, "Stack overflow"); @@ -590,7 +599,7 @@ eval_code2(co, globals, locals, Py_MakePendingCalls() above. */ if (things_to_do || --tstate->ticker < 0) { - tstate->ticker = tstate->sys_checkinterval; + tstate->ticker = tstate->interp->checkinterval; if (things_to_do) { if (Py_MakePendingCalls() < 0) { why = WHY_EXCEPTION; @@ -612,14 +621,15 @@ eval_code2(co, globals, locals, if (interpreter_lock) { /* Give another thread a chance */ - PyThreadState *tstate = - PyThreadState_Swap(NULL); + if (PyThreadState_Swap(NULL) != tstate) + Py_FatalError("ceval: tstate mix-up"); release_lock(interpreter_lock); /* Other threads may run now */ acquire_lock(interpreter_lock, 1); - PyThreadState_Swap(tstate); + if (PyThreadState_Swap(tstate) != NULL) + Py_FatalError("ceval: orphan tstate"); } #endif } @@ -2176,9 +2186,10 @@ call_trace(p_trace, p_newtrace, f, msg, arg) PyObject * PyEval_GetBuiltins() { - PyFrameObject *current_frame = PyThreadState_Get()->frame; + PyThreadState *tstate = PyThreadState_Get(); + PyFrameObject *current_frame = tstate->frame; if (current_frame == NULL) - return PyBuiltin_GetModule(); + return tstate->interp->builtins; else return current_frame->f_builtins; } diff --git a/Python/import.c b/Python/import.c index aa1272b..2a77e5a 100644 --- a/Python/import.c +++ b/Python/import.c @@ -61,18 +61,15 @@ extern long PyOS_GetLastModificationTime(); /* In getmtime.c */ /* New way to come up with the magic number: (YEAR-1995), MONTH, DAY */ #define MAGIC (20121 | ((long)'\r'<<16) | ((long)'\n'<<24)) -static PyObject *_PyImport_Modules; /* This becomes sys.modules */ +/* See _PyImport_FixupExtension() below */ +static PyObject *extensions = NULL; /* Initialize things */ void -PyImport_Init() +_PyImport_Init() { - if (_PyImport_Modules != NULL) - Py_FatalError("duplicate initimport() call"); - if ((_PyImport_Modules = PyDict_New()) == NULL) - Py_FatalError("no mem for dictionary of modules"); if (Py_OptimizeFlag) { /* Replace ".pyc" with ".pyo" in import_filetab */ struct filedescr *p; @@ -83,21 +80,44 @@ PyImport_Init() } } +void +_PyImport_Fini() +{ + Py_XDECREF(extensions); + extensions = NULL; +} + + +/* Helper for sys */ + +PyObject * +PyImport_GetModuleDict() +{ + PyInterpreterState *interp = PyThreadState_Get()->interp; + if (interp->modules == NULL) + Py_FatalError("PyImport_GetModuleDict: no module dictionary!"); + return interp->modules; +} + /* Un-initialize things, as good as we can */ void PyImport_Cleanup() { - if (_PyImport_Modules != NULL) { - PyObject *tmp = _PyImport_Modules; - _PyImport_Modules = NULL; - /* This deletes all modules from sys.modules. - When a module is deallocated, it in turn clears its - dictionary, thus hopefully breaking any circular - references between modules and between a module's - dictionary and its functions. Note that "import" - will fail while we are cleaning up. */ + PyInterpreterState *interp = PyThreadState_Get()->interp; + PyObject *tmp = interp->modules; + if (tmp != NULL) { + int pos; + PyObject *key, *value; + interp->modules = NULL; + pos = 0; + while (PyDict_Next(tmp, &pos, &key, &value)) { + if (PyModule_Check(value)) { + PyObject *d = PyModule_GetDict(value); + PyDict_Clear(d); + } + } PyDict_Clear(tmp); Py_DECREF(tmp); } @@ -113,12 +133,70 @@ PyImport_GetMagicNumber() } -/* Helper for sysmodule.c -- return modules dictionary */ +/* Magic for extension modules (built-in as well as dynamically + loaded). To prevent initializing an extension module more than + once, we keep a static dictionary 'extensions' keyed by module name + (for built-in modules) or by filename (for dynamically loaded + modules), containing these modules. A copy od the module's + dictionary is stored by calling _PyImport_FixupExtension() + immediately after the module initialization function succeeds. A + copy can be retrieved from there by calling + _PyImport_FindExtension(). */ PyObject * -PyImport_GetModuleDict() +_PyImport_FixupExtension(name, filename) + char *name; + char *filename; +{ + PyObject *modules, *mod, *dict, *copy; + if (extensions == NULL) { + extensions = PyDict_New(); + if (extensions == NULL) + return NULL; + } + modules = PyImport_GetModuleDict(); + mod = PyDict_GetItemString(modules, name); + if (mod == NULL || !PyModule_Check(mod)) { + PyErr_SetString(PyExc_SystemError, + "_PyImport_FixupExtension: module not loaded"); + return NULL; + } + dict = PyModule_GetDict(mod); + if (dict == NULL) + return NULL; + copy = PyObject_CallMethod(dict, "copy", ""); + if (copy == NULL) + return NULL; + PyDict_SetItemString(extensions, filename, copy); + Py_DECREF(copy); + return copy; +} + +PyObject * +_PyImport_FindExtension(name, filename) + char *name; + char *filename; { - return _PyImport_Modules; + PyObject *dict, *mod, *mdict, *result; + if (extensions == NULL) + return NULL; + dict = PyDict_GetItemString(extensions, filename); + if (dict == NULL) + return NULL; + mod = PyImport_AddModule(name); + if (mod == NULL) + return NULL; + mdict = PyModule_GetDict(mod); + if (mdict == NULL) + return NULL; + result = PyObject_CallMethod(mdict, "update", "O", dict); + if (result == NULL) + return NULL; + Py_DECREF(result); + if (Py_VerboseFlag) + fprintf(stderr, "import %s # previously loaded (%s)\n", + name, filename); + return mod; } @@ -132,20 +210,16 @@ PyObject * PyImport_AddModule(name) char *name; { + PyObject *modules = PyImport_GetModuleDict(); PyObject *m; - if (_PyImport_Modules == NULL) { - PyErr_SetString(PyExc_SystemError, - "sys.modules has been deleted"); - return NULL; - } - if ((m = PyDict_GetItemString(_PyImport_Modules, name)) != NULL && + if ((m = PyDict_GetItemString(modules, name)) != NULL && PyModule_Check(m)) return m; m = PyModule_New(name); if (m == NULL) return NULL; - if (PyDict_SetItemString(_PyImport_Modules, name, m) != 0) { + if (PyDict_SetItemString(modules, name, m) != 0) { Py_DECREF(m); return NULL; } @@ -163,6 +237,7 @@ PyImport_ExecCodeModule(name, co) char *name; PyObject *co; { + PyObject *modules = PyImport_GetModuleDict(); PyObject *m, *d, *v; m = PyImport_AddModule(name); @@ -183,7 +258,7 @@ PyImport_ExecCodeModule(name, co) return NULL; Py_DECREF(v); - if ((m = PyDict_GetItemString(_PyImport_Modules, name)) == NULL) { + if ((m = PyDict_GetItemString(modules, name)) == NULL) { PyErr_SetString(PyExc_SystemError, "loaded module not found in sys.modules"); return NULL; @@ -573,20 +648,27 @@ static int init_builtin(name) char *name; { - int i; - for (i = 0; _PyImport_Inittab[i].name != NULL; i++) { - if (strcmp(name, _PyImport_Inittab[i].name) == 0) { - if (_PyImport_Inittab[i].initfunc == NULL) { + PyInterpreterState *interp = PyThreadState_Get()->interp; + struct _inittab *p; + PyObject *mod; + + if ((mod = _PyImport_FindExtension(name, name)) != NULL) + return 1; + + for (p = _PyImport_Inittab; p->name != NULL; p++) { + if (strcmp(name, p->name) == 0) { + if (p->initfunc == NULL) { PyErr_SetString(PyExc_ImportError, "Cannot re-init internal module"); return -1; } if (Py_VerboseFlag) - fprintf(stderr, "import %s # builtin\n", - name); - (*_PyImport_Inittab[i].initfunc)(); + fprintf(stderr, "import %s # builtin\n", name); + (*p->initfunc)(); if (PyErr_Occurred()) return -1; + if (_PyImport_FixupExtension(name, name) == NULL) + return -1; return 1; } } @@ -666,14 +748,10 @@ PyObject * PyImport_ImportModule(name) char *name; { + PyObject *modules = PyImport_GetModuleDict(); PyObject *m; - if (_PyImport_Modules == NULL) { - PyErr_SetString(PyExc_SystemError, - "sys.modules has been deleted"); - return NULL; - } - if ((m = PyDict_GetItemString(_PyImport_Modules, name)) != NULL) { + if ((m = PyDict_GetItemString(modules, name)) != NULL) { Py_INCREF(m); } else { @@ -682,7 +760,7 @@ PyImport_ImportModule(name) (i = PyImport_ImportFrozenModule(name))) { if (i < 0) return NULL; - if ((m = PyDict_GetItemString(_PyImport_Modules, + if ((m = PyDict_GetItemString(modules, name)) == NULL) { if (PyErr_Occurred() == NULL) PyErr_SetString(PyExc_SystemError, @@ -706,6 +784,7 @@ PyObject * PyImport_ReloadModule(m) PyObject *m; { + PyObject *modules = PyImport_GetModuleDict(); char *name; int i; @@ -717,12 +796,7 @@ PyImport_ReloadModule(m) name = PyModule_GetName(m); if (name == NULL) return NULL; - if (_PyImport_Modules == NULL) { - PyErr_SetString(PyExc_SystemError, - "sys.modules has been deleted"); - return NULL; - } - if (m != PyDict_GetItemString(_PyImport_Modules, name)) { + if (m != PyDict_GetItemString(modules, name)) { PyErr_SetString(PyExc_ImportError, "reload() module not in sys.modules"); return NULL; diff --git a/Python/importdl.c b/Python/importdl.c index 44f57ac..b372e46 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -246,6 +246,10 @@ _PyImport_LoadDynamicModule(name, pathname, fp) pathname = pathbuf; } #endif + if ((m = _PyImport_FindExtension(name, pathname)) != NULL) { + Py_INCREF(m); + return m; + } sprintf(funcname, FUNCNAME_PATTERN, name); #ifdef USE_SHLIB if (fp != NULL) { @@ -518,13 +522,15 @@ _PyImport_LoadDynamicModule(name, pathname, fp) return NULL; } (*p)(); - /* XXX Need check for err_occurred() here */ + if (PyErr_Occurred()) + return NULL; + if (_PyImport_FixupExtension(name, pathname) == NULL) + return NULL; m = PyDict_GetItemString(PyImport_GetModuleDict(), name); if (m == NULL) { - if (PyErr_Occurred() == NULL) - PyErr_SetString(PyExc_SystemError, - "dynamic module not initialized properly"); + PyErr_SetString(PyExc_SystemError, + "dynamic module not initialized properly"); return NULL; } /* Remember the filename as the __file__ attribute */ diff --git a/Python/pystate.c b/Python/pystate.c index bf2bdf4..138dc09 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -33,6 +33,14 @@ PERFORMANCE OF THIS SOFTWARE. #include "Python.h" +#define ZAP(x) { \ + PyObject *tmp = (PyObject *)(x); \ + (x) = NULL; \ + Py_XDECREF(tmp); \ +} + + +static PyInterpreterState *interp_head = NULL; static PyThreadState *current_tstate = NULL; @@ -41,23 +49,65 @@ PyInterpreterState * PyInterpreterState_New() { PyInterpreterState *interp = PyMem_NEW(PyInterpreterState, 1); + if (interp != NULL) { - interp->import_modules = NULL; + interp->modules = NULL; interp->sysdict = NULL; - interp->nthreads = 0; - interp->nexitfuncs = 0; + interp->builtins = NULL; + interp->checkinterval = 10; + interp->tstate_head = NULL; + + interp->next = interp_head; + interp_head = interp; } + return interp; } void -PyInterpreterState_Delete(interp) +PyInterpreterState_Clear(interp) + PyInterpreterState *interp; +{ + PyThreadState *p; + for (p = interp->tstate_head; p != NULL; p = p->next) + PyThreadState_Clear(p); + ZAP(interp->modules); + ZAP(interp->sysdict); + ZAP(interp->builtins); +} + + +static void +zapthreads(interp) PyInterpreterState *interp; { - Py_XDECREF(interp->import_modules); - Py_XDECREF(interp->sysdict); + PyThreadState *p, *q; + p = interp->tstate_head; + while (p != NULL) { + q = p->next; + PyThreadState_Delete(p); + p = q; + } +} + +void +PyInterpreterState_Delete(interp) + PyInterpreterState *interp; +{ + PyInterpreterState **p; + zapthreads(interp); + for (p = &interp_head; ; p = &(*p)->next) { + if (*p == NULL) + Py_FatalError( + "PyInterpreterState_Delete: invalid interp"); + if (*p == interp) + break; + } + if (interp->tstate_head != NULL) + Py_FatalError("PyInterpreterState_Delete: remaining threads"); + *p = interp->next; PyMem_DEL(interp); } @@ -67,9 +117,9 @@ PyThreadState_New(interp) PyInterpreterState *interp; { PyThreadState *tstate = PyMem_NEW(PyThreadState, 1); - /* fprintf(stderr, "new tstate -> %p\n", tstate); */ + if (tstate != NULL) { - tstate->interpreter_state = interp; + tstate->interp = interp; tstate->frame = NULL; tstate->recursion_depth = 0; @@ -86,36 +136,59 @@ PyThreadState_New(interp) tstate->sys_profilefunc = NULL; tstate->sys_tracefunc = NULL; - tstate->sys_checkinterval = 0; - interp->nthreads++; + tstate->next = interp->tstate_head; + interp->tstate_head = tstate; } + return tstate; } void -PyThreadState_Delete(tstate) +PyThreadState_Clear(tstate) PyThreadState *tstate; { - /* fprintf(stderr, "delete tstate %p\n", tstate); */ - if (tstate == current_tstate) - current_tstate = NULL; - tstate->interpreter_state->nthreads--; + if (tstate->frame != NULL) + fprintf(stderr, + "PyThreadState_Clear: warning: thread still has a frame"); + + ZAP(tstate->frame); - Py_XDECREF((PyObject *) (tstate->frame)); /* XXX really? */ + ZAP(tstate->curexc_type); + ZAP(tstate->curexc_value); + ZAP(tstate->curexc_traceback); - Py_XDECREF(tstate->curexc_type); - Py_XDECREF(tstate->curexc_value); - Py_XDECREF(tstate->curexc_traceback); + ZAP(tstate->exc_type); + ZAP(tstate->exc_value); + ZAP(tstate->exc_traceback); - Py_XDECREF(tstate->exc_type); - Py_XDECREF(tstate->exc_value); - Py_XDECREF(tstate->exc_traceback); + ZAP(tstate->sys_profilefunc); + ZAP(tstate->sys_tracefunc); +} - Py_XDECREF(tstate->sys_profilefunc); - Py_XDECREF(tstate->sys_tracefunc); +void +PyThreadState_Delete(tstate) + PyThreadState *tstate; +{ + PyInterpreterState *interp; + PyThreadState **p; + if (tstate == NULL) + Py_FatalError("PyThreadState_Delete: NULL tstate"); + if (tstate == current_tstate) + Py_FatalError("PyThreadState_Delete: tstate is still current"); + interp = tstate->interp; + if (interp == NULL) + Py_FatalError("PyThreadState_Delete: NULL interp"); + for (p = &interp->tstate_head; ; p = &(*p)->next) { + if (*p == NULL) + Py_FatalError( + "PyThreadState_Delete: invalid tstate"); + if (*p == tstate) + break; + } + *p = tstate->next; PyMem_DEL(tstate); } @@ -123,7 +196,9 @@ PyThreadState_Delete(tstate) PyThreadState * PyThreadState_Get() { - /* fprintf(stderr, "get tstate -> %p\n", current_tstate); */ + if (current_tstate == NULL) + Py_FatalError("PyThreadState_Get: no current thread"); + return current_tstate; } @@ -133,7 +208,8 @@ PyThreadState_Swap(new) PyThreadState *new; { PyThreadState *old = current_tstate; - /* fprintf(stderr, "swap tstate new=%p <--> old=%p\n", new, old); */ + current_tstate = new; + return old; } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index caa0a4c..d0fe2fc 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -36,7 +36,6 @@ PERFORMANCE OF THIS SOFTWARE. #include "grammar.h" #include "node.h" #include "parsetok.h" -#undef argument /* Avoid conflict on Mac */ #include "errcode.h" #include "compile.h" #include "eval.h" @@ -52,7 +51,6 @@ PERFORMANCE OF THIS SOFTWARE. #ifdef MS_WIN32 #undef BYTE -#undef arglist #include "windows.h" #endif @@ -70,65 +68,217 @@ static PyObject *run_pyc_file Py_PROTO((FILE *fp, char *filename, PyObject *globals, PyObject *locals)); static void err_input Py_PROTO((perrdetail *)); static void initsigs Py_PROTO((void)); +static void finisigs Py_PROTO((void)); int Py_DebugFlag; /* Needed by parser.c */ int Py_VerboseFlag; /* Needed by import.c */ int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */ -/* Initialize the current interpreter; pass in the Python path. */ +static int initialized = 0; + +/* Global initializations. Can be undone by Py_Finalize(). Don't + call this twice without an intervening Py_Finalize() 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.) + +*/ void -Py_Setup() +Py_Initialize() { - PyImport_Init(); - - /* Modules '__builtin__' and 'sys' are initialized here, - they are needed by random bits of the interpreter. - All other modules are optional and are initialized - when they are first imported. */ + PyInterpreterState *interp; + PyThreadState *tstate; + PyObject *bimod, *sysmod; + char *p; + + if (initialized) + Py_FatalError("Py_Initialize: already initialized"); + initialized = 1; - PyBuiltin_Init(); /* Also initializes builtin exceptions */ - PySys_Init(); + if ((p = getenv("PYTHONDEBUG")) && *p != '\0') + Py_DebugFlag = 1; + if ((p = getenv("PYTHONVERBOSE")) && *p != '\0') + Py_VerboseFlag = 1; + + 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); + interp->modules = PyDict_New(); + if (interp->modules == NULL) + Py_FatalError("Py_Initialize: can't make modules dictionary"); + + bimod = _PyBuiltin_Init(); + if (bimod == NULL) + Py_FatalError("Py_Initialize: can't initialize __builtin__"); + interp->builtins = PyModule_GetDict(bimod); + Py_INCREF(interp->builtins); + _PyImport_FixupExtension("__builtin__", "__builtin__"); + + sysmod = _PySys_Init(); + if (sysmod == NULL) + Py_FatalError("Py_Initialize: can't initialize sys"); + interp->sysdict = PyModule_GetDict(sysmod); + Py_INCREF(interp->sysdict); + _PyImport_FixupExtension("sys", "sys"); PySys_SetPath(Py_GetPath()); + PyDict_SetItemString(interp->sysdict, "modules", + interp->modules); + + _PyImport_Init(); initsigs(); /* Signal handling stuff, including initintr() */ - initmain(); + initmain(); /* Module __main__ */ } -/* Create and interpreter and thread state and initialize them; - if we already have an interpreter and thread, do nothing. - Fatal error if the creation fails. */ +/* Undo the effect of Py_Initialize(). + + Beware: if multiple interpreter and/or thread states exist, these + are not wiped out; only the current thread and interpreter state + are deleted. But since everything else is deleted, those other + interpreter and thread states should no longer be used. + + (XXX We should do better, e.g. wipe out all interpreters and + threads.) + + Locking: as above. + +*/ void -Py_Initialize() +Py_Finalize() { + PyInterpreterState *interp; PyThreadState *tstate; + + if (!initialized) + Py_FatalError("Py_Finalize: not initialized"); + initialized = 0; + + tstate = PyThreadState_Get(); + interp = tstate->interp; + + PyImport_Cleanup(); + PyInterpreterState_Clear(interp); + PyThreadState_Swap(NULL); + PyInterpreterState_Delete(interp); + + finisigs(); + _PyImport_Fini(); + _PyBuiltin_Fini(); + PyString_Fini(); + + PyGrammar_RemoveAccelerators(&_PyParser_Grammar); +} + +/* 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() +{ PyInterpreterState *interp; - char *p; - - if (PyThreadState_Get()) - return; + PyThreadState *tstate, *save_tstate; + PyObject *bimod, *sysmod; - if ((p = getenv("PYTHONDEBUG")) && *p != '\0') - Py_DebugFlag = 1; - if ((p = getenv("PYTHONVERBOSE")) && *p != '\0') - Py_VerboseFlag = 1; + if (!initialized) + Py_FatalError("Py_NewInterpreter: call Py_Initialize first"); interp = PyInterpreterState_New(); if (interp == NULL) - Py_FatalError("PyInterpreterState_New() failed"); + return NULL; tstate = PyThreadState_New(interp); - if (tstate == NULL) - Py_FatalError("PyThreadState_New() failed"); - (void) PyThreadState_Swap(tstate); + if (tstate == NULL) { + PyInterpreterState_Delete(interp); + return NULL; + } - Py_Setup(); + save_tstate = PyThreadState_Swap(tstate); - PySys_SetPath(Py_GetPath()); - /* XXX Who should set the path -- Setup or Initialize? */ + /* XXX The following is lax in error checking */ + + interp->modules = PyDict_New(); + + bimod = _PyImport_FindExtension("__builtin__", "__builtin__"); + if (bimod != NULL) { + interp->builtins = PyModule_GetDict(bimod); + Py_INCREF(interp->builtins); + } + sysmod = _PyImport_FindExtension("sys", "sys"); + if (bimod != NULL && sysmod != NULL) { + interp->sysdict = PyModule_GetDict(sysmod); + Py_INCREF(interp->sysdict); + PySys_SetPath(Py_GetPath()); + PyDict_SetItemString(interp->sysdict, "modules", + interp->modules); + initmain(); + } + + if (!PyErr_Occurred()) + return tstate; + + /* Oops, it didn't work. Undo it all. */ + + PyErr_Print(); + 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_Finalize() doesn't have these constraints -- it zaps + everything, regardless.) + + Locking: as above. + +*/ + +void +Py_EndInterpreter(tstate) + 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"); + 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); } static char *progname = "python"; @@ -700,8 +850,13 @@ Py_Cleanup() Py_FlushLine(); + Py_Finalize(); + while (nexitfuncs > 0) (*exitfuncs[--nexitfuncs])(); + + fflush(stdout); + fflush(stderr); } #ifdef COUNT_ALLOCS @@ -718,31 +873,6 @@ Py_Exit(sts) dump_counts(); #endif -#ifdef WITH_THREAD - - /* Other threads may still be active, so skip most of the - cleanup actions usually done (these are mostly for - debugging anyway). */ - - (void) PyEval_SaveThread(); -#ifndef NO_EXIT_PROG - if (_PyThread_Started) - _exit_prog(sts); - else - exit_prog(sts); -#else /* !NO_EXIT_PROG */ - if (_PyThread_Started) - _exit(sts); - else - exit(sts); -#endif /* !NO_EXIT_PROG */ - -#else /* WITH_THREAD */ - - PyImport_Cleanup(); - - PyErr_Clear(); - #ifdef Py_REF_DEBUG fprintf(stderr, "[%ld refs]\n", _Py_RefTotal); #endif @@ -758,8 +888,6 @@ Py_Exit(sts) #else exit(sts); #endif -#endif /* WITH_THREAD */ - /*NOTREACHED*/ } #ifdef HAVE_SIGNAL_H @@ -804,6 +932,12 @@ initsigs() PyOS_InitInterrupts(); /* May imply initsignal() */ } +static void +finisigs() +{ + PyOS_FiniInterrupts(); /* May imply finisignal() */ +} + #ifdef Py_TRACE_REFS /* Ask a yes/no question */ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index da40438..68b176f 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -52,8 +52,6 @@ Data members: #include #endif -static PyObject *sysdict; - #ifdef MS_COREDLL extern void *PyWin_DLLhModule; #endif @@ -62,7 +60,9 @@ PyObject * PySys_GetObject(name) char *name; { - return PyDict_GetItemString(sysdict, name); + PyThreadState *tstate = PyThreadState_Get(); + PyObject *sd = tstate->interp->sysdict; + return PyDict_GetItemString(sd, name); } FILE * @@ -84,14 +84,16 @@ PySys_SetObject(name, v) char *name; PyObject *v; { + PyThreadState *tstate = PyThreadState_Get(); + PyObject *sd = tstate->interp->sysdict; if (v == NULL) { - if (PyDict_GetItemString(sysdict, name) == NULL) + if (PyDict_GetItemString(sd, name) == NULL) return 0; else - return PyDict_DelItemString(sysdict, name); + return PyDict_DelItemString(sd, name); } else - return PyDict_SetItemString(sysdict, name, v); + return PyDict_SetItemString(sd, name, v); } static PyObject * @@ -103,8 +105,6 @@ sys_exc_info(self, args) if (!PyArg_Parse(args, "")) return NULL; tstate = PyThreadState_Get(); - if (tstate == NULL) - Py_FatalError("sys.exc_info(): no thread state"); return Py_BuildValue( "(OOO)", tstate->exc_type != NULL ? tstate->exc_type : Py_None, @@ -161,7 +161,7 @@ sys_setcheckinterval(self, args) PyObject *args; { PyThreadState *tstate = PyThreadState_Get(); - if (!PyArg_ParseTuple(args, "i", &tstate->sys_checkinterval)) + if (!PyArg_ParseTuple(args, "i", &tstate->interp->checkinterval)) return NULL; Py_INCREF(Py_None); return Py_None; @@ -242,8 +242,6 @@ static PyMethodDef sys_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyObject *sysin, *sysout, *syserr; - static PyObject * list_builtin_module_names() { @@ -271,24 +269,28 @@ list_builtin_module_names() return list; } -void -PySys_Init() +PyObject * +_PySys_Init() { extern int fclose Py_PROTO((FILE *)); - PyObject *m = Py_InitModule("sys", sys_methods); - PyObject *v; + PyThreadState *tstate; + PyObject *m, *v, *sysdict; + PyObject *sysin, *sysout, *syserr; + + m = Py_InitModule("sys", sys_methods); sysdict = PyModule_GetDict(m); - Py_INCREF(sysdict); - /* NB keep an extra ref to the std files to avoid closing them - when the user deletes them */ - sysin = PyFile_FromFile(stdin, "", "r", fclose); - sysout = PyFile_FromFile(stdout, "", "w", fclose); - syserr = PyFile_FromFile(stderr, "", "w", fclose); + + sysin = PyFile_FromFile(stdin, "", "r", NULL); + sysout = PyFile_FromFile(stdout, "", "w", NULL); + syserr = PyFile_FromFile(stderr, "", "w", NULL); if (PyErr_Occurred()) - Py_FatalError("can't initialize sys.std{in,out,err}"); + return NULL; PyDict_SetItemString(sysdict, "stdin", sysin); PyDict_SetItemString(sysdict, "stdout", sysout); PyDict_SetItemString(sysdict, "stderr", syserr); + Py_XDECREF(sysin); + Py_XDECREF(sysout); + Py_XDECREF(syserr); PyDict_SetItemString(sysdict, "version", v = PyString_FromString(Py_GetVersion())); Py_XDECREF(v); @@ -310,7 +312,6 @@ PySys_Init() PyDict_SetItemString(sysdict, "maxint", v = PyInt_FromLong(PyInt_GetMax())); Py_XDECREF(v); - PyDict_SetItemString(sysdict, "modules", PyImport_GetModuleDict()); PyDict_SetItemString(sysdict, "builtin_module_names", v = list_builtin_module_names()); Py_XDECREF(v); @@ -323,7 +324,8 @@ PySys_Init() Py_XDECREF(v); #endif if (PyErr_Occurred()) - Py_FatalError("can't insert sys.* objects in sys dict"); + return NULL; + return m; } static PyObject * -- cgit v0.12