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 "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))
|
||||||
|
|
|
@ -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 *));
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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},
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
412
Python/ceval.c
412
Python/ceval.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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_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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue