/* Thread and interpreter state structures and their interfaces */ #include "Python.h" #define ZAP(x) { \ PyObject *tmp = (PyObject *)(x); \ (x) = NULL; \ Py_XDECREF(tmp); \ } #ifdef WITH_THREAD #include "pythread.h" static PyThread_type_lock head_mutex = NULL; /* Protects interp->tstate_head */ #define HEAD_INIT() (void)(head_mutex || (head_mutex = PyThread_allocate_lock())) #define HEAD_LOCK() PyThread_acquire_lock(head_mutex, WAIT_LOCK) #define HEAD_UNLOCK() PyThread_release_lock(head_mutex) #else #define HEAD_INIT() /* Nothing */ #define HEAD_LOCK() /* Nothing */ #define HEAD_UNLOCK() /* Nothing */ #endif static PyInterpreterState *interp_head = NULL; PyThreadState *_PyThreadState_Current = NULL; PyInterpreterState * PyInterpreterState_New(void) { PyInterpreterState *interp = PyMem_NEW(PyInterpreterState, 1); if (interp != NULL) { HEAD_INIT(); interp->modules = NULL; interp->sysdict = NULL; interp->builtins = NULL; interp->checkinterval = 10; interp->tstate_head = NULL; interp->next = interp_head; interp_head = interp; } return interp; } void PyInterpreterState_Clear(PyInterpreterState *interp) { PyThreadState *p; HEAD_LOCK(); for (p = interp->tstate_head; p != NULL; p = p->next) PyThreadState_Clear(p); HEAD_UNLOCK(); ZAP(interp->modules); ZAP(interp->sysdict); ZAP(interp->builtins); } static void zapthreads(PyInterpreterState *interp) { PyThreadState *p; /* No need to lock the mutex here because this should only happen when the threads are all really dead (XXX famous last words). */ while ((p = interp->tstate_head) != NULL) { PyThreadState_Delete(p); } } void PyInterpreterState_Delete(PyInterpreterState *interp) { PyInterpreterState **p; zapthreads(interp); for (p = &interp_head; ; p = &(*p)->next) { if (*p == NULL) Py_FatalError( "PyInterpreterState_Delete: invalid interp"); if (*p == interp) break; } if (interp->tstate_head != NULL) Py_FatalError("PyInterpreterState_Delete: remaining threads"); *p = interp->next; PyMem_DEL(interp); } PyThreadState * PyThreadState_New(PyInterpreterState *interp) { PyThreadState *tstate = PyMem_NEW(PyThreadState, 1); if (tstate != NULL) { tstate->interp = interp; tstate->frame = NULL; tstate->recursion_depth = 0; tstate->ticker = 0; tstate->tracing = 0; tstate->dict = NULL; 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; HEAD_LOCK(); tstate->next = interp->tstate_head; interp->tstate_head = tstate; HEAD_UNLOCK(); } return tstate; } void PyThreadState_Clear(PyThreadState *tstate) { if (Py_VerboseFlag && tstate->frame != NULL) fprintf(stderr, "PyThreadState_Clear: warning: thread still has a frame\n"); ZAP(tstate->frame); ZAP(tstate->dict); ZAP(tstate->curexc_type); ZAP(tstate->curexc_value); ZAP(tstate->curexc_traceback); ZAP(tstate->exc_type); ZAP(tstate->exc_value); ZAP(tstate->exc_traceback); ZAP(tstate->sys_profilefunc); ZAP(tstate->sys_tracefunc); } void PyThreadState_Delete(PyThreadState *tstate) { PyInterpreterState *interp; PyThreadState **p; if (tstate == NULL) Py_FatalError("PyThreadState_Delete: NULL tstate"); if (tstate == _PyThreadState_Current) Py_FatalError("PyThreadState_Delete: tstate is still current"); interp = tstate->interp; if (interp == NULL) Py_FatalError("PyThreadState_Delete: NULL interp"); HEAD_LOCK(); for (p = &interp->tstate_head; ; p = &(*p)->next) { if (*p == NULL) Py_FatalError( "PyThreadState_Delete: invalid tstate"); if (*p == tstate) break; } *p = tstate->next; HEAD_UNLOCK(); PyMem_DEL(tstate); } PyThreadState * PyThreadState_Get(void) { if (_PyThreadState_Current == NULL) Py_FatalError("PyThreadState_Get: no current thread"); return _PyThreadState_Current; } PyThreadState * PyThreadState_Swap(PyThreadState *new) { PyThreadState *old = _PyThreadState_Current; _PyThreadState_Current = new; return old; } /* An extension mechanism to store arbitrary additional per-thread state. PyThreadState_GetDict() returns a dictionary that can be used to hold such state; the caller should pick a unique key and store its state there. If PyThreadState_GetDict() returns NULL, an exception has been raised (most likely MemoryError) and the caller should pass on the exception. */ PyObject * PyThreadState_GetDict(void) { if (_PyThreadState_Current == NULL) Py_FatalError("PyThreadState_GetDict: no current thread"); if (_PyThreadState_Current->dict == NULL) _PyThreadState_Current->dict = PyDict_New(); return _PyThreadState_Current->dict; }