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.
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 @@
 	{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_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 @@
 }
 
 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 @@
 
 /* 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 @@
 		   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 @@
 			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 @@
 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 @@
 /* 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 @@
 	}
 }
 
+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 @@
 }
 
 
-/* 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;
 {
-	return _PyImport_Modules;
+	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;
+{
+	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 @@
 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 @@
 	char *name;
 	PyObject *co;
 {
+	PyObject *modules = PyImport_GetModuleDict();
 	PyObject *m, *d, *v;
 
 	m = PyImport_AddModule(name);
@@ -183,7 +258,7 @@
 		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 @@
 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 @@
 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 @@
 		    (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 @@
 PyImport_ReloadModule(m)
 	PyObject *m;
 {
+	PyObject *modules = PyImport_GetModuleDict();
 	char *name;
 	int i;
 
@@ -717,12 +796,7 @@
 	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 @@
 		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 @@
 		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 @@
 
 #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_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_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;
+{
+	PyThreadState *p, *q;
+	p = interp->tstate_head;
+	while (p != NULL) {
+		q = p->next;
+		PyThreadState_Delete(p);
+		p = q;
+	}
+}
+
+
+void
 PyInterpreterState_Delete(interp)
 	PyInterpreterState *interp;
 {
-	Py_XDECREF(interp->import_modules);
-	Py_XDECREF(interp->sysdict);
-
+	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 @@
 	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 @@
 
 		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_Clear(tstate)
+	PyThreadState *tstate;
+{
+	if (tstate->frame != NULL)
+		fprintf(stderr,
+		  "PyThreadState_Clear: warning: thread still has a frame");
+
+	ZAP(tstate->frame);
+
+	ZAP(tstate->curexc_type);
+	ZAP(tstate->curexc_value);
+	ZAP(tstate->curexc_traceback);
+
+	ZAP(tstate->exc_type);
+	ZAP(tstate->exc_value);
+	ZAP(tstate->exc_traceback);
+
+	ZAP(tstate->sys_profilefunc);
+	ZAP(tstate->sys_tracefunc);
+}
+
+
+void
 PyThreadState_Delete(tstate)
 	PyThreadState *tstate;
 {
-	/* fprintf(stderr, "delete tstate %p\n", tstate); */
+	PyInterpreterState *interp;
+	PyThreadState **p;
+	if (tstate == NULL)
+		Py_FatalError("PyThreadState_Delete: NULL tstate");
 	if (tstate == current_tstate)
-		current_tstate = NULL;
-	tstate->interpreter_state->nthreads--;
-
-	Py_XDECREF((PyObject *) (tstate->frame)); /* XXX really? */
-
-	Py_XDECREF(tstate->curexc_type);
-	Py_XDECREF(tstate->curexc_value);
-	Py_XDECREF(tstate->curexc_traceback);
-
-	Py_XDECREF(tstate->exc_type);
-	Py_XDECREF(tstate->exc_value);
-	Py_XDECREF(tstate->exc_traceback);
-
-	Py_XDECREF(tstate->sys_profilefunc);
-	Py_XDECREF(tstate->sys_tracefunc);
-
+		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 *
 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 *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 @@
 #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 @@
 
 #ifdef MS_WIN32
 #undef BYTE
-#undef arglist
 #include "windows.h"
 #endif
 
@@ -70,47 +68,38 @@
 				   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;
 
-void
-Py_Setup()
-{
-	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. */
-	
-	PyBuiltin_Init(); /* Also initializes builtin exceptions */
-	PySys_Init();
+/* 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.
 
-	PySys_SetPath(Py_GetPath());
+   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.)
 
-	initsigs(); /* Signal handling stuff, including initintr() */
-
-	initmain();
-}
-
-/* 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. */
+*/
 
 void
 Py_Initialize()
 {
-	PyThreadState *tstate;
 	PyInterpreterState *interp;
+	PyThreadState *tstate;
+	PyObject *bimod, *sysmod;
 	char *p;
-	
-	if (PyThreadState_Get())
-		return;
 
+	if (initialized)
+		Py_FatalError("Py_Initialize: already initialized");
+	initialized = 1;
+	
 	if ((p = getenv("PYTHONDEBUG")) && *p != '\0')
 		Py_DebugFlag = 1;
 	if ((p = getenv("PYTHONVERBOSE")) && *p != '\0')
@@ -118,17 +107,178 @@
 
 	interp = PyInterpreterState_New();
 	if (interp == NULL)
-		Py_FatalError("PyInterpreterState_New() failed");
+		Py_FatalError("Py_Initialize: can't make first interpreter");
 
 	tstate = PyThreadState_New(interp);
 	if (tstate == NULL)
-		Py_FatalError("PyThreadState_New() failed");
+		Py_FatalError("Py_Initialize: can't make first thread");
 	(void) PyThreadState_Swap(tstate);
 
-	Py_Setup();
+	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());
-	/* XXX Who should set the path -- Setup or Initialize? */
+	PyDict_SetItemString(interp->sysdict, "modules",
+			     interp->modules);
+
+	_PyImport_Init();
+
+	initsigs(); /* Signal handling stuff, including initintr() */
+
+	initmain(); /* Module __main__ */
+}
+
+/* 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_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;
+	PyThreadState *tstate, *save_tstate;
+	PyObject *bimod, *sysmod;
+
+	if (!initialized)
+		Py_FatalError("Py_NewInterpreter: call Py_Initialize first");
+
+	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_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_FlushLine();
 
+	Py_Finalize();
+
 	while (nexitfuncs > 0)
 		(*exitfuncs[--nexitfuncs])();
+
+	fflush(stdout);
+	fflush(stderr);
 }
 
 #ifdef COUNT_ALLOCS
@@ -718,31 +873,6 @@
 	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 @@
 #else
 	exit(sts);
 #endif
-#endif /* WITH_THREAD */
-	/*NOTREACHED*/
 }
 
 #ifdef HAVE_SIGNAL_H
@@ -804,6 +932,12 @@
 	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 @@
 #include <unistd.h>
 #endif
 
-static PyObject *sysdict;
-
 #ifdef MS_COREDLL
 extern void *PyWin_DLLhModule;
 #endif
@@ -62,7 +60,9 @@
 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 @@
 	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 @@
 	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 @@
 	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 @@
 	{NULL,		NULL}		/* sentinel */
 };
 
-static PyObject *sysin, *sysout, *syserr;
-
 static PyObject *
 list_builtin_module_names()
 {
@@ -271,24 +269,28 @@
 	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, "<stdin>", "r", fclose);
-	sysout = PyFile_FromFile(stdout, "<stdout>", "w", fclose);
-	syserr = PyFile_FromFile(stderr, "<stderr>", "w", fclose);
+
+	sysin = PyFile_FromFile(stdin, "<stdin>", "r", NULL);
+	sysout = PyFile_FromFile(stdout, "<stdout>", "w", NULL);
+	syserr = PyFile_FromFile(stderr, "<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 @@
 	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 @@
 	Py_XDECREF(v);
 #endif
 	if (PyErr_Occurred())
-		Py_FatalError("can't insert sys.* objects in sys dict");
+		return NULL;
+	return m;
 }
 
 static PyObject *