Massive changes for separate thread state management.

All per-thread globals are moved into a struct which is manipulated
separately.
This commit is contained in:
Guido van Rossum 1997-05-05 20:56:21 +00:00
parent 73237c54b4
commit a027efa5bf
15 changed files with 865 additions and 262 deletions

View File

@ -95,6 +95,8 @@ PERFORMANCE OF THIS SOFTWARE.
#include "import.h"
#include "bltinmodule.h"
#include "pystate.h"
#include "abstract.h"
#define PyArg_GetInt(v, a) PyArg_Parse((v), "i", (a))

View File

@ -52,6 +52,8 @@ typedef struct _frame {
PyObject *f_locals; /* local symbol table (PyDictObject) */
PyObject **f_valuestack; /* points after the last local */
PyObject *f_trace; /* Trace function */
PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
PyThreadState *f_tstate;
int f_lasti; /* Last instruction if called */
int f_lineno; /* Current line number */
int f_restricted; /* Flag set if restricted operations
@ -71,7 +73,7 @@ extern DL_IMPORT(PyTypeObject) PyFrame_Type;
#define PyFrame_Check(op) ((op)->ob_type == &PyFrame_Type)
PyFrameObject * PyFrame_New
Py_PROTO((PyFrameObject *, PyCodeObject *,
Py_PROTO((PyThreadState *, PyCodeObject *,
PyObject *, PyObject *));

134
Include/pystate.h Normal file
View File

@ -0,0 +1,134 @@
#ifndef Py_PYSTATE_H
#define Py_PYSTATE_H
#ifdef __cplusplus
extern "C" {
#endif
/***********************************************************
Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
The Netherlands.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Stichting Mathematisch
Centrum or CWI or Corporation for National Research Initiatives or
CNRI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
While CWI is the initial source for this software, a modified version
is made available by the Corporation for National Research Initiatives
(CNRI) at the Internet address ftp://ftp.python.org.
STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
******************************************************************/
/* Thread and interpreter state structures and their interfaces */
/* State shared between threads */
#define NEXITFUNCS 32
typedef struct _is {
PyObject *import_modules;
PyObject *sysdict;
int nthreads;
void (*exitfuncs[NEXITFUNCS])();
int nexitfuncs;
} PyInterpreterState;
/* State unique per thread */
struct _frame; /* Avoid including frameobject.h */
typedef struct _ts {
PyInterpreterState *interpreter_state;
struct _frame *frame;
int recursion_depth;
int ticker;
int tracing;
PyObject *sys_profilefunc;
PyObject *sys_tracefunc;
int sys_checkinterval;
PyObject *curexc_type;
PyObject *curexc_value;
PyObject *curexc_traceback;
PyObject *exc_type;
PyObject *exc_value;
PyObject *exc_traceback;
/* XXX Other state that should be here:
- signal handlers
- low-level "pending calls"
Problem with both is that they may be referenced from
interrupt handlers where there is no clear concept of a
"current thread"???
*/
} PyThreadState;
PyInterpreterState *PyInterpreterState_New(void);
void PyInterpreterState_Delete(PyInterpreterState *);
PyThreadState *PyThreadState_New(PyInterpreterState *);
void PyThreadState_Delete(PyThreadState *);
PyThreadState *PyThreadState_Get(void);
PyThreadState *PyThreadState_Swap(PyThreadState *);
/* Some background.
There are lots of issues here.
First, we can build Python without threads, with threads, or (when
Greg Stein's mods are out of beta, on some platforms) with free
threading.
Next, assuming some form of threading is used, there can be several
kinds of threads. Python code can create threads with the thread
module. C code can create threads with the interface defined in
python's "thread.h". Or C code can create threads directly with
the OS threads interface (e.g. Solaris threads, SGI threads or
pthreads, whatever is being used, as long as it's the same that
Python is configured for).
Next, let's discuss sharing of interpreter state between threads.
The exception state (sys.exc_* currently) should never be shared
between threads, because it is stack frame specific. The contents
of the sys module, in particular sys.modules and sys.path, are
generally shared between threads. But occasionally it is useful to
have separate module collections, e.g. when threads originate in C
code and are used to execute unrelated Python scripts.
(Traditionally, one would use separate processes for this, but
there are lots of reasons why threads are attractive.)
*/
#ifdef __cplusplus
}
#endif
#endif /* !Py_PYSTATE_H */

View File

@ -35,6 +35,10 @@ extern "C" {
#define up_sema PyThread_up_sema
#define exit_prog PyThread_exit_prog
#define _exit_prog PyThread__exit_prog
#define create_key PyThread_create_key
#define delete_key PyThread_delete_key
#define get_key_value PyThread_get_key_value
#define set_key_value PyThread_set_key_value
void init_thread Py_PROTO((void));
@ -62,6 +66,11 @@ void exit_prog Py_PROTO((int));
void _exit_prog Py_PROTO((int));
#endif
int create_key Py_PROTO((void));
void delete_key Py_PROTO((int));
int set_key_value Py_PROTO((int, void *));
void * get_key_value Py_PROTO((int));
#ifdef __cplusplus
}
#endif

View File

@ -35,6 +35,10 @@ extern "C" {
#define up_sema PyThread_up_sema
#define exit_prog PyThread_exit_prog
#define _exit_prog PyThread__exit_prog
#define create_key PyThread_create_key
#define delete_key PyThread_delete_key
#define get_key_value PyThread_get_key_value
#define set_key_value PyThread_set_key_value
void init_thread Py_PROTO((void));
@ -62,6 +66,11 @@ void exit_prog Py_PROTO((int));
void _exit_prog Py_PROTO((int));
#endif
int create_key Py_PROTO((void));
void delete_key Py_PROTO((int));
int set_key_value Py_PROTO((int, void *));
void * get_key_value Py_PROTO((int));
#ifdef __cplusplus
}
#endif

View File

