PyEval_SaveThread() and PyEval_RestoreThread() now return/take a
PyThreadState pointer instead of a (frame) PyObject pointer.  This
makes much more sense.  It is backward incompatible, but that's no
problem, because (a) the heaviest users are the Py_{BEGIN,END}_
ALLOW_THREADS macros here, which have been fixed too; (b) there are
very few direct users; (c) those who use it are there will probably
appreciate the change.

Also, added new functions PyEval_AcquireThread() and
PyEval_ReleaseThread() which allows the threads created by the thread
module as well threads created by others (!) to set/reset the current
thread, and at the same time acquire/release the interpreter lock.

Much saner.
diff --git a/Include/ceval.h b/Include/ceval.h
index 68c5977..2336ed3 100644
--- a/Include/ceval.h
+++ b/Include/ceval.h
@@ -100,13 +100,16 @@
 */
 
 extern void PyEval_InitThreads Py_PROTO((void));
-extern PyObject *PyEval_SaveThread Py_PROTO((void));
-extern void PyEval_RestoreThread Py_PROTO((PyObject *));
+extern PyThreadState *PyEval_SaveThread Py_PROTO((void));
+extern void PyEval_RestoreThread Py_PROTO((PyThreadState *));
 
 #ifdef WITH_THREAD
 
+extern void PyEval_AcquireThread Py_PROTO((PyThreadState *tstate));
+extern void PyEval_ReleaseThread Py_PROTO((PyThreadState *tstate));
+
 #define Py_BEGIN_ALLOW_THREADS { \
-			PyObject *_save; \
+			PyThreadState *_save; \
 			_save = PyEval_SaveThread();
 #define Py_BLOCK_THREADS	PyEval_RestoreThread(_save);
 #define Py_UNBLOCK_THREADS	_save = PyEval_SaveThread();
diff --git a/Python/ceval.c b/Python/ceval.c
index ab1e90f..be4ffec 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -135,35 +135,57 @@
    dynamically loaded modules needn't be compiled separately for use
    with and without threads: */
 
-PyObject *
+PyThreadState *
 PyEval_SaveThread()
 {
 #ifdef WITH_THREAD
 	if (interpreter_lock) {
 		PyThreadState *tstate = PyThreadState_Swap(NULL);
-		PyObject *res = tstate ? (PyObject *) (tstate->frame) : NULL;
+		if (tstate == NULL)
+			Py_FatalError("PyEval_SaveThread: NULL tstate");
 		release_lock(interpreter_lock);
-		return res;
+		return tstate;
 	}
 #endif
 	return NULL;
 }
 
 void
-PyEval_RestoreThread(x)
-	PyObject *x;
+PyEval_RestoreThread(tstate)
+	PyThreadState *tstate;
 {
 #ifdef WITH_THREAD
 	if (interpreter_lock) {
 		int err;
 		err = errno;
+		if (tstate == NULL)
+			Py_FatalError("PyEval_RestoreThread: NULL tstate");
 		acquire_lock(interpreter_lock, 1);
+		PyThreadState_Swap(tstate);
 		errno = err;
-		PyThreadState_Swap(x ? ((PyFrameObject *)x)->f_tstate : NULL);
 	}
 #endif
 }
 
+#ifdef WITH_THREAD
+void
+PyEval_AcquireThread(tstate)
+	PyThreadState *tstate;
+{
+	acquire_lock(interpreter_lock, 1);
+	if (PyThreadState_Swap(tstate) != NULL)
+		Py_FatalError("PyEval_AcquireThread: non-NULL old state");
+}
+
+void
+PyEval_ReleaseThread(tstate)
+	PyThreadState *tstate;
+{
+	if (PyThreadState_Swap(NULL) != tstate)
+		Py_FatalError("PyEval_ReleaseThread: wrong thread state");
+	release_lock(interpreter_lock);
+}
+#endif
 
 /* Mechanism whereby asynchronously executing callbacks (e.g. UNIX
    signal handlers or Mac I/O completion routines) can schedule calls