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 "import.h"
#include "bltinmodule.h" #include "bltinmodule.h"
#include "pystate.h"
#include "abstract.h" #include "abstract.h"
#define PyArg_GetInt(v, a) PyArg_Parse((v), "i", (a)) #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_locals; /* local symbol table (PyDictObject) */
PyObject **f_valuestack; /* points after the last local */ PyObject **f_valuestack; /* points after the last local */
PyObject *f_trace; /* Trace function */ 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_lasti; /* Last instruction if called */
int f_lineno; /* Current line number */ int f_lineno; /* Current line number */
int f_restricted; /* Flag set if restricted operations 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) #define PyFrame_Check(op) ((op)->ob_type == &PyFrame_Type)
PyFrameObject * PyFrame_New PyFrameObject * PyFrame_New
Py_PROTO((PyFrameObject *, PyCodeObject *, Py_PROTO((PyThreadState *, PyCodeObject *,
PyObject *, PyObject *)); 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 up_sema PyThread_up_sema
#define exit_prog PyThread_exit_prog #define exit_prog PyThread_exit_prog
#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)); void init_thread Py_PROTO((void));
@ -62,6 +66,11 @@ void exit_prog Py_PROTO((int));
void _exit_prog Py_PROTO((int)); void _exit_prog Py_PROTO((int));
#endif #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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -35,6 +35,10 @@ extern "C" {
#define up_sema PyThread_up_sema #define up_sema PyThread_up_sema
#define exit_prog PyThread_exit_prog #define exit_prog PyThread_exit_prog
#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)); void init_thread Py_PROTO((void));
@ -62,6 +66,11 @@ void exit_prog Py_PROTO((int));
void _exit_prog Py_PROTO((int)); void _exit_prog Py_PROTO((int));
#endif #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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -35,14 +35,13 @@ PERFORMANCE OF THIS SOFTWARE.
#include "Python.h" #include "Python.h"
#ifndef WITH_THREAD #ifndef WITH_THREAD
Error! The rest of Python is not compiled with thread support. #error "Error! The rest of Python is not compiled with thread support."
Rerun configure, adding a --with-thread option. #error "Rerun configure, adding a --with-thread option."
#error "Then run `make clean' followed by `make'."
#endif #endif
#include "thread.h" #include "thread.h"
extern int _PyThread_Started;
static PyObject *ThreadError; static PyObject *ThreadError;
@ -192,52 +191,90 @@ static PyTypeObject Locktype = {
/* Module functions */ /* Module functions */
struct bootstate {
PyInterpreterState *interp;
PyObject *func;
PyObject *args;
PyObject *keyw;
};
static void static void
t_bootstrap(args_raw) t_bootstrap(boot_raw)
void *args_raw; void *boot_raw;
{ {
PyObject *args = (PyObject *) args_raw; struct bootstate *boot = (struct bootstate *) boot_raw;
PyObject *func, *arg, *res; PyThreadState *alttstate, *tstate;
PyObject *res;
_PyThread_Started++;
tstate = PyThreadState_New(boot->interp);
PyEval_RestoreThread((void *)NULL); PyEval_RestoreThread((void *)NULL);
func = PyTuple_GetItem(args, 0); alttstate = PyThreadState_Swap(tstate);
arg = PyTuple_GetItem(args, 1); res = PyEval_CallObjectWithKeywords(
res = PyEval_CallObject(func, arg); boot->func, boot->args, boot->keyw);
Py_DECREF(args); /* Matches the INCREF(args) in thread_start_new_thread */ Py_DECREF(boot->func);
Py_DECREF(boot->args);
Py_XDECREF(boot->keyw);
PyMem_DEL(boot_raw);
if (res == NULL) { if (res == NULL) {
if (PyErr_Occurred() == PyExc_SystemExit) if (PyErr_Occurred() == PyExc_SystemExit)
PyErr_Clear(); PyErr_Clear();
else { else {
fprintf(stderr, "Unhandled exception in thread:\n"); fprintf(stderr, "Unhandled exception in thread:\n");
PyErr_Print(); /* From pythonmain.c */ PyErr_Print();
} }
} }
else else
Py_DECREF(res); Py_DECREF(res);
(void) PyEval_SaveThread(); /* Should always be NULL */ (void) PyThreadState_Swap(alttstate);
(void) PyEval_SaveThread();
PyThreadState_Delete(tstate);
exit_thread(); exit_thread();
} }
static PyObject * static PyObject *
thread_start_new_thread(self, args) thread_start_new_thread(self, fargs)
PyObject *self; /* Not used */ 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; return NULL;
Py_INCREF(args); if (!PyCallable_Check(func)) {
/* Initialize the interpreter's stack save/restore mechanism */ PyErr_SetString(PyExc_TypeError,
PyEval_InitThreads(); "first arg must be callable");
if (!start_new_thread(t_bootstrap, (void*) args)) { return NULL;
Py_DECREF(args); }
PyErr_SetString(ThreadError, "can't start new thread\n"); 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; return NULL;
} }
/* Otherwise the DECREF(args) is done by t_bootstrap */
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
@ -294,8 +331,8 @@ thread_get_ident(self, args)
} }
static PyMethodDef thread_methods[] = { static PyMethodDef thread_methods[] = {
{"start_new_thread", (PyCFunction)thread_start_new_thread}, {"start_new_thread", (PyCFunction)thread_start_new_thread, 1},
{"start_new", (PyCFunction)thread_start_new_thread}, {"start_new", (PyCFunction)thread_start_new_thread, 1},
{"allocate_lock", (PyCFunction)thread_allocate_lock}, {"allocate_lock", (PyCFunction)thread_allocate_lock},
{"allocate", (PyCFunction)thread_allocate_lock}, {"allocate", (PyCFunction)thread_allocate_lock},
{"exit_thread", (PyCFunction)thread_exit_thread}, {"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_lineno", T_INT, OFF(f_lineno), RO},
{"f_restricted",T_INT, OFF(f_restricted),RO}, {"f_restricted",T_INT, OFF(f_restricted),RO},
{"f_trace", T_OBJECT, OFF(f_trace)}, {"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 */ {NULL} /* Sentinel */
}; };
@ -112,6 +115,9 @@ frame_dealloc(f)
Py_XDECREF(f->f_globals); Py_XDECREF(f->f_globals);
Py_XDECREF(f->f_locals); Py_XDECREF(f->f_locals);
Py_XDECREF(f->f_trace); 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; f->f_back = free_list;
free_list = f; free_list = f;
} }
@ -134,12 +140,13 @@ PyTypeObject PyFrame_Type = {
}; };
PyFrameObject * PyFrameObject *
PyFrame_New(back, code, globals, locals) PyFrame_New(tstate, code, globals, locals)
PyFrameObject *back; PyThreadState *tstate;
PyCodeObject *code; PyCodeObject *code;
PyObject *globals; PyObject *globals;
PyObject *locals; PyObject *locals;
{ {
PyFrameObject *back = tstate->frame;
static PyObject *builtin_object; static PyObject *builtin_object;
PyFrameObject *f; PyFrameObject *f;
PyObject *builtins; PyObject *builtins;
@ -214,6 +221,10 @@ PyFrame_New(back, code, globals, locals)
} }
f->f_locals = locals; f->f_locals = locals;
f->f_trace = NULL; 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_lasti = 0;
f->f_lineno = code->co_firstlineno; f->f_lineno = code->co_firstlineno;

View File

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

View File

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

View File

@ -55,23 +55,34 @@ extern char *strerror Py_PROTO((int));
#endif #endif
#endif #endif
/* Last exception stored */
static PyObject *last_exception;
static PyObject *last_exc_val;
void void
PyErr_Restore(exception, value, traceback) PyErr_Restore(type, value, traceback)
PyObject *exception; PyObject *type;
PyObject *value; PyObject *value;
PyObject *traceback; PyObject *traceback;
{ {
PyErr_Clear(); PyThreadState *tstate = PyThreadState_Get();
PyObject *oldtype, *oldvalue, *oldtraceback;
last_exception = exception; if (traceback != NULL && !PyTraceBack_Check(traceback)) {
last_exc_val = value; /* XXX Should never happen -- fatal error instead? */
(void) PyTraceBack_Store(traceback); Py_DECREF(traceback);
Py_XDECREF(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 void
@ -105,33 +116,32 @@ PyErr_SetString(exception, string)
PyObject * PyObject *
PyErr_Occurred() PyErr_Occurred()
{ {
return last_exception; PyThreadState *tstate = PyThreadState_Get();
return tstate->curexc_type;
} }
void void
PyErr_Fetch(p_exc, p_val, p_tb) PyErr_Fetch(p_type, p_value, p_traceback)
PyObject **p_exc; PyObject **p_type;
PyObject **p_val; PyObject **p_value;
PyObject **p_tb; PyObject **p_traceback;
{ {
*p_exc = last_exception; PyThreadState *tstate = PyThreadState_Get();
last_exception = NULL;
*p_val = last_exc_val; *p_type = tstate->curexc_type;
last_exc_val = NULL; *p_value = tstate->curexc_value;
*p_tb = PyTraceBack_Fetch(); *p_traceback = tstate->curexc_traceback;
tstate->curexc_type = NULL;
tstate->curexc_value = NULL;
tstate->curexc_traceback = NULL;
} }
void void
PyErr_Clear() PyErr_Clear()
{ {
PyObject *tb; PyErr_Restore(NULL, NULL, NULL);
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);
} }
/* Convenience functions to set a type error exception and return 0 */ /* Convenience functions to set a type error exception and return 0 */
@ -139,7 +149,8 @@ PyErr_Clear()
int int
PyErr_BadArgument() 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; return 0;
} }
@ -171,7 +182,8 @@ PyErr_SetFromErrno(exc)
void void
PyErr_BadInternalCall() 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_SuppressPrintingFlag; /* Needed by ceval.c */
int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */ int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */
/* Initialize all */ /* Initialize the current interpreter; pass in the Python path. */
void void
Py_Initialize() Py_Setup()
{ {
static int inited;
if (inited)
return;
inited = 1;
PyImport_Init(); PyImport_Init();
/* Modules '__builtin__' and 'sys' are initialized here, /* Modules '__builtin__' and 'sys' are initialized here,
@ -105,6 +99,46 @@ Py_Initialize()
initmain(); 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 */ /* Create __main__ module */
static void static void

View File

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

View File

@ -451,3 +451,83 @@ void up_sema _P1(sema, type_sema sema)
if (usvsema((usema_t *) sema) < 0) if (usvsema((usema_t *) sema) < 0)
perror("usvsema"); 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; return tb;
} }
static tracebackobject *tb_current = NULL;
int int
PyTraceBack_Here(frame) PyTraceBack_Here(frame)
PyFrameObject *frame; PyFrameObject *frame;
{ {
tracebackobject *tb; PyThreadState *tstate = frame->f_tstate;
tb = newtracebackobject(tb_current, frame, tracebackobject *oldtb = (tracebackobject *) tstate->curexc_traceback;
frame->f_lasti, frame->f_lineno); tracebackobject *tb = newtracebackobject(oldtb,
frame, frame->f_lasti, frame->f_lineno);
if (tb == NULL) if (tb == NULL)
return -1; return -1;
Py_XDECREF(tb_current); tstate->curexc_traceback = (PyObject *)tb;
tb_current = tb; Py_XDECREF(oldtb);
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;
return 0; return 0;
} }