@ -35,14 +35,13 @@ PERFORMANCE OF THIS SOFTWARE.
#include "Python.h"
#ifndef WITH_THREAD
Error! The rest of Python is not compiled with thread support.
Rerun configure, adding a --with-thread option.
#error "Error! The rest of Python is not compiled with thread support."
#error "Rerun configure, adding a --with-thread option."
#error "Then run `make clean' followed by `make'."
#endif
#include "thread.h"
extern int _PyThread_Started;
static PyObject *ThreadError;
@ -192,52 +191,90 @@ static PyTypeObject Locktype = {
/* Module functions */
struct bootstate {
PyInterpreterState *interp;
PyObject *func;
PyObject *args;
PyObject *keyw;
};
static void
t_bootstrap(args_raw)
void *args_raw;
t_bootstrap(boot_raw)
void *boot_raw;
{
PyObject *args = (PyObject *) args_raw;
PyObject *func, *arg, *res;
_PyThread_Started++;
struct bootstate *boot = (struct bootstate *) boot_raw;
PyThreadState *alttstate, *tstate;
PyObject *res;
tstate = PyThreadState_New(boot->interp);
PyEval_RestoreThread((void *)NULL);
func = PyTuple_GetItem(args, 0);
arg = PyTuple_GetItem(args, 1);
res = PyEval_CallObject(func, arg);
Py_DECREF(args); /* Matches the INCREF(args) in thread_start_new_thread */
alttstate = PyThreadState_Swap(tstate);
res = PyEval_CallObjectWithKeywords(
boot->func, boot->args, boot->keyw);
Py_DECREF(boot->func);
Py_DECREF(boot->args);
Py_XDECREF(boot->keyw);
PyMem_DEL(boot_raw);
if (res == NULL) {
if (PyErr_Occurred() == PyExc_SystemExit)
PyErr_Clear();
else {
fprintf(stderr, "Unhandled exception in thread:\n");
PyErr_Print(); /* From pythonmain.c */
PyErr_Print();
}
}
else
Py_DECREF(res);
(void) PyEval_SaveThread(); /* Should always be NULL */
(void) PyThreadState_Swap(alttstate);
(void) PyEval_SaveThread();
PyThreadState_Delete(tstate);
exit_thread();
}
static PyObject *
thread_start_new_thread(self, args)
thread_start_new_thread(self, fargs)
PyObject *self; /* Not used */
PyObject *args;
PyObject *fargs;
{
PyObject *func, *arg;
PyObject *func, *args = NULL, *keyw = NULL;
struct bootstate *boot;
if (!PyArg_Parse(args, "(OO)", &func, &arg))
if (!PyArg_ParseTuple(fargs, "OO|O", &func, &args, &keyw))
return NULL;
Py_INCREF(args);
/* Initialize the interpreter's stack save/restore mechanism */
PyEval_InitThreads();
if (!start_new_thread(t_bootstrap, (void*) args)) {
Py_DECREF(args);
PyErr_SetString(ThreadError, "can't start new thread\n");
if (!PyCallable_Check(func)) {
PyErr_SetString(PyExc_TypeError,
"first arg must be callable");
return NULL;
}
if (!PyTuple_Check(args)) {
PyErr_SetString(PyExc_TypeError,
"optional 2nd arg must be a tuple");
return NULL;
}
if (keyw != NULL && !PyDict_Check(keyw)) {
PyErr_SetString(PyExc_TypeError,
"optional 3rd arg must be a dictionary");
return NULL;
}
boot = PyMem_NEW(struct bootstate, 1);
if (boot == NULL)
return PyErr_NoMemory();
boot->interp = PyThreadState_Get()->interpreter_state;
boot->func = func;
boot->args = args;
boot->keyw = keyw;
Py_INCREF(func);
Py_INCREF(args);
Py_XINCREF(keyw);
PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
if (!start_new_thread(t_bootstrap, (void*) boot)) {
PyErr_SetString(ThreadError, "can't start new thread\n");
Py_DECREF(func);
Py_DECREF(args);
Py_XDECREF(keyw);
PyMem_DEL(boot);
return NULL;
}
/* Otherwise the DECREF(args) is done by t_bootstrap */
Py_INCREF(Py_None);
return Py_None;
}
@ -294,8 +331,8 @@ thread_get_ident(self, args)
}
static PyMethodDef thread_methods[] = {
{"start_new_thread", (PyCFunction)thread_start_new_thread},
{"start_new", (PyCFunction)thread_start_new_thread},
{"start_new_thread", (PyCFunction)thread_start_new_thread, 1},
{"start_new", (PyCFunction)thread_start_new_thread, 1},
{"allocate_lock", (PyCFunction)thread_allocate_lock},
{"allocate", (PyCFunction)thread_allocate_lock},
{"exit_thread", (PyCFunction)thread_exit_thread},

View File

@ -50,6 +50,9 @@ static struct memberlist frame_memberlist[] = {
{"f_lineno", T_INT, OFF(f_lineno), RO},
{"f_restricted",T_INT, OFF(f_restricted),RO},
{"f_trace", T_OBJECT, OFF(f_trace)},
{"f_exc_type", T_OBJECT, OFF(f_exc_type)},
{"f_exc_value", T_OBJECT, OFF(f_exc_value)},
{"f_exc_traceback", T_OBJECT, OFF(f_exc_traceback)},
{NULL} /* Sentinel */
};
@ -112,6 +115,9 @@ frame_dealloc(f)
Py_XDECREF(f->f_globals);
Py_XDECREF(f->f_locals);
Py_XDECREF(f->f_trace);
Py_XDECREF(f->f_exc_type);
Py_XDECREF(f->f_exc_value);
Py_XDECREF(f->f_exc_traceback);
f->f_back = free_list;
free_list = f;
}
@ -134,12 +140,13 @@ PyTypeObject PyFrame_Type = {
};
PyFrameObject *
PyFrame_New(back, code, globals, locals)
PyFrameObject *back;
PyFrame_New(tstate, code, globals, locals)
PyThreadState *tstate;
PyCodeObject *code;
PyObject *globals;
PyObject *locals;
{
PyFrameObject *back = tstate->frame;
static PyObject *builtin_object;
PyFrameObject *f;
PyObject *builtins;
@ -214,6 +221,10 @@ PyFrame_New(back, code, globals, locals)
}
f->f_locals = locals;
f->f_trace = NULL;
f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL;
f->f_tstate = PyThreadState_Get();
if (f->f_tstate == NULL)
Py_FatalError("can't create new frame without thread");
f->f_lasti = 0;
f->f_lineno = code->co_firstlineno;

View File

@ -41,7 +41,7 @@ OBJS= \
getplatform.o getversion.o graminit.o \
import.o importdl.o \
marshal.o modsupport.o mystrtoul.o \
pyfpe.o pythonrun.o \
pyfpe.o pystate.o pythonrun.o \
sigcheck.o structmember.o sysmodule.o \
traceback.o \
$(LIBOBJS)
@ -107,6 +107,7 @@ memmove.o: memmove.c
modsupport.o: modsupport.c
mystrtoul.o: mystrtoul.c
pyfpe.o: pyfpe.c
pystate.o: pystate.c
pythonrun.o: pythonrun.c
sigcheck.o: sigcheck.c
strerror.o: strerror.c

View File

@ -47,6 +47,12 @@ PERFORMANCE OF THIS SOFTWARE.
#include <ctype.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#else
#define INT_MAX 2147483647
#endif
/* Turn this on if your compiler chokes on the big switch: */
/* #define CASE_TOO_BIG 1 */
@ -68,9 +74,10 @@ static PyObject *eval_code2 Py_PROTO((PyCodeObject *,
#ifdef LLTRACE
static int prtrace Py_PROTO((PyObject *, char *));
#endif
static void call_exc_trace Py_PROTO((PyObject **, PyObject**, PyFrameObject *));
static int call_trace
Py_PROTO((PyObject **, PyObject **, PyFrameObject *, char *, PyObject *));
static void call_exc_trace Py_PROTO((PyObject **, PyObject**,
PyFrameObject *));
static int call_trace Py_PROTO((PyObject **, PyObject **,
PyFrameObject *, char *, PyObject *));
static PyObject *add Py_PROTO((PyObject *, PyObject *));
static PyObject *sub Py_PROTO((PyObject *, PyObject *));
static PyObject *powerop Py_PROTO((PyObject *, PyObject *));
@ -90,17 +97,22 @@ static PyObject *call_builtin Py_PROTO((PyObject *, PyObject *, PyObject *));
static PyObject *call_function Py_PROTO((PyObject *, PyObject *, PyObject *));
static PyObject *apply_subscript Py_PROTO((PyObject *, PyObject *));
static PyObject *loop_subscript Py_PROTO((PyObject *, PyObject *));
static int slice_index Py_PROTO((PyObject *, int, int *));
static int slice_index Py_PROTO((PyObject *, int *));
static PyObject *apply_slice Py_PROTO((PyObject *, PyObject *, PyObject *));
static int assign_subscript Py_PROTO((PyObject *, PyObject *, PyObject *));
static int assign_slice Py_PROTO((PyObject *, PyObject *, PyObject *, PyObject *));
static int assign_slice Py_PROTO((PyObject *, PyObject *,
PyObject *, PyObject *));
static int cmp_exception Py_PROTO((PyObject *, PyObject *));
static int cmp_member Py_PROTO((PyObject *, PyObject *));
static PyObject *cmp_outcome Py_PROTO((int, PyObject *, PyObject *));
static int import_from Py_PROTO((PyObject *, PyObject *, PyObject *));
static PyObject *build_class Py_PROTO((PyObject *, PyObject *, PyObject *));
static int exec_statement Py_PROTO((PyObject *, PyObject *, PyObject *));
static int exec_statement Py_PROTO((PyFrameObject *,
PyObject *, PyObject *, PyObject *));
static PyObject *find_from_args Py_PROTO((PyFrameObject *, int));
static void set_exc_info Py_PROTO((PyThreadState *,
PyObject *, PyObject *, PyObject *));
static void reset_exc_info Py_PROTO((PyThreadState *));
/* Dynamic execution profile */
@ -114,15 +126,13 @@ static long dxp[256];
#endif
/* Pointer to current frame, used to link new frames to */
static PyFrameObject *current_frame;
#ifdef WITH_THREAD
#include <errno.h>
#include "thread.h"
extern int _PyThread_Started; /* Flag for Py_Exit */
static type_lock interpreter_lock = 0;
static long main_thread = 0;
@ -131,6 +141,7 @@ PyEval_InitThreads()
{
if (interpreter_lock)
return;
_PyThread_Started = 1;
interpreter_lock = allocate_lock();
acquire_lock(interpreter_lock, 1);
main_thread = get_thread_ident();
@ -147,9 +158,8 @@ PyEval_SaveThread()
{
#ifdef WITH_THREAD
if (interpreter_lock) {
PyObject *res;
res = (PyObject *)current_frame;
current_frame = NULL;
PyThreadState *tstate = PyThreadState_Swap(NULL);
PyObject *res = tstate ? (PyObject *) (tstate->frame) : NULL;
release_lock(interpreter_lock);
return res;
}
@ -167,7 +177,7 @@ PyEval_RestoreThread(x)
err = errno;
acquire_lock(interpreter_lock, 1);
errno = err;
current_frame = (PyFrameObject *)x;
PyThreadState_Swap(x ? ((PyFrameObject *)x)->f_tstate : NULL);
}
#endif
}
@ -200,9 +210,10 @@ PyEval_RestoreThread(x)
The current code is safe against (2), but not against (1).
The safety against (2) is derived from the fact that only one
thread (the main thread) ever takes things out of the queue.
*/
static int ticker = 0; /* main loop counter to do periodic things */
XXX Darn! With the advent of thread state, we should have an array
of pending calls per thread in the thread state! Later...
*/
#define NPENDINGCALLS 32
static struct {
@ -211,6 +222,7 @@ static struct {
} pendingcalls[NPENDINGCALLS];
static volatile int pendingfirst = 0;
static volatile int pendinglast = 0;
static volatile int things_to_do = 0;
int
Py_AddPendingCall(func, arg)
@ -232,7 +244,7 @@ Py_AddPendingCall(func, arg)
pendingcalls[i].func = func;
pendingcalls[i].arg = arg;
pendinglast = j;
ticker = 0; /* Signal main loop */
things_to_do = 1; /* Signal main loop */
busy = 0;
/* XXX End critical section */
return 0;
@ -243,16 +255,13 @@ Py_MakePendingCalls()
{
static int busy = 0;
#ifdef WITH_THREAD
if (main_thread && get_thread_ident() != main_thread) {
ticker = 0; /* We're not done yet */
if (main_thread && get_thread_ident() != main_thread)
return 0;
}
#endif
if (busy) {
ticker = 0; /* We're not done yet */
if (busy)
return 0;
}
busy = 1;
things_to_do = 0;
for (;;) {
int i;
int (*func) Py_PROTO((ANY *));
@ -265,7 +274,7 @@ Py_MakePendingCalls()
pendingfirst = (i + 1) % NPENDINGCALLS;
if (func(arg) < 0) {
busy = 0;
ticker = 0; /* We're not done yet */
things_to_do = 1; /* We're not done yet */
return -1;
}
}
@ -310,8 +319,6 @@ PyEval_EvalCode(co, globals, locals)
#define MAX_RECURSION_DEPTH 10000
#endif
static int recursion_depth = 0;
static PyObject *
eval_code2(co, globals, locals,
args, argcount, kws, kwcount, defs, defcount, owner)
@ -343,6 +350,7 @@ eval_code2(co, globals, locals,
register PyFrameObject *f; /* Current frame */
register PyObject **fastlocals = NULL;
PyObject *retval = NULL; /* Return value */
PyThreadState *tstate = PyThreadState_Get();
#ifdef LLTRACE
int lltrace;
#endif
@ -385,8 +393,13 @@ eval_code2(co, globals, locals,
#define SETLOCAL(i, value) do { Py_XDECREF(GETLOCAL(i)); \
GETLOCAL(i) = value; } while (0)
/* Start of code */
if (tstate == NULL)
Py_FatalError("eval_code2 called without a current thread");
#ifdef USE_STACKCHECK
if (recursion_depth%10 == 0 && PyOS_CheckStack()) {
if (tstate->recursion_depth%10 == 0 && PyOS_CheckStack()) {
PyErr_SetString(PyExc_MemoryError, "Stack overflow");
return NULL;
}
@ -402,14 +415,14 @@ eval_code2(co, globals, locals,
#endif
f = PyFrame_New(
current_frame, /*back*/
tstate, /*back*/
co, /*code*/
globals, /*globals*/
locals); /*locals*/
if (f == NULL)
return NULL;
current_frame = f;
tstate->frame = f;
fastlocals = f->f_localsplus;
if (co->co_argcount > 0 ||
@ -428,7 +441,8 @@ eval_code2(co, globals, locals,
}
if (argcount > co->co_argcount) {
if (!(co->co_flags & CO_VARARGS)) {
PyErr_SetString(PyExc_TypeError, "too many arguments");
PyErr_SetString(PyExc_TypeError,
"too many arguments");
goto fail;
}
n = co->co_argcount;
@ -455,15 +469,16 @@ eval_code2(co, globals, locals,
int j;
/* XXX slow -- speed up using dictionary? */
for (j = 0; j < co->co_argcount; j++) {
PyObject *nm = PyTuple_GET_ITEM(co->co_varnames, j);
PyObject *nm = PyTuple_GET_ITEM(
co->co_varnames, j);
if (PyObject_Compare(keyword, nm) == 0)
break;
}
if (j >= co->co_argcount) {
if (kwdict == NULL) {
PyErr_Format(PyExc_TypeError,
"unexpected keyword argument: %.400s",
PyString_AsString(keyword));
"unexpected keyword argument: %.400s",
PyString_AsString(keyword));
goto fail;
}
PyDict_SetItem(kwdict, keyword, value);
@ -502,14 +517,15 @@ eval_code2(co, globals, locals,
}
else {
if (argcount > 0 || kwcount > 0) {
PyErr_SetString(PyExc_TypeError, "no arguments expected");
PyErr_SetString(PyExc_TypeError,
"no arguments expected");
goto fail;
}
}
if (_PySys_TraceFunc != NULL) {
/* sys_trace, if defined, is a function that will
be called on *every* entry to a code block.
if (tstate->sys_tracefunc != NULL) {
/* tstate->sys_tracefunc, if defined, is a function that
will be called on *every* entry to a code block.
Its return value, if not None, is a function that
will be called at the start of each executed line
of code. (Actually, the function must return
@ -520,26 +536,29 @@ eval_code2(co, globals, locals,
depends on the situation. The global trace function
(sys.trace) is also called whenever an exception
is detected. */
if (call_trace(&_PySys_TraceFunc, &f->f_trace, f, "call",
if (call_trace(&tstate->sys_tracefunc,
&f->f_trace, f, "call",
Py_None/*XXX how to compute arguments now?*/)) {
/* Trace function raised an error */
goto fail;
}
}
if (_PySys_ProfileFunc != NULL) {
/* Similar for sys_profile, except it needn't return
if (tstate->sys_profilefunc != NULL) {
/* Similar for sys_profilefunc, except it needn't return
itself and isn't called for "line" events */
if (call_trace(&_PySys_ProfileFunc, (PyObject**)0, f, "call",
if (call_trace(&tstate->sys_profilefunc,
(PyObject**)0, f, "call",
Py_None/*XXX*/)) {
goto fail;
}
}
if (++recursion_depth > MAX_RECURSION_DEPTH) {
--recursion_depth;
PyErr_SetString(PyExc_RuntimeError, "Maximum recursion depth exceeded");
current_frame = f->f_back;
if (++tstate->recursion_depth > MAX_RECURSION_DEPTH) {
--tstate->recursion_depth;
PyErr_SetString(PyExc_RuntimeError,
"Maximum recursion depth exceeded");
tstate->frame = f->f_back;
Py_DECREF(f);
return NULL;
}
@ -552,30 +571,27 @@ eval_code2(co, globals, locals,
x = Py_None; /* Not a reference, just anything non-NULL */
for (;;) {
/* Do periodic things.
Doing this every time through the loop would add
too much overhead (a function call per instruction).
So we do it only every Nth instruction.
/* Do periodic things. Doing this every time through
the loop would add too much overhead, so we do it
only every Nth instruction. We also do it if
``things_to_do'' is set, i.e. when an asynchronous
event needs attention (e.g. a signal handler or
async I/O handler); see Py_AddPendingCall() and
Py_MakePendingCalls() above. */
The ticker is reset to zero if there are pending
calls (see Py_AddPendingCall() and
Py_MakePendingCalls() above). */
if (--ticker < 0) {
ticker = _PySys_CheckInterval;
if (pendingfirst != pendinglast) {
if (things_to_do || --tstate->ticker < 0) {
tstate->ticker = tstate->sys_checkinterval;
if (things_to_do) {
if (Py_MakePendingCalls() < 0) {
why = WHY_EXCEPTION;
goto on_error;
}
}
#ifdef macintosh
#undef HAVE_SIGNAL_H
#endif
#ifndef HAVE_SIGNAL_H /* Is this the right #define? */
/* If we have true signals, the signal handler will call
Py_AddPendingCall() so we don't have to call sigcheck().
On the Mac and DOS, alas, we have to call it. */
#if !defined(HAVE_SIGNAL_H) && !defined(macintosh)
/* If we have true signals, the signal handler
will call Py_AddPendingCall() so we don't
have to call sigcheck(). On the Mac and
DOS, alas, we have to call it. */
if (PyErr_CheckSignals()) {
why = WHY_EXCEPTION;
goto on_error;
@ -586,13 +602,14 @@ eval_code2(co, globals, locals,
if (interpreter_lock) {
/* Give another thread a chance */
current_frame = NULL;
PyThreadState *tstate =
PyThreadState_Swap(NULL);
release_lock(interpreter_lock);
/* Other threads may run now */
acquire_lock(interpreter_lock, 1);
current_frame = f;
PyThreadState_Swap(tstate);
}
#endif
}
@ -919,7 +936,8 @@ eval_code2(co, globals, locals,
/* Print value except if procedure result */
/* Before printing, also assign to '_' */
if (v != Py_None &&
(err = PyDict_SetItemString(f->f_builtins, "_", v)) == 0 &&
(err = PyDict_SetItemString(
f->f_builtins, "_", v)) == 0 &&
!Py_SuppressPrintingFlag) {
Py_FlushLine();
x = PySys_GetObject("stdout");
@ -952,7 +970,8 @@ eval_code2(co, globals, locals,
case PRINT_NEWLINE:
x = PySys_GetObject("stdout");
if (x == NULL)
PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout");
PyErr_SetString(PyExc_RuntimeError,
"lost sys.stdout");
else {
PyFile_WriteString("\n", x);
PyFile_SoftSpace(x, 0);
@ -986,7 +1005,8 @@ eval_code2(co, globals, locals,
case LOAD_LOCALS:
if ((x = f->f_locals) == NULL) {
PyErr_SetString(PyExc_SystemError, "no locals");
PyErr_SetString(PyExc_SystemError,
"no locals");
break;
}
Py_INCREF(x);
@ -1002,7 +1022,7 @@ eval_code2(co, globals, locals,
w = POP();
v = POP();
u = POP();
err = exec_statement(u, v, w);
err = exec_statement(f, u, v, w);
Py_DECREF(u);
Py_DECREF(v);
Py_DECREF(w);
@ -1055,7 +1075,8 @@ eval_code2(co, globals, locals,
w = GETNAMEV(oparg);
v = POP();
if ((x = f->f_locals) == NULL) {
PyErr_SetString(PyExc_SystemError, "no locals");
PyErr_SetString(PyExc_SystemError,
"no locals");
break;
}
err = PyDict_SetItem(x, w, v);
@ -1065,7 +1086,8 @@ eval_code2(co, globals, locals,
case DELETE_NAME:
w = GETNAMEV(oparg);
if ((x = f->f_locals) == NULL) {
PyErr_SetString(PyExc_SystemError, "no locals");
PyErr_SetString(PyExc_SystemError,
"no locals");
break;
}
if ((err = PyDict_DelItem(x, w)) != 0)
@ -1079,7 +1101,8 @@ eval_code2(co, globals, locals,
case UNPACK_TUPLE:
v = POP();
if (!PyTuple_Check(v)) {
PyErr_SetString(PyExc_TypeError, "unpack non-tuple");
PyErr_SetString(PyExc_TypeError,
"unpack non-tuple");
why = WHY_EXCEPTION;
}
else if (PyTuple_Size(v) != oparg) {
@ -1100,7 +1123,8 @@ eval_code2(co, globals, locals,
case UNPACK_LIST:
v = POP();
if (!PyList_Check(v)) {
PyErr_SetString(PyExc_TypeError, "unpack non-list");
PyErr_SetString(PyExc_TypeError,
"unpack non-list");
why = WHY_EXCEPTION;
}
else if (PyList_Size(v) != oparg) {
@ -1130,7 +1154,8 @@ eval_code2(co, globals, locals,
case DELETE_ATTR:
w = GETNAMEV(oparg);
v = POP();
err = PyObject_SetAttr(v, w, (PyObject *)NULL); /* del v.w */
err = PyObject_SetAttr(v, w, (PyObject *)NULL);
/* del v.w */
Py_DECREF(v);
break;
@ -1156,7 +1181,8 @@ eval_code2(co, globals, locals,
case LOAD_NAME:
w = GETNAMEV(oparg);
if ((x = f->f_locals) == NULL) {
PyErr_SetString(PyExc_SystemError, "no locals");
PyErr_SetString(PyExc_SystemError,
"no locals");
break;
}
x = PyDict_GetItem(x, w);
@ -1167,7 +1193,8 @@ eval_code2(co, globals, locals,
PyErr_Clear();
x = PyDict_GetItem(f->f_builtins, w);
if (x == NULL) {
PyErr_SetObject(PyExc_NameError, w);
PyErr_SetObject(
PyExc_NameError, w);
break;
}
}
@ -1286,7 +1313,8 @@ eval_code2(co, globals, locals,
w = Py_BuildValue("(OOOO)",
w,
f->f_globals,
f->f_locals == NULL ? Py_None : f->f_locals,
f->f_locals == NULL ?
Py_None : f->f_locals,
u);
Py_DECREF(u);
if (w == NULL) {
@ -1304,7 +1332,8 @@ eval_code2(co, globals, locals,
v = TOP();
PyFrame_FastToLocals(f);
if ((x = f->f_locals) == NULL) {
PyErr_SetString(PyExc_SystemError, "no locals");
PyErr_SetString(PyExc_SystemError,
"no locals");
break;
}
err = import_from(x, v, w);
@ -1432,7 +1461,8 @@ eval_code2(co, globals, locals,
class))
/* Handy-dandy */ ;
else {
PyErr_SetString(PyExc_TypeError,
PyErr_SetString(
PyExc_TypeError,
"unbound method must be called with class instance 1st argument");
x = NULL;
break;
@ -1443,13 +1473,16 @@ eval_code2(co, globals, locals,
Py_INCREF(func);
if (PyFunction_Check(func)) {
PyObject *co = PyFunction_GetCode(func);
PyObject *globals = PyFunction_GetGlobals(func);
PyObject *argdefs = PyFunction_GetDefaults(func);
PyObject *globals =
PyFunction_GetGlobals(func);
PyObject *argdefs =
PyFunction_GetDefaults(func);
PyObject **d;
int nd;
if (argdefs != NULL) {
d = &PyTuple_GET_ITEM(argdefs, 0);
nd = ((PyTupleObject *)argdefs)->ob_size;
nd = ((PyTupleObject *)argdefs) ->
ob_size;
}
else {
d = NULL;
@ -1589,7 +1622,8 @@ eval_code2(co, globals, locals,
if (why == WHY_EXCEPTION || why == WHY_RERAISE) {
if (!PyErr_Occurred()) {
fprintf(stderr, "XXX ghost error\n");
PyErr_SetString(PyExc_SystemError, "ghost error");
PyErr_SetString(PyExc_SystemError,
"ghost error");
why = WHY_EXCEPTION;
}
}
@ -1613,9 +1647,10 @@ eval_code2(co, globals, locals,
if (f->f_trace)
call_exc_trace(&f->f_trace, &f->f_trace, f);
if (_PySys_ProfileFunc)
call_exc_trace(&_PySys_ProfileFunc, (PyObject**)0, f);
}
if (tstate->sys_profilefunc)
call_exc_trace(&tstate->sys_profilefunc,
(PyObject**)0, f);
}
/* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */
@ -1651,9 +1686,8 @@ eval_code2(co, globals, locals,
Python main loop. Don't do
this for 'finally'. */
if (b->b_type == SETUP_EXCEPT) {
PySys_SetObject("exc_traceback", tb);
PySys_SetObject("exc_value", val);
PySys_SetObject("exc_type", exc);
set_exc_info(tstate,
exc, val, tb);
}
PUSH(tb);
PUSH(val);
@ -1699,8 +1733,8 @@ eval_code2(co, globals, locals,
}
}
if (_PySys_ProfileFunc && why == WHY_RETURN) {
if (call_trace(&_PySys_ProfileFunc, (PyObject**)0,
if (tstate->sys_profilefunc && why == WHY_RETURN) {
if (call_trace(&tstate->sys_profilefunc, (PyObject**)0,
f, "return", retval)) {
Py_XDECREF(retval);
retval = NULL;
@ -1708,18 +1742,89 @@ eval_code2(co, globals, locals,
}
}
--recursion_depth;
reset_exc_info(tstate);
--tstate->recursion_depth;
fail: /* Jump here from prelude on failure */
/* Restore previous frame and release the current one */
current_frame = f->f_back;
tstate->frame = f->f_back;
Py_DECREF(f);
return retval;
}
static void
set_exc_info(tstate, type, value, tb)
PyThreadState *tstate;
PyObject *type;
PyObject *value;
PyObject *tb;
{
PyFrameObject *frame;
frame = tstate->frame;
if (frame->f_exc_type == NULL) {
/* This frame didn't catch an exception before */
/* Save previous exception of this thread in this frame */
Py_XDECREF(frame->f_exc_type);
Py_XDECREF(frame->f_exc_value);
Py_XDECREF(frame->f_exc_traceback);
if (tstate->exc_type == NULL) {
Py_INCREF(Py_None);
tstate->exc_type = Py_None;
}
Py_XINCREF(tstate->exc_type);
Py_XINCREF(tstate->exc_value);
Py_XINCREF(tstate->exc_traceback);
frame->f_exc_type = tstate->exc_type;
frame->f_exc_value = tstate->exc_value;
frame->f_exc_traceback = tstate->exc_traceback;
}
/* Set new exception for this thread */
Py_XINCREF(type);
Py_XINCREF(value);
Py_XINCREF(tb);
tstate->exc_type = type;
tstate->exc_value = value;
tstate->exc_traceback = tb;
/* For b/w compatibility */
PySys_SetObject("exc_type", type);
PySys_SetObject("exc_value", value);
PySys_SetObject("exc_traceback", tb);
}
static void
reset_exc_info(tstate)
PyThreadState *tstate;
{
PyFrameObject *frame;
frame = tstate->frame;
if (frame->f_exc_type != NULL) {
/* This frame caught an exception */
Py_XDECREF(tstate->exc_type);
Py_XDECREF(tstate->exc_value);
Py_XDECREF(tstate->exc_traceback);
Py_XINCREF(frame->f_exc_type);
Py_XINCREF(frame->f_exc_value);
Py_XINCREF(frame->f_exc_traceback);
tstate->exc_type = frame->f_exc_type;
tstate->exc_value = frame->f_exc_value;
tstate->exc_traceback = frame->f_exc_traceback;
/* For b/w compatibility */
PySys_SetObject("exc_type", frame->f_exc_type);
PySys_SetObject("exc_value", frame->f_exc_value);
PySys_SetObject("exc_traceback", frame->f_exc_traceback);
}
Py_XDECREF(frame->f_exc_type);
Py_XDECREF(frame->f_exc_value);
Py_XDECREF(frame->f_exc_traceback);
frame->f_exc_type = NULL;
frame->f_exc_value = NULL;
frame->f_exc_traceback = NULL;
}
/* Logic for the raise statement (too complicated for inlining).
This *consumes* a reference count to each of its arguments. */
static enum why_code
@ -1895,11 +2000,11 @@ call_trace(p_trace, p_newtrace, f, msg, arg)
char *msg;
PyObject *arg;
{
PyThreadState *tstate = f->f_tstate;
PyObject *args, *what;
PyObject *res = NULL;
static int tracing = 0;
if (tracing) {
if (tstate->tracing) {
/* Don't do recursive traces */
if (p_newtrace) {
Py_XDECREF(*p_newtrace);
@ -1921,11 +2026,11 @@ call_trace(p_trace, p_newtrace, f, msg, arg)
arg = Py_None;
Py_INCREF(arg);
PyTuple_SET_ITEM(args, 2, arg);
tracing++;
tstate->tracing++;
PyFrame_FastToLocals(f);
res = PyEval_CallObject(*p_trace, args); /* May clear *p_trace! */
PyFrame_LocalsToFast(f, 1);
tracing--;
tstate->tracing--;
Py_Cleanup:
Py_XDECREF(args);
if (res == NULL) {
@ -1957,6 +2062,7 @@ call_trace(p_trace, p_newtrace, f, msg, arg)
PyObject *
PyEval_GetBuiltins()
{
PyFrameObject *current_frame = PyThreadState_Get()->frame;
if (current_frame == NULL)
return PyBuiltin_GetModule();
else
@ -1966,6 +2072,7 @@ PyEval_GetBuiltins()
PyObject *
PyEval_GetLocals()
{
PyFrameObject *current_frame = PyThreadState_Get()->frame;
if (current_frame == NULL)
return NULL;
PyFrame_FastToLocals(current_frame);
@ -1975,6 +2082,7 @@ PyEval_GetLocals()
PyObject *
PyEval_GetGlobals()
{
PyFrameObject *current_frame = PyThreadState_Get()->frame;
if (current_frame == NULL)
return NULL;
else
@ -1984,12 +2092,14 @@ PyEval_GetGlobals()
PyObject *
PyEval_GetFrame()
{
PyFrameObject *current_frame = PyThreadState_Get()->frame;
return (PyObject *)current_frame;
}
int
PyEval_GetRestricted()
{
PyFrameObject *current_frame = PyThreadState_Get()->frame;
return current_frame == NULL ? 0 : current_frame->f_restricted;
}
@ -2002,6 +2112,9 @@ Py_FlushLine()
}
/* XXX Many of the following operator implementations could be
replaced by calls into the 'abstract' module. */
#define BINOP(opname, ropname, thisfunc) \
if (!PyInstance_Check(v) && !PyInstance_Check(w)) \
; \
@ -2245,7 +2358,8 @@ powerop(v, w)
BINOP("__pow__", "__rpow__", powerop);
if (v->ob_type->tp_as_number == NULL ||
w->ob_type->tp_as_number == NULL) {
PyErr_SetString(PyExc_TypeError, "pow() requires numeric arguments");
PyErr_SetString(PyExc_TypeError,
"pow() requires numeric arguments");
return NULL;
}
if (PyNumber_Coerce(&v, &w) != 0)
@ -2328,14 +2442,16 @@ PyEval_CallObjectWithKeywords(func, arg, kw)
if (arg == NULL)
arg = PyTuple_New(0);
else if (!PyTuple_Check(arg)) {
PyErr_SetString(PyExc_TypeError, "argument list must be a tuple");
PyErr_SetString(PyExc_TypeError,
"argument list must be a tuple");
return NULL;
}
else
Py_INCREF(arg);
if (kw != NULL && !PyDict_Check(kw)) {
PyErr_SetString(PyExc_TypeError, "keyword list must be a dictionary");
PyErr_SetString(PyExc_TypeError,
"keyword list must be a dictionary");
return NULL;
}
@ -2460,7 +2576,8 @@ call_function(func, arg, kw)
}
else {
if (!PyFunction_Check(func)) {
PyErr_SetString(PyExc_TypeError, "call of non-function");
PyErr_SetString(PyExc_TypeError,
"call of non-function");
return NULL;
}
Py_INCREF(arg);
@ -2529,7 +2646,8 @@ apply_subscript(v, w)
int i;
if (!PyInt_Check(w)) {
if (PySlice_Check(w)) {
PyErr_SetString(PyExc_ValueError, SLICE_ERROR_MSG);
PyErr_SetString(PyExc_ValueError,
SLICE_ERROR_MSG);
} else {
PyErr_SetString(PyExc_TypeError,
"sequence subscript not int");
@ -2567,19 +2685,24 @@ loop_subscript(v, w)
}
static int
slice_index(v, isize, pi)
slice_index(v, pi)
PyObject *v;
int isize;
int *pi;
{
if (v != NULL) {
long x;
if (!PyInt_Check(v)) {
PyErr_SetString(PyExc_TypeError, "slice index must be int");
PyErr_SetString(PyExc_TypeError,
"slice index must be int");
return -1;
}
*pi = PyInt_AsLong(v);
if (*pi < 0)
*pi += isize;
x = PyInt_AsLong(v);
/* Truncate -- very long indices are truncated anyway */
if (x > INT_MAX)
x = INT_MAX;
else if (x < -INT_MAX)
x = 0;
*pi = x;
}
return 0;
}
@ -2588,21 +2711,12 @@ static PyObject *
apply_slice(u, v, w) /* return u[v:w] */
PyObject *u, *v, *w;
{
PyTypeObject *tp = u->ob_type;
int ilow, ihigh, isize;
if (tp->tp_as_sequence == NULL) {
PyErr_SetString(PyExc_TypeError, "only sequences can be sliced");
int ilow = 0, ihigh = INT_MAX;
if (slice_index(v, &ilow) != 0)
return NULL;
}
ilow = 0;
isize = ihigh = (*tp->tp_as_sequence->sq_length)(u);
if (isize < 0)
if (slice_index(w, &ihigh) != 0)
return NULL;
if (slice_index(v, isize, &ilow) != 0)
return NULL;
if (slice_index(w, isize, &ihigh) != 0)
return NULL;
return (*tp->tp_as_sequence->sq_slice)(u, ilow, ihigh);
return PySequence_GetSlice(u, ilow, ihigh);
}
static int
@ -2649,25 +2763,15 @@ static int
assign_slice(u, v, w, x) /* u[v:w] = x */
PyObject *u, *v, *w, *x;
{
PySequenceMethods *sq = u->ob_type->tp_as_sequence;
int ilow, ihigh, isize;
if (sq == NULL) {
PyErr_SetString(PyExc_TypeError, "assign to slice of non-sequence");
int ilow = 0, ihigh = INT_MAX;
if (slice_index(v, &ilow) != 0)
return -1;
}
if (sq == NULL || sq->sq_ass_slice == NULL) {
PyErr_SetString(PyExc_TypeError, "unassignable slice");
if (slice_index(w, &ihigh) != 0)
return -1;
}
ilow = 0;
isize = ihigh = (*sq->sq_length)(u);
if (isize < 0)
return -1;
if (slice_index(v, isize, &ilow) != 0)
return -1;
if (slice_index(w, isize, &ihigh) != 0)
return -1;
return (*sq->sq_ass_slice)(u, ilow, ihigh, x);
if (x == NULL)
return PySequence_DelSlice(u, ilow, ihigh);
else
return PySequence_SetSlice(u, ilow, ihigh, x);
}
static int
@ -2788,7 +2892,8 @@ import_from(locals, v, name)
{
PyObject *w, *x;
if (!PyModule_Check(v)) {
PyErr_SetString(PyExc_TypeError, "import-from requires module object");
PyErr_SetString(PyExc_TypeError,
"import-from requires module object");
return -1;
}
w = PyModule_GetDict(v);
@ -2830,15 +2935,18 @@ build_class(methods, bases, name)
{
int i;
if (!PyTuple_Check(bases)) {
PyErr_SetString(PyExc_SystemError, "build_class with non-tuple bases");
PyErr_SetString(PyExc_SystemError,
"build_class with non-tuple bases");
return NULL;
}
if (!PyDict_Check(methods)) {
PyErr_SetString(PyExc_SystemError, "build_class with non-dictionary");
PyErr_SetString(PyExc_SystemError,
"build_class with non-dictionary");
return NULL;
}
if (!PyString_Check(name)) {
PyErr_SetString(PyExc_SystemError, "build_class witn non-string name");
PyErr_SetString(PyExc_SystemError,
"build_class witn non-string name");
return NULL;
}
for (i = PyTuple_Size(bases); --i >= 0; ) {
@ -2852,9 +2960,10 @@ build_class(methods, bases, name)
if (base->ob_type->ob_type->tp_call) {
PyObject *args;
PyObject *class;
args = Py_BuildValue("(OOO)", name, bases, methods);
class = PyEval_CallObject((PyObject *)base->ob_type,
args);
args = Py_BuildValue("(OOO)",
name, bases, methods);
class = PyEval_CallObject(
(PyObject *)base->ob_type, args);
Py_DECREF(args);
return class;
}
@ -2867,7 +2976,8 @@ build_class(methods, bases, name)
}
static int
exec_statement(prog, globals, locals)
exec_statement(f, prog, globals, locals)
PyFrameObject *f;
PyObject *prog;
PyObject *globals;
PyObject *locals;
@ -2907,9 +3017,10 @@ exec_statement(prog, globals, locals)
return -1;
}
if (PyDict_GetItemString(globals, "__builtins__") == NULL)
PyDict_SetItemString(globals, "__builtins__", current_frame->f_builtins);
PyDict_SetItemString(globals, "__builtins__", f->f_builtins);
if (PyCode_Check(prog)) {
if (PyEval_EvalCode((PyCodeObject *) prog, globals, locals) == NULL)
if (PyEval_EvalCode((PyCodeObject *) prog,
globals, locals) == NULL)
return -1;
return 0;
}
@ -2922,7 +3033,8 @@ exec_statement(prog, globals, locals)
}
s = PyString_AsString(prog);
if (strlen(s) != PyString_Size(prog)) {
PyErr_SetString(PyExc_ValueError, "embedded '\\0' in exec string");
PyErr_SetString(PyExc_ValueError,
"embedded '\\0' in exec string");
return -1;
}
v = PyRun_String(s, file_input, globals, locals);
@ -2930,7 +3042,7 @@ exec_statement(prog, globals, locals)
return -1;
Py_DECREF(v);
if (plain)
PyFrame_LocalsToFast(current_frame, 0);
PyFrame_LocalsToFast(f, 0);
return 0;
}

View File

@ -55,23 +55,34 @@ extern char *strerror Py_PROTO((int));
#endif
#endif
/* Last exception stored */
static PyObject *last_exception;
static PyObject *last_exc_val;
void
PyErr_Restore(exception, value, traceback)
PyObject *exception;
PyErr_Restore(type, value, traceback)
PyObject *type;
PyObject *value;
PyObject *traceback;
{
PyErr_Clear();
PyThreadState *tstate = PyThreadState_Get();
PyObject *oldtype, *oldvalue, *oldtraceback;
last_exception = exception;
last_exc_val = value;
(void) PyTraceBack_Store(traceback);
Py_XDECREF(traceback);
if (traceback != NULL && !PyTraceBack_Check(traceback)) {
/* XXX Should never happen -- fatal error instead? */
Py_DECREF(traceback);
traceback = NULL;
}
/* Save these in locals to safeguard against recursive
invocation through Py_XDECREF */
oldtype = tstate->curexc_type;
oldvalue = tstate->curexc_value;
oldtraceback = tstate->curexc_traceback;
tstate->curexc_type = type;
tstate->curexc_value = value;
tstate->curexc_traceback = traceback;
Py_XDECREF(oldtype);
Py_XDECREF(oldvalue);
Py_XDECREF(oldtraceback);
}
void
@ -105,33 +116,32 @@ PyErr_SetString(exception, string)
PyObject *
PyErr_Occurred()
{
return last_exception;
PyThreadState *tstate = PyThreadState_Get();
return tstate->curexc_type;
}
void
PyErr_Fetch(p_exc, p_val, p_tb)
PyObject **p_exc;
PyObject **p_val;
PyObject **p_tb;
PyErr_Fetch(p_type, p_value, p_traceback)
PyObject **p_type;
PyObject **p_value;
PyObject **p_traceback;
{
*p_exc = last_exception;
last_exception = NULL;
*p_val = last_exc_val;
last_exc_val = NULL;
*p_tb = PyTraceBack_Fetch();
PyThreadState *tstate = PyThreadState_Get();
*p_type = tstate->curexc_type;
*p_value = tstate->curexc_value;
*p_traceback = tstate->curexc_traceback;
tstate->curexc_type = NULL;
tstate->curexc_value = NULL;
tstate->curexc_traceback = NULL;
}
void
PyErr_Clear()
{
PyObject *tb;
Py_XDECREF(last_exception);
last_exception = NULL;
Py_XDECREF(last_exc_val);
last_exc_val = NULL;
/* Also clear interpreter stack trace */
tb = PyTraceBack_Fetch();
Py_XDECREF(tb);
PyErr_Restore(NULL, NULL, NULL);
}
/* Convenience functions to set a type error exception and return 0 */
@ -139,7 +149,8 @@ PyErr_Clear()
int
PyErr_BadArgument()
{
PyErr_SetString(PyExc_TypeError, "illegal argument type for built-in operation");
PyErr_SetString(PyExc_TypeError,
"illegal argument type for built-in operation");
return 0;
}
@ -171,7 +182,8 @@ PyErr_SetFromErrno(exc)
void
PyErr_BadInternalCall()
{
PyErr_SetString(PyExc_SystemError, "bad argument to internal function");
PyErr_SetString(PyExc_SystemError,
"bad argument to internal function");
}

163
Python/pystate.c Normal file
View File

@ -0,0 +1,163 @@
/***********************************************************
Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
The Netherlands.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Stichting Mathematisch
Centrum or CWI or Corporation for National Research Initiatives or
CNRI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
While CWI is the initial source for this software, a modified version
is made available by the Corporation for National Research Initiatives
(CNRI) at the Internet address ftp://ftp.python.org.
STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
******************************************************************/
/* Thread and interpreter state structures and their interfaces */
#include "Python.h"
static PyThreadState *current_tstate = NULL;
PyInterpreterState *
PyInterpreterState_New()
{
PyInterpreterState *interp = PyMem_NEW(PyInterpreterState, 1);
if (interp != NULL) {
interp->import_modules = NULL;
interp->sysdict = NULL;
interp->nthreads = 0;
interp->nexitfuncs = 0;
}
return interp;
}
void
PyInterpreterState_Delete(PyInterpreterState *interp)
{
Py_XDECREF(interp->import_modules);
Py_XDECREF(interp->sysdict);
PyMem_DEL(interp);
}
PyThreadState *
PyThreadState_New(PyInterpreterState *interp)
{
PyThreadState *tstate = PyMem_NEW(PyThreadState, 1);
/* fprintf(stderr, "new tstate -> %p\n", tstate); */
if (tstate != NULL) {
tstate->interpreter_state = interp;
tstate->frame = NULL;
tstate->recursion_depth = 0;
tstate->ticker = 0;
tstate->tracing = 0;
tstate->curexc_type = NULL;
tstate->curexc_value = NULL;
tstate->curexc_traceback = NULL;
tstate->exc_type = NULL;
tstate->exc_value = NULL;
tstate->exc_traceback = NULL;
tstate->sys_profilefunc = NULL;
tstate->sys_tracefunc = NULL;
tstate->sys_checkinterval = 0;
interp->nthreads++;
}
return tstate;
}
void
PyThreadState_Delete(PyThreadState *tstate)
{
/* fprintf(stderr, "delete tstate %p\n", 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);
PyMem_DEL(tstate);
}
PyThreadState *
PyThreadState_Get()
{
/* fprintf(stderr, "get tstate -> %p\n", current_tstate); */
return current_tstate;
}
PyThreadState *
PyThreadState_Swap(PyThreadState *new)
{
PyThreadState *old = current_tstate;
/* fprintf(stderr, "swap tstate new=%p <--> old=%p\n", new, old); */
current_tstate = new;
return old;
}
/* How should one use this code?
1. Standard Python interpreter, assuming no other interpreters or threads:
PyInterpreterState *interp;
PyThreadState *tstate;
interp = PyInterpreterState_New();
if (interp == NULL)
Py_FatalError("...");
tstate = PyThreadState_New(interp);
if (tstate == NULL)
Py_FatalError("...");
(void) PyThreadState_Swap(tstate);
PyInitialize();
.
. (use the interpreter here)
.
Py_Cleanup();
PyThreadState_Delete(tstate);
PyInterpreterState_Delete(interp);
2. Totally indepent interpreter invocation in a separate C thread:
XXX Need to interact with the thread lock nevertheless!!!
*/

View File

@ -77,17 +77,11 @@ int Py_VerboseFlag; /* Needed by import.c */
int Py_SuppressPrintingFlag; /* Needed by ceval.c */
int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */
/* Initialize all */
/* Initialize the current interpreter; pass in the Python path. */
void
Py_Initialize()
Py_Setup()
{
static int inited;
if (inited)
return;
inited = 1;
PyImport_Init();
/* Modules '__builtin__' and 'sys' are initialized here,
@ -105,6 +99,46 @@ Py_Initialize()
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;
if (PyThreadState_Get())
return;
interp = PyInterpreterState_New();
if (interp == NULL)
Py_FatalError("PyInterpreterState_New() failed");
tstate = PyThreadState_New(interp);
if (tstate == NULL)
Py_FatalError("PyThreadState_New() failed");
(void) PyThreadState_Swap(tstate);
Py_Setup();
PySys_SetPath(Py_GetPath());
}
/*
Py_Initialize()
-- do everything, no-op on second call, call fatal on failure, set path
#2
-- create new interp+tstate & make it current, return NULL on failure,
make it current, do all setup, set path
#3
-- #2 without set path
#4
-- is there any point to #3 for caller-provided current interp+tstate?
*/
/* Create __main__ module */
static void

View File

@ -48,9 +48,6 @@ Data members:
#include "osdefs.h"
PyObject *_PySys_TraceFunc, *_PySys_ProfileFunc;
int _PySys_CheckInterval = 10;
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
@ -97,6 +94,25 @@ PySys_SetObject(name, v)
return PyDict_SetItemString(sysdict, name, v);
}
static PyObject *
sys_exc_info(self, args)
PyObject *self;
PyObject *args;
{
PyThreadState *tstate;
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,
tstate->exc_value != NULL ? tstate->exc_value : Py_None,
tstate->exc_traceback != NULL ?
tstate->exc_traceback : Py_None);
}
static PyObject *
sys_exit(self, args)
PyObject *self;
@ -112,12 +128,13 @@ sys_settrace(self, args)
PyObject *self;
PyObject *args;
{
PyThreadState *tstate = PyThreadState_Get();
if (args == Py_None)
args = NULL;
else
Py_XINCREF(args);
Py_XDECREF(_PySys_TraceFunc);
_PySys_TraceFunc = args;
Py_XDECREF(tstate->sys_tracefunc);
tstate->sys_tracefunc = args;
Py_INCREF(Py_None);
return Py_None;
}
@ -127,12 +144,13 @@ sys_setprofile(self, args)
PyObject *self;
PyObject *args;
{
PyThreadState *tstate = PyThreadState_Get();
if (args == Py_None)
args = NULL;
else
Py_XINCREF(args);
Py_XDECREF(_PySys_ProfileFunc);
_PySys_ProfileFunc = args;
Py_XDECREF(tstate->sys_profilefunc);
tstate->sys_profilefunc = args;
Py_INCREF(Py_None);
return Py_None;
}
@ -142,7 +160,8 @@ sys_setcheckinterval(self, args)
PyObject *self;
PyObject *args;
{
if (!PyArg_ParseTuple(args, "i", &_PySys_CheckInterval))
PyThreadState *tstate = PyThreadState_Get();
if (!PyArg_ParseTuple(args, "i", &tstate->sys_checkinterval))
return NULL;
Py_INCREF(Py_None);
return Py_None;
@ -202,6 +221,7 @@ extern PyObject *_Py_GetDXProfile Py_PROTO((PyObject *, PyObject *));
static PyMethodDef sys_methods[] = {
/* Might as well keep this in alphabetic order */
{"exc_info", sys_exc_info, 0},
{"exit", sys_exit, 0},
#ifdef COUNT_ALLOCS
{"getcounts", sys_getcounts, 0},
@ -232,7 +252,8 @@ list_builtin_module_names()
if (list == NULL)
return NULL;
for (i = 0; _PyImport_Inittab[i].name != NULL; i++) {
PyObject *name = PyString_FromString(_PyImport_Inittab[i].name);
PyObject *name = PyString_FromString(
_PyImport_Inittab[i].name);
if (name == NULL)
break;
PyList_Append(list, name);

View File

@ -451,3 +451,83 @@ void up_sema _P1(sema, type_sema sema)
if (usvsema((usema_t *) sema) < 0)
perror("usvsema");
}
/*
* Per-thread data ("key") support.
*/
struct key {
struct key *next;
long id;
int key;
void *value;
};
static struct key *keyhead = NULL;
static int nkeys = 0;
static type_lock keymutex = NULL;
static struct key *find_key _P2(key, int key, value, void *value)
{
struct key *p;
long id = get_thread_ident();
for (p = keyhead; p != NULL; p = p->next) {
if (p->id == id && p->key == key)
return p;
}
if (value == NULL)
return NULL;
p = (struct key *)malloc(sizeof(struct key));
if (p != NULL) {
p->id = id;
p->key = key;
p->value = value;
acquire_lock(keymutex, 1);
p->next = keyhead;
keyhead = p;
release_lock(keymutex);
}
return p;
}
int create_key _P0()
{
if (keymutex == NULL)
keymutex = allocate_lock();
return ++nkeys;
}
void delete_key _P1(key, int key)
{
struct key *p, **q;
acquire_lock(keymutex, 1);
q = &keyhead;
while ((p = *q) != NULL) {
if (p->key == key) {
*q = p->next;
free((void *)p);
/* NB This does *not* free p->value! */
}
else
q = &p->next;
}
release_lock(keymutex);
}
int set_key_value _P2(key, int key, value, void *value)
{
struct key *p = find_key(key, value);
if (p == NULL)
return -1;
else
return 0;
}
void *get_key_value _P1(key, int key)
{
struct key *p = find_key(key, NULL);
if (p == NULL)
return NULL;
else
return p->value;
}

View File

@ -117,42 +117,18 @@ newtracebackobject(next, frame, lasti, lineno)
return tb;
}
static tracebackobject *tb_current = NULL;
int
PyTraceBack_Here(frame)
PyFrameObject *frame;
{
tracebackobject *tb;
tb = newtracebackobject(tb_current, frame,
frame->f_lasti, frame->f_lineno);
PyThreadState *tstate = frame->f_tstate;
tracebackobject *oldtb = (tracebackobject *) tstate->curexc_traceback;
tracebackobject *tb = newtracebackobject(oldtb,
frame, frame->f_lasti, frame->f_lineno);
if (tb == NULL)
return -1;
Py_XDECREF(tb_current);
tb_current = tb;
return 0;
}
PyObject *
PyTraceBack_Fetch()
{
PyObject *v;
v = (PyObject *)tb_current;
tb_current = NULL;
return v;
}
int
PyTraceBack_Store(v)
PyObject *v;
{
if (v != NULL && !is_tracebackobject(v)) {
PyErr_BadInternalCall();
return -1;
}
Py_XDECREF(tb_current);
Py_XINCREF(v);
tb_current = (tracebackobject *)v;
tstate->curexc_traceback = (PyObject *)tb;
Py_XDECREF(oldtb);
return 0;
}