diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:30 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:30 +0300 |
commit | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (patch) | |
tree | 012bb94d777798f1f56ac1cec429509766d05181 /contrib/tools/python3/src/Modules/_threadmodule.c | |
parent | 6751af0b0c1b952fede40b19b71da8025b5d8bcf (diff) | |
download | ydb-2598ef1d0aee359b4b6d5fdd1758916d5907d04f.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/python3/src/Modules/_threadmodule.c')
-rw-r--r-- | contrib/tools/python3/src/Modules/_threadmodule.c | 630 |
1 files changed, 315 insertions, 315 deletions
diff --git a/contrib/tools/python3/src/Modules/_threadmodule.c b/contrib/tools/python3/src/Modules/_threadmodule.c index a370352238..5101259577 100644 --- a/contrib/tools/python3/src/Modules/_threadmodule.c +++ b/contrib/tools/python3/src/Modules/_threadmodule.c @@ -3,16 +3,16 @@ /* Interface to Sjoerd's portable C thread library */ #include "Python.h" -#include "pycore_pylifecycle.h" -#include "pycore_interp.h" // _PyInterpreterState.num_threads -#include "pycore_pystate.h" // _PyThreadState_Init() -#include <stddef.h> // offsetof() +#include "pycore_pylifecycle.h" +#include "pycore_interp.h" // _PyInterpreterState.num_threads +#include "pycore_pystate.h" // _PyThreadState_Init() +#include <stddef.h> // offsetof() static PyObject *ThreadError; static PyObject *str_dict; _Py_IDENTIFIER(stderr); -_Py_IDENTIFIER(flush); +_Py_IDENTIFIER(flush); /* Lock objects */ @@ -165,7 +165,7 @@ and the return value reflects whether the lock is acquired.\n\ The blocking operation is interruptible."); static PyObject * -lock_PyThread_release_lock(lockobject *self, PyObject *Py_UNUSED(ignored)) +lock_PyThread_release_lock(lockobject *self, PyObject *Py_UNUSED(ignored)) { /* Sanity check: the lock must be locked */ if (!self->locked) { @@ -187,7 +187,7 @@ the lock to acquire the lock. The lock must be in the locked state,\n\ but it needn't be locked by the same thread that unlocks it."); static PyObject * -lock_locked_lock(lockobject *self, PyObject *Py_UNUSED(ignored)) +lock_locked_lock(lockobject *self, PyObject *Py_UNUSED(ignored)) { return PyBool_FromLong((long)self->locked); } @@ -205,26 +205,26 @@ lock_repr(lockobject *self) self->locked ? "locked" : "unlocked", Py_TYPE(self)->tp_name, self); } -#ifdef HAVE_FORK -static PyObject * -lock__at_fork_reinit(lockobject *self, PyObject *Py_UNUSED(args)) -{ - if (_PyThread_at_fork_reinit(&self->lock_lock) < 0) { - PyErr_SetString(ThreadError, "failed to reinitialize lock at fork"); - return NULL; - } - - self->locked = 0; - - Py_RETURN_NONE; -} -#endif /* HAVE_FORK */ - - +#ifdef HAVE_FORK +static PyObject * +lock__at_fork_reinit(lockobject *self, PyObject *Py_UNUSED(args)) +{ + if (_PyThread_at_fork_reinit(&self->lock_lock) < 0) { + PyErr_SetString(ThreadError, "failed to reinitialize lock at fork"); + return NULL; + } + + self->locked = 0; + + Py_RETURN_NONE; +} +#endif /* HAVE_FORK */ + + static PyMethodDef lock_methods[] = { - {"acquire_lock", (PyCFunction)(void(*)(void))lock_PyThread_acquire_lock, + {"acquire_lock", (PyCFunction)(void(*)(void))lock_PyThread_acquire_lock, METH_VARARGS | METH_KEYWORDS, acquire_doc}, - {"acquire", (PyCFunction)(void(*)(void))lock_PyThread_acquire_lock, + {"acquire", (PyCFunction)(void(*)(void))lock_PyThread_acquire_lock, METH_VARARGS | METH_KEYWORDS, acquire_doc}, {"release_lock", (PyCFunction)lock_PyThread_release_lock, METH_NOARGS, release_doc}, @@ -234,14 +234,14 @@ static PyMethodDef lock_methods[] = { METH_NOARGS, locked_doc}, {"locked", (PyCFunction)lock_locked_lock, METH_NOARGS, locked_doc}, - {"__enter__", (PyCFunction)(void(*)(void))lock_PyThread_acquire_lock, + {"__enter__", (PyCFunction)(void(*)(void))lock_PyThread_acquire_lock, METH_VARARGS | METH_KEYWORDS, acquire_doc}, {"__exit__", (PyCFunction)lock_PyThread_release_lock, METH_VARARGS, release_doc}, -#ifdef HAVE_FORK - {"_at_fork_reinit", (PyCFunction)lock__at_fork_reinit, - METH_NOARGS, NULL}, -#endif +#ifdef HAVE_FORK + {"_at_fork_reinit", (PyCFunction)lock__at_fork_reinit, + METH_NOARGS, NULL}, +#endif {NULL, NULL} /* sentinel */ }; @@ -252,10 +252,10 @@ static PyTypeObject Locktype = { 0, /*tp_itemsize*/ /* methods */ (destructor)lock_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ + 0, /*tp_vectorcall_offset*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ - 0, /*tp_as_async*/ + 0, /*tp_as_async*/ (reprfunc)lock_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ @@ -355,7 +355,7 @@ internal counter is simply incremented. If nobody holds the lock,\n\ the lock is taken and its internal counter initialized to 1."); static PyObject * -rlock_release(rlockobject *self, PyObject *Py_UNUSED(ignored)) +rlock_release(rlockobject *self, PyObject *Py_UNUSED(ignored)) { unsigned long tid = PyThread_get_thread_ident(); @@ -414,7 +414,7 @@ PyDoc_STRVAR(rlock_acquire_restore_doc, For internal use by `threading.Condition`."); static PyObject * -rlock_release_save(rlockobject *self, PyObject *Py_UNUSED(ignored)) +rlock_release_save(rlockobject *self, PyObject *Py_UNUSED(ignored)) { unsigned long owner; unsigned long count; @@ -440,7 +440,7 @@ For internal use by `threading.Condition`."); static PyObject * -rlock_is_owned(rlockobject *self, PyObject *Py_UNUSED(ignored)) +rlock_is_owned(rlockobject *self, PyObject *Py_UNUSED(ignored)) { unsigned long tid = PyThread_get_thread_ident(); @@ -458,19 +458,19 @@ For internal use by `threading.Condition`."); static PyObject * rlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - rlockobject *self = (rlockobject *) type->tp_alloc(type, 0); - if (self == NULL) { - return NULL; - } - self->in_weakreflist = NULL; - self->rlock_owner = 0; - self->rlock_count = 0; - - self->rlock_lock = PyThread_allocate_lock(); - if (self->rlock_lock == NULL) { - Py_DECREF(self); - PyErr_SetString(ThreadError, "can't allocate lock"); - return NULL; + rlockobject *self = (rlockobject *) type->tp_alloc(type, 0); + if (self == NULL) { + return NULL; + } + self->in_weakreflist = NULL; + self->rlock_owner = 0; + self->rlock_count = 0; + + self->rlock_lock = PyThread_allocate_lock(); + if (self->rlock_lock == NULL) { + Py_DECREF(self); + PyErr_SetString(ThreadError, "can't allocate lock"); + return NULL; } return (PyObject *) self; } @@ -485,25 +485,25 @@ rlock_repr(rlockobject *self) } -#ifdef HAVE_FORK -static PyObject * -rlock__at_fork_reinit(rlockobject *self, PyObject *Py_UNUSED(args)) -{ - if (_PyThread_at_fork_reinit(&self->rlock_lock) < 0) { - PyErr_SetString(ThreadError, "failed to reinitialize lock at fork"); - return NULL; - } - - self->rlock_owner = 0; - self->rlock_count = 0; - - Py_RETURN_NONE; -} -#endif /* HAVE_FORK */ - - +#ifdef HAVE_FORK +static PyObject * +rlock__at_fork_reinit(rlockobject *self, PyObject *Py_UNUSED(args)) +{ + if (_PyThread_at_fork_reinit(&self->rlock_lock) < 0) { + PyErr_SetString(ThreadError, "failed to reinitialize lock at fork"); + return NULL; + } + + self->rlock_owner = 0; + self->rlock_count = 0; + + Py_RETURN_NONE; +} +#endif /* HAVE_FORK */ + + static PyMethodDef rlock_methods[] = { - {"acquire", (PyCFunction)(void(*)(void))rlock_acquire, + {"acquire", (PyCFunction)(void(*)(void))rlock_acquire, METH_VARARGS | METH_KEYWORDS, rlock_acquire_doc}, {"release", (PyCFunction)rlock_release, METH_NOARGS, rlock_release_doc}, @@ -513,14 +513,14 @@ static PyMethodDef rlock_methods[] = { METH_VARARGS, rlock_acquire_restore_doc}, {"_release_save", (PyCFunction)rlock_release_save, METH_NOARGS, rlock_release_save_doc}, - {"__enter__", (PyCFunction)(void(*)(void))rlock_acquire, + {"__enter__", (PyCFunction)(void(*)(void))rlock_acquire, METH_VARARGS | METH_KEYWORDS, rlock_acquire_doc}, {"__exit__", (PyCFunction)rlock_release, METH_VARARGS, rlock_release_doc}, -#ifdef HAVE_FORK - {"_at_fork_reinit", (PyCFunction)rlock__at_fork_reinit, - METH_NOARGS, NULL}, -#endif +#ifdef HAVE_FORK + {"_at_fork_reinit", (PyCFunction)rlock__at_fork_reinit, + METH_NOARGS, NULL}, +#endif {NULL, NULL} /* sentinel */ }; @@ -532,10 +532,10 @@ static PyTypeObject RLocktype = { 0, /*tp_itemsize*/ /* methods */ (destructor)rlock_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ + 0, /*tp_vectorcall_offset*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ - 0, /*tp_as_async*/ + 0, /*tp_as_async*/ (reprfunc)rlock_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ @@ -646,10 +646,10 @@ static PyTypeObject localdummytype = { /* tp_basicsize */ sizeof(localdummyobject), /* tp_itemsize */ 0, /* tp_dealloc */ (destructor)localdummy_dealloc, - /* tp_vectorcall_offset */ 0, + /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, - /* tp_as_async */ 0, + /* tp_as_async */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, @@ -853,11 +853,11 @@ _ldict(localobject *self) return NULL; } - dummy = PyDict_GetItemWithError(tdict, self->key); + dummy = PyDict_GetItemWithError(tdict, self->key); if (dummy == NULL) { - if (PyErr_Occurred()) { - return NULL; - } + if (PyErr_Occurred()) { + return NULL; + } ldict = _local_create_dummy(self); if (ldict == NULL) return NULL; @@ -873,7 +873,7 @@ _ldict(localobject *self) } } else { - assert(Py_IS_TYPE(dummy, &localdummytype)); + assert(Py_IS_TYPE(dummy, &localdummytype)); ldict = ((localdummyobject *) dummy)->localdict; } @@ -911,10 +911,10 @@ static PyTypeObject localtype = { /* tp_basicsize */ sizeof(localobject), /* tp_itemsize */ 0, /* tp_dealloc */ (destructor)local_dealloc, - /* tp_vectorcall_offset */ 0, + /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, - /* tp_as_async */ 0, + /* tp_as_async */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, @@ -967,23 +967,23 @@ local_getattro(localobject *self, PyObject *name) if (r == -1) return NULL; - if (!Py_IS_TYPE(self, &localtype)) + if (!Py_IS_TYPE(self, &localtype)) /* use generic lookup for subtypes */ return _PyObject_GenericGetAttrWithDict( (PyObject *)self, name, ldict, 0); /* Optimization: just look in dict ourselves */ - value = PyDict_GetItemWithError(ldict, name); - if (value != NULL) { - Py_INCREF(value); - return value; - } - else if (PyErr_Occurred()) { - return NULL; - } - /* Fall back on generic to get __class__ and __dict__ */ - return _PyObject_GenericGetAttrWithDict( - (PyObject *)self, name, ldict, 0); + value = PyDict_GetItemWithError(ldict, name); + if (value != NULL) { + Py_INCREF(value); + return value; + } + else if (PyErr_Occurred()) { + return NULL; + } + /* Fall back on generic to get __class__ and __dict__ */ + return _PyObject_GenericGetAttrWithDict( + (PyObject *)self, name, ldict, 0); } /* Called when a dummy is destroyed. */ @@ -1003,7 +1003,7 @@ _localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref) self = (localobject *) obj; if (self->dummies != NULL) { PyObject *ldict; - ldict = PyDict_GetItemWithError(self->dummies, dummyweakref); + ldict = PyDict_GetItemWithError(self->dummies, dummyweakref); if (ldict != NULL) { PyDict_DelItem(self->dummies, dummyweakref); } @@ -1022,7 +1022,7 @@ struct bootstate { PyObject *args; PyObject *keyw; PyThreadState *tstate; - _PyRuntimeState *runtime; + _PyRuntimeState *runtime; }; static void @@ -1034,38 +1034,38 @@ t_bootstrap(void *boot_raw) tstate = boot->tstate; tstate->thread_id = PyThread_get_thread_ident(); - _PyThreadState_Init(tstate); + _PyThreadState_Init(tstate); PyEval_AcquireThread(tstate); tstate->interp->num_threads++; res = PyObject_Call(boot->func, boot->args, boot->keyw); if (res == NULL) { if (PyErr_ExceptionMatches(PyExc_SystemExit)) - /* SystemExit is ignored silently */ + /* SystemExit is ignored silently */ PyErr_Clear(); else { - _PyErr_WriteUnraisableMsg("in thread started by", boot->func); + _PyErr_WriteUnraisableMsg("in thread started by", boot->func); } } - else { + else { Py_DECREF(res); - } + } Py_DECREF(boot->func); Py_DECREF(boot->args); Py_XDECREF(boot->keyw); PyMem_DEL(boot_raw); tstate->interp->num_threads--; PyThreadState_Clear(tstate); - _PyThreadState_DeleteCurrent(tstate); - - // bpo-44434: Don't call explicitly PyThread_exit_thread(). On Linux with - // the glibc, pthread_exit() can abort the whole process if dlopen() fails - // to open the libgcc_s.so library (ex: EMFILE error). + _PyThreadState_DeleteCurrent(tstate); + + // bpo-44434: Don't call explicitly PyThread_exit_thread(). On Linux with + // the glibc, pthread_exit() can abort the whole process if dlopen() fails + // to open the libgcc_s.so library (ex: EMFILE error). } static PyObject * thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) { - _PyRuntimeState *runtime = &_PyRuntime; + _PyRuntimeState *runtime = &_PyRuntime; PyObject *func, *args, *keyw = NULL; struct bootstate *boot; unsigned long ident; @@ -1088,23 +1088,23 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) "optional 3rd arg must be a dictionary"); return NULL; } - - PyInterpreterState *interp = _PyInterpreterState_GET(); - if (interp->config._isolated_interpreter) { - PyErr_SetString(PyExc_RuntimeError, - "thread is not supported for isolated subinterpreters"); - return NULL; - } - + + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (interp->config._isolated_interpreter) { + PyErr_SetString(PyExc_RuntimeError, + "thread is not supported for isolated subinterpreters"); + return NULL; + } + boot = PyMem_NEW(struct bootstate, 1); if (boot == NULL) return PyErr_NoMemory(); - boot->interp = _PyInterpreterState_GET(); + boot->interp = _PyInterpreterState_GET(); boot->func = func; boot->args = args; boot->keyw = keyw; boot->tstate = _PyThreadState_Prealloc(boot->interp); - boot->runtime = runtime; + boot->runtime = runtime; if (boot->tstate == NULL) { PyMem_DEL(boot); return PyErr_NoMemory(); @@ -1112,7 +1112,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) Py_INCREF(func); Py_INCREF(args); Py_XINCREF(keyw); - + ident = PyThread_start_new_thread(t_bootstrap, (void*) boot); if (ident == PYTHREAD_INVALID_THREAD_ID) { PyErr_SetString(ThreadError, "can't start new thread"); @@ -1138,7 +1138,7 @@ when the function raises an unhandled exception; a stack trace will be\n\ printed unless the exception is SystemExit.\n"); static PyObject * -thread_PyThread_exit_thread(PyObject *self, PyObject *Py_UNUSED(ignored)) +thread_PyThread_exit_thread(PyObject *self, PyObject *Py_UNUSED(ignored)) { PyErr_SetNone(PyExc_SystemExit); return NULL; @@ -1152,7 +1152,7 @@ This is synonymous to ``raise SystemExit''. It will cause the current\n\ thread to exit silently unless the exception is caught."); static PyObject * -thread_PyThread_interrupt_main(PyObject * self, PyObject *Py_UNUSED(ignored)) +thread_PyThread_interrupt_main(PyObject * self, PyObject *Py_UNUSED(ignored)) { PyErr_SetInterrupt(); Py_RETURN_NONE; @@ -1168,7 +1168,7 @@ A subthread can use this function to interrupt the main thread." static lockobject *newlockobject(void); static PyObject * -thread_PyThread_allocate_lock(PyObject *self, PyObject *Py_UNUSED(ignored)) +thread_PyThread_allocate_lock(PyObject *self, PyObject *Py_UNUSED(ignored)) { return (PyObject *) newlockobject(); } @@ -1181,7 +1181,7 @@ Create a new lock object. See help(type(threading.Lock())) for\n\ information about locks."); static PyObject * -thread_get_ident(PyObject *self, PyObject *Py_UNUSED(ignored)) +thread_get_ident(PyObject *self, PyObject *Py_UNUSED(ignored)) { unsigned long ident = PyThread_get_thread_ident(); if (ident == PYTHREAD_INVALID_THREAD_ID) { @@ -1202,34 +1202,34 @@ allocated consecutive numbers starting at 1, this behavior should not\n\ be relied upon, and the number should be seen purely as a magic cookie.\n\ A thread's identity may be reused for another thread after it exits."); -#ifdef PY_HAVE_THREAD_NATIVE_ID +#ifdef PY_HAVE_THREAD_NATIVE_ID static PyObject * -thread_get_native_id(PyObject *self, PyObject *Py_UNUSED(ignored)) +thread_get_native_id(PyObject *self, PyObject *Py_UNUSED(ignored)) { - unsigned long native_id = PyThread_get_thread_native_id(); - return PyLong_FromUnsignedLong(native_id); -} - -PyDoc_STRVAR(get_native_id_doc, -"get_native_id() -> integer\n\ -\n\ -Return a non-negative integer identifying the thread as reported\n\ -by the OS (kernel). This may be used to uniquely identify a\n\ -particular thread within a system."); -#endif - -static PyObject * -thread__count(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - PyInterpreterState *interp = _PyInterpreterState_GET(); - return PyLong_FromLong(interp->num_threads); + unsigned long native_id = PyThread_get_thread_native_id(); + return PyLong_FromUnsignedLong(native_id); } +PyDoc_STRVAR(get_native_id_doc, +"get_native_id() -> integer\n\ +\n\ +Return a non-negative integer identifying the thread as reported\n\ +by the OS (kernel). This may be used to uniquely identify a\n\ +particular thread within a system."); +#endif + +static PyObject * +thread__count(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return PyLong_FromLong(interp->num_threads); +} + PyDoc_STRVAR(_count_doc, "_count() -> integer\n\ \n\ \ -Return the number of currently running Python threads, excluding\n\ +Return the number of currently running Python threads, excluding\n\ the main thread. The returned number comprises all threads created\n\ through `start_new_thread()` as well as `threading.Thread`, and not\n\ yet finished.\n\ @@ -1238,16 +1238,16 @@ This function is meant for internal and specialized purposes only.\n\ In most applications `threading.enumerate()` should be used instead."); static void -release_sentinel(void *wr_raw) +release_sentinel(void *wr_raw) { - PyObject *wr = _PyObject_CAST(wr_raw); + PyObject *wr = _PyObject_CAST(wr_raw); /* Tricky: this function is called when the current thread state is being deleted. Therefore, only simple C code can safely execute here. */ PyObject *obj = PyWeakref_GET_OBJECT(wr); lockobject *lock; if (obj != Py_None) { - assert(Py_IS_TYPE(obj, &Locktype)); + assert(Py_IS_TYPE(obj, &Locktype)); lock = (lockobject *) obj; if (lock->locked) { PyThread_release_lock(lock->lock_lock); @@ -1260,7 +1260,7 @@ release_sentinel(void *wr_raw) } static PyObject * -thread__set_sentinel(PyObject *self, PyObject *Py_UNUSED(ignored)) +thread__set_sentinel(PyObject *self, PyObject *Py_UNUSED(ignored)) { PyObject *wr; PyThreadState *tstate = PyThreadState_Get(); @@ -1352,177 +1352,177 @@ requiring allocation in multiples of the system memory page size\n\ (4 KiB pages are common; using multiples of 4096 for the stack size is\n\ the suggested approach in the absence of more specific information)."); -static int -thread_excepthook_file(PyObject *file, PyObject *exc_type, PyObject *exc_value, - PyObject *exc_traceback, PyObject *thread) -{ - _Py_IDENTIFIER(name); - /* print(f"Exception in thread {thread.name}:", file=file) */ - if (PyFile_WriteString("Exception in thread ", file) < 0) { - return -1; - } - - PyObject *name = NULL; - if (thread != Py_None) { - if (_PyObject_LookupAttrId(thread, &PyId_name, &name) < 0) { - return -1; - } - } - if (name != NULL) { - if (PyFile_WriteObject(name, file, Py_PRINT_RAW) < 0) { - Py_DECREF(name); - return -1; - } - Py_DECREF(name); - } - else { - unsigned long ident = PyThread_get_thread_ident(); - PyObject *str = PyUnicode_FromFormat("%lu", ident); - if (str != NULL) { - if (PyFile_WriteObject(str, file, Py_PRINT_RAW) < 0) { - Py_DECREF(str); - return -1; - } - Py_DECREF(str); - } - else { - PyErr_Clear(); - - if (PyFile_WriteString("<failed to get thread name>", file) < 0) { - return -1; - } - } - } - - if (PyFile_WriteString(":\n", file) < 0) { - return -1; - } - - /* Display the traceback */ - _PyErr_Display(file, exc_type, exc_value, exc_traceback); - - /* Call file.flush() */ - PyObject *res = _PyObject_CallMethodIdNoArgs(file, &PyId_flush); - if (!res) { - return -1; - } - Py_DECREF(res); - - return 0; -} - - -PyDoc_STRVAR(ExceptHookArgs__doc__, -"ExceptHookArgs\n\ -\n\ -Type used to pass arguments to threading.excepthook."); - -static PyTypeObject ExceptHookArgsType; - -static PyStructSequence_Field ExceptHookArgs_fields[] = { - {"exc_type", "Exception type"}, - {"exc_value", "Exception value"}, - {"exc_traceback", "Exception traceback"}, - {"thread", "Thread"}, - {0} -}; - -static PyStructSequence_Desc ExceptHookArgs_desc = { - .name = "_thread.ExceptHookArgs", - .doc = ExceptHookArgs__doc__, - .fields = ExceptHookArgs_fields, - .n_in_sequence = 4 -}; - - -static PyObject * -thread_excepthook(PyObject *self, PyObject *args) -{ - if (!Py_IS_TYPE(args, &ExceptHookArgsType)) { - PyErr_SetString(PyExc_TypeError, - "_thread.excepthook argument type " - "must be ExceptHookArgs"); - return NULL; - } - - /* Borrowed reference */ - PyObject *exc_type = PyStructSequence_GET_ITEM(args, 0); - if (exc_type == PyExc_SystemExit) { - /* silently ignore SystemExit */ - Py_RETURN_NONE; - } - - /* Borrowed references */ - PyObject *exc_value = PyStructSequence_GET_ITEM(args, 1); - PyObject *exc_tb = PyStructSequence_GET_ITEM(args, 2); - PyObject *thread = PyStructSequence_GET_ITEM(args, 3); - - PyObject *file = _PySys_GetObjectId(&PyId_stderr); - if (file == NULL || file == Py_None) { - if (thread == Py_None) { - /* do nothing if sys.stderr is None and thread is None */ - Py_RETURN_NONE; - } - - file = PyObject_GetAttrString(thread, "_stderr"); - if (file == NULL) { - return NULL; - } - if (file == Py_None) { - Py_DECREF(file); - /* do nothing if sys.stderr is None and sys.stderr was None - when the thread was created */ - Py_RETURN_NONE; - } - } - else { - Py_INCREF(file); - } - - int res = thread_excepthook_file(file, exc_type, exc_value, exc_tb, - thread); - Py_DECREF(file); - if (res < 0) { - return NULL; - } - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(excepthook_doc, -"excepthook(exc_type, exc_value, exc_traceback, thread)\n\ -\n\ -Handle uncaught Thread.run() exception."); - +static int +thread_excepthook_file(PyObject *file, PyObject *exc_type, PyObject *exc_value, + PyObject *exc_traceback, PyObject *thread) +{ + _Py_IDENTIFIER(name); + /* print(f"Exception in thread {thread.name}:", file=file) */ + if (PyFile_WriteString("Exception in thread ", file) < 0) { + return -1; + } + + PyObject *name = NULL; + if (thread != Py_None) { + if (_PyObject_LookupAttrId(thread, &PyId_name, &name) < 0) { + return -1; + } + } + if (name != NULL) { + if (PyFile_WriteObject(name, file, Py_PRINT_RAW) < 0) { + Py_DECREF(name); + return -1; + } + Py_DECREF(name); + } + else { + unsigned long ident = PyThread_get_thread_ident(); + PyObject *str = PyUnicode_FromFormat("%lu", ident); + if (str != NULL) { + if (PyFile_WriteObject(str, file, Py_PRINT_RAW) < 0) { + Py_DECREF(str); + return -1; + } + Py_DECREF(str); + } + else { + PyErr_Clear(); + + if (PyFile_WriteString("<failed to get thread name>", file) < 0) { + return -1; + } + } + } + + if (PyFile_WriteString(":\n", file) < 0) { + return -1; + } + + /* Display the traceback */ + _PyErr_Display(file, exc_type, exc_value, exc_traceback); + + /* Call file.flush() */ + PyObject *res = _PyObject_CallMethodIdNoArgs(file, &PyId_flush); + if (!res) { + return -1; + } + Py_DECREF(res); + + return 0; +} + + +PyDoc_STRVAR(ExceptHookArgs__doc__, +"ExceptHookArgs\n\ +\n\ +Type used to pass arguments to threading.excepthook."); + +static PyTypeObject ExceptHookArgsType; + +static PyStructSequence_Field ExceptHookArgs_fields[] = { + {"exc_type", "Exception type"}, + {"exc_value", "Exception value"}, + {"exc_traceback", "Exception traceback"}, + {"thread", "Thread"}, + {0} +}; + +static PyStructSequence_Desc ExceptHookArgs_desc = { + .name = "_thread.ExceptHookArgs", + .doc = ExceptHookArgs__doc__, + .fields = ExceptHookArgs_fields, + .n_in_sequence = 4 +}; + + +static PyObject * +thread_excepthook(PyObject *self, PyObject *args) +{ + if (!Py_IS_TYPE(args, &ExceptHookArgsType)) { + PyErr_SetString(PyExc_TypeError, + "_thread.excepthook argument type " + "must be ExceptHookArgs"); + return NULL; + } + + /* Borrowed reference */ + PyObject *exc_type = PyStructSequence_GET_ITEM(args, 0); + if (exc_type == PyExc_SystemExit) { + /* silently ignore SystemExit */ + Py_RETURN_NONE; + } + + /* Borrowed references */ + PyObject *exc_value = PyStructSequence_GET_ITEM(args, 1); + PyObject *exc_tb = PyStructSequence_GET_ITEM(args, 2); + PyObject *thread = PyStructSequence_GET_ITEM(args, 3); + + PyObject *file = _PySys_GetObjectId(&PyId_stderr); + if (file == NULL || file == Py_None) { + if (thread == Py_None) { + /* do nothing if sys.stderr is None and thread is None */ + Py_RETURN_NONE; + } + + file = PyObject_GetAttrString(thread, "_stderr"); + if (file == NULL) { + return NULL; + } + if (file == Py_None) { + Py_DECREF(file); + /* do nothing if sys.stderr is None and sys.stderr was None + when the thread was created */ + Py_RETURN_NONE; + } + } + else { + Py_INCREF(file); + } + + int res = thread_excepthook_file(file, exc_type, exc_value, exc_tb, + thread); + Py_DECREF(file); + if (res < 0) { + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(excepthook_doc, +"excepthook(exc_type, exc_value, exc_traceback, thread)\n\ +\n\ +Handle uncaught Thread.run() exception."); + static PyMethodDef thread_methods[] = { {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread, METH_VARARGS, start_new_doc}, {"start_new", (PyCFunction)thread_PyThread_start_new_thread, METH_VARARGS, start_new_doc}, - {"allocate_lock", thread_PyThread_allocate_lock, + {"allocate_lock", thread_PyThread_allocate_lock, METH_NOARGS, allocate_doc}, - {"allocate", thread_PyThread_allocate_lock, + {"allocate", thread_PyThread_allocate_lock, METH_NOARGS, allocate_doc}, - {"exit_thread", thread_PyThread_exit_thread, + {"exit_thread", thread_PyThread_exit_thread, METH_NOARGS, exit_doc}, - {"exit", thread_PyThread_exit_thread, + {"exit", thread_PyThread_exit_thread, METH_NOARGS, exit_doc}, - {"interrupt_main", thread_PyThread_interrupt_main, + {"interrupt_main", thread_PyThread_interrupt_main, METH_NOARGS, interrupt_doc}, - {"get_ident", thread_get_ident, + {"get_ident", thread_get_ident, METH_NOARGS, get_ident_doc}, -#ifdef PY_HAVE_THREAD_NATIVE_ID - {"get_native_id", thread_get_native_id, - METH_NOARGS, get_native_id_doc}, -#endif - {"_count", thread__count, +#ifdef PY_HAVE_THREAD_NATIVE_ID + {"get_native_id", thread_get_native_id, + METH_NOARGS, get_native_id_doc}, +#endif + {"_count", thread__count, METH_NOARGS, _count_doc}, {"stack_size", (PyCFunction)thread_stack_size, METH_VARARGS, stack_size_doc}, - {"_set_sentinel", thread__set_sentinel, + {"_set_sentinel", thread__set_sentinel, METH_NOARGS, _set_sentinel_doc}, - {"_excepthook", thread_excepthook, - METH_O, excepthook_doc}, + {"_excepthook", thread_excepthook, + METH_O, excepthook_doc}, {NULL, NULL} /* sentinel */ }; @@ -1564,7 +1564,7 @@ PyInit__thread(void) PyObject *m, *d, *v; double time_max; double timeout_max; - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = _PyInterpreterState_GET(); /* Initialize types: */ if (PyType_Ready(&localdummytype) < 0) @@ -1575,12 +1575,12 @@ PyInit__thread(void) return NULL; if (PyType_Ready(&RLocktype) < 0) return NULL; - if (ExceptHookArgsType.tp_name == NULL) { - if (PyStructSequence_InitType2(&ExceptHookArgsType, - &ExceptHookArgs_desc) < 0) { - return NULL; - } - } + if (ExceptHookArgsType.tp_name == NULL) { + if (PyStructSequence_InitType2(&ExceptHookArgsType, + &ExceptHookArgs_desc) < 0) { + return NULL; + } + } /* Create the module and add the functions */ m = PyModule_Create(&threadmodule); @@ -1617,13 +1617,13 @@ PyInit__thread(void) if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) return NULL; - Py_INCREF(&ExceptHookArgsType); - if (PyModule_AddObject(m, "_ExceptHookArgs", - (PyObject *)&ExceptHookArgsType) < 0) - return NULL; - - interp->num_threads = 0; + Py_INCREF(&ExceptHookArgsType); + if (PyModule_AddObject(m, "_ExceptHookArgs", + (PyObject *)&ExceptHookArgsType) < 0) + return NULL; + interp->num_threads = 0; + str_dict = PyUnicode_InternFromString("__dict__"); if (str_dict == NULL) return NULL; |