Commit a027efa5 authored by Guido van Rossum's avatar Guido van Rossum

Massive changes for separate thread state management.

All per-thread globals are moved into a struct which is manipulated
separately.
parent 73237c54
......@@ -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 *));
......
#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;
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);
/* Initialize the interpreter's stack save/restore mechanism */
PyEval_InitThreads();
if (!start_new_thread(t_bootstrap, (void*) args)) {
Py_DECREF(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
......
This diff is collapsed.
......@@ -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;
if (traceback != NULL && !PyTraceBack_Check(traceback)) {
/* XXX Should never happen -- fatal error instead? */
Py_DECREF(traceback);
traceback = NULL;
}
last_exception = exception;
last_exc_val = value;
(void) PyTraceBack_Store(traceback);
Py_XDECREF(traceback);
/* 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");
}
......
/***********************************************************
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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment