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:
parent
73237c54b4
commit
a027efa5bf
|
@ -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))
|
||||
|
|
|
@ -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 *));
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
412
Python/ceval.c
412
Python/ceval.c
|
@ -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.
|
||||
|
||||
The ticker is reset to zero if there are pending
|
||||
calls (see Py_AddPendingCall() and
|
||||
Py_MakePendingCalls() above). */
|
||||
/* 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. */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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!!!
|
||||
|
||||
*/
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue