static void faulthandler_thread(void *unused) { PyLockStatus st; const char* errmsg; PyThreadState *current; int ok; do { st = PyThread_acquire_lock_timed(thread.cancel_event, thread.timeout_ms, 0); if (st == PY_LOCK_ACQUIRED) { /* Cancelled by user */ break; } /* Timeout => dump traceback */ assert(st == PY_LOCK_FAILURE); /* get the thread holding the GIL, NULL if no thread hold the GIL */ current = _Py_atomic_load_relaxed(&_PyThreadState_Current); errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, current); ok = (errmsg == NULL); if (thread.exit) _exit(1); } while (ok && thread.repeat); /* The only way out */ PyThread_release_lock(thread.cancel_event); PyThread_release_lock(thread.join_event); }
/* Keep this as a static, as it is not reliable! It can only ever be compared to the state for the *current* thread. * If not equal, then it doesn't matter that the actual value may change immediately after comparison, as it can't possibly change to the current thread's state. * If equal, then the current thread holds the lock, so the value can't change until we yield the lock. */ static int PyThreadState_IsCurrent(PyThreadState *tstate) { /* Must be the tstate for this thread */ assert(PyGILState_GetThisThreadState()==tstate); return tstate == (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current); }
PyThreadState * PyThreadState_Swap(PyThreadState *newts) { PyThreadState *oldts = (PyThreadState*)_Py_atomic_load_relaxed( &_PyThreadState_Current); _Py_atomic_store_relaxed(&_PyThreadState_Current, newts); /* It should not be possible for more than one thread state to be used for a thread. Check this the best we can in debug builds. */ #if defined(Py_DEBUG) && defined(WITH_THREAD) if (newts) { /* This can be called from PyEval_RestoreThread(). Similar to it, we need to ensure errno doesn't change. */ int err = errno; PyThreadState *check = PyGILState_GetThisThreadState(); if (check && check->interp == newts->interp && check != newts) Py_FatalError("Invalid thread state for this thread"); errno = err; } #endif return oldts; }
int PyGILState_Check(void) { /* can't use PyThreadState_Get() since it will assert that it has the GIL */ PyThreadState *tstate = (PyThreadState*)_Py_atomic_load_relaxed( &_PyThreadState_Current); return tstate && (tstate == PyGILState_GetThisThreadState()); }
PyThreadState * PyThreadState_Get(void) { PyThreadState *tstate = (PyThreadState*)_Py_atomic_load_relaxed( &_PyThreadState_Current); if (tstate == NULL) Py_FatalError("PyThreadState_Get: no current thread"); return tstate; }
void PyThreadState_Delete(PyThreadState *tstate) { if (tstate == (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current)) Py_FatalError("PyThreadState_Delete: tstate is still current"); #ifdef WITH_THREAD if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate) PyThread_delete_key_value(autoTLSkey); #endif /* WITH_THREAD */ tstate_delete_common(tstate); }
PyObject * PyErr_Occurred(void) { /* If there is no thread state, PyThreadState_GET calls Py_FatalError, which calls PyErr_Occurred. To avoid the resulting infinite loop, we inline PyThreadState_GET here and treat no thread as no error. */ PyThreadState *tstate = ((PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current)); return tstate == NULL ? NULL : tstate->curexc_type; }
void PyThreadState_DeleteCurrent() { PyThreadState *tstate = (PyThreadState*)_Py_atomic_load_relaxed( &_PyThreadState_Current); if (tstate == NULL) Py_FatalError( "PyThreadState_DeleteCurrent: no current tstate"); _Py_atomic_store_relaxed(&_PyThreadState_Current, NULL); if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate) PyThread_delete_key_value(autoTLSkey); tstate_delete_common(tstate); PyEval_ReleaseLock(); }
PyObject * PyThreadState_GetDict(void) { PyThreadState *tstate = (PyThreadState*)_Py_atomic_load_relaxed( &_PyThreadState_Current); if (tstate == NULL) return NULL; if (tstate->dict == NULL) { PyObject *d; tstate->dict = d = PyDict_New(); if (d == NULL) PyErr_Clear(); } return tstate->dict; }
void Py_FatalError(const char *msg) { const int fd = fileno(stderr); PyThreadState *tstate; fprintf(stderr, "Fatal Python error: %s\n", msg); fflush(stderr); /* it helps in Windows debug build */ if (PyErr_Occurred()) { PyErr_PrintEx(0); } else { tstate = _Py_atomic_load_relaxed(&_PyThreadState_Current); if (tstate != NULL) { fputc('\n', stderr); fflush(stderr); _Py_DumpTracebackThreads(fd, tstate->interp, tstate); } _PyFaulthandler_Fini(); } #ifdef MS_WINDOWS { size_t len = strlen(msg); WCHAR* buffer; size_t i; /* Convert the message to wchar_t. This uses a simple one-to-one conversion, assuming that the this error message actually uses ASCII only. If this ceases to be true, we will have to convert. */ buffer = alloca( (len+1) * (sizeof *buffer)); for( i=0; i<=len; ++i) buffer[i] = msg[i]; OutputDebugStringW(L"Fatal Python error: "); OutputDebugStringW(buffer); OutputDebugStringW(L"\n"); } #ifdef _DEBUG DebugBreak(); #endif #endif /* MS_WINDOWS */ abort(); }
static void faulthandler_thread(void *unused) { PyLockStatus st; const char* errmsg; PyThreadState *current; int ok; #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) sigset_t set; /* we don't want to receive any signal */ sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, NULL); #endif do { st = PyThread_acquire_lock_timed(thread.cancel_event, thread.timeout_us, 0); if (st == PY_LOCK_ACQUIRED) { PyThread_release_lock(thread.cancel_event); break; } /* Timeout => dump traceback */ assert(st == PY_LOCK_FAILURE); /* get the thread holding the GIL, NULL if no thread hold the GIL */ current = _Py_atomic_load_relaxed(&_PyThreadState_Current); write(thread.fd, thread.header, thread.header_len); errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, current); ok = (errmsg == NULL); if (thread.exit) _exit(1); } while (ok && thread.repeat); /* The only way out */ PyThread_release_lock(thread.running); }