mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
[3.14] gh-125434: Display thread name in faulthandler on Windows (#142011)
* gh-125434: Display thread name in faulthandler on Windows (#140675) (cherry picked from commit313145eab5) * gh-125434: Fix non-ASCII thread names in faulthandler on Windows (#140700) Add _Py_DumpWideString() function to dump a wide string as ASCII. It supports surrogate pairs. Replace _Py_EncodeLocaleRaw() with _Py_DumpWideString() in write_thread_name(). (cherry picked from commit80f20f58b2)
This commit is contained in:
parent
f47e928574
commit
ad60d8963e
4 changed files with 121 additions and 14 deletions
|
|
@ -103,6 +103,8 @@ extern int _Py_WriteIndent(int, PyObject *);
|
||||||
PyAPI_FUNC(void) _Py_InitDumpStack(void);
|
PyAPI_FUNC(void) _Py_InitDumpStack(void);
|
||||||
PyAPI_FUNC(void) _Py_DumpStack(int fd);
|
PyAPI_FUNC(void) _Py_DumpStack(int fd);
|
||||||
|
|
||||||
|
extern void _Py_DumpTraceback_Init(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
Display thread name in :mod:`faulthandler` on Windows. Patch by Victor
|
||||||
|
Stinner.
|
||||||
|
|
@ -503,6 +503,7 @@ pycore_init_runtime(_PyRuntimeState *runtime,
|
||||||
_PyRuntimeState_SetFinalizing(runtime, NULL);
|
_PyRuntimeState_SetFinalizing(runtime, NULL);
|
||||||
|
|
||||||
_Py_InitVersion();
|
_Py_InitVersion();
|
||||||
|
_Py_DumpTraceback_Init();
|
||||||
|
|
||||||
status = _Py_HashRandomization_Init(config);
|
status = _Py_HashRandomization_Init(config);
|
||||||
if (_PyStatus_EXCEPTION(status)) {
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,13 @@ class traceback "PyTracebackObject *" "&PyTraceback_Type"
|
||||||
|
|
||||||
#include "clinic/traceback.c.h"
|
#include "clinic/traceback.c.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
typedef HRESULT (WINAPI *PF_GET_THREAD_DESCRIPTION)(HANDLE, PCWSTR*);
|
||||||
|
static PF_GET_THREAD_DESCRIPTION pGetThreadDescription = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti,
|
tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti,
|
||||||
int lineno)
|
int lineno)
|
||||||
|
|
@ -974,6 +981,52 @@ _Py_DumpASCII(int fd, PyObject *text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
static void
|
||||||
|
_Py_DumpWideString(int fd, wchar_t *str)
|
||||||
|
{
|
||||||
|
Py_ssize_t size = wcslen(str);
|
||||||
|
int truncated;
|
||||||
|
if (MAX_STRING_LENGTH < size) {
|
||||||
|
size = MAX_STRING_LENGTH;
|
||||||
|
truncated = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
truncated = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Py_ssize_t i=0; i < size; i++) {
|
||||||
|
Py_UCS4 ch = str[i];
|
||||||
|
if (' ' <= ch && ch <= 126) {
|
||||||
|
/* printable ASCII character */
|
||||||
|
dump_char(fd, (char)ch);
|
||||||
|
}
|
||||||
|
else if (ch <= 0xff) {
|
||||||
|
PUTS(fd, "\\x");
|
||||||
|
_Py_DumpHexadecimal(fd, ch, 2);
|
||||||
|
}
|
||||||
|
else if (Py_UNICODE_IS_HIGH_SURROGATE(ch)
|
||||||
|
&& Py_UNICODE_IS_LOW_SURROGATE(str[i+1])) {
|
||||||
|
ch = Py_UNICODE_JOIN_SURROGATES(ch, str[i+1]);
|
||||||
|
i++; // Skip the low surrogate character
|
||||||
|
PUTS(fd, "\\U");
|
||||||
|
_Py_DumpHexadecimal(fd, ch, 8);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Py_BUILD_ASSERT(sizeof(wchar_t) == 2);
|
||||||
|
PUTS(fd, "\\u");
|
||||||
|
_Py_DumpHexadecimal(fd, ch, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (truncated) {
|
||||||
|
PUTS(fd, "...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Write a frame into the file fd: "File "xxx", line xxx in xxx".
|
/* Write a frame into the file fd: "File "xxx", line xxx in xxx".
|
||||||
|
|
||||||
This function is signal safe.
|
This function is signal safe.
|
||||||
|
|
@ -1122,23 +1175,12 @@ _Py_DumpTraceback(int fd, PyThreadState *tstate)
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
|
|
||||||
is_current is true, "Thread 0xHHHH:\n" otherwise.
|
|
||||||
|
|
||||||
This function is signal safe. */
|
|
||||||
|
|
||||||
|
// Write the thread name
|
||||||
static void
|
static void
|
||||||
write_thread_id(int fd, PyThreadState *tstate, int is_current)
|
write_thread_name(int fd, PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
if (is_current)
|
#ifndef MS_WINDOWS
|
||||||
PUTS(fd, "Current thread 0x");
|
|
||||||
else
|
|
||||||
PUTS(fd, "Thread 0x");
|
|
||||||
_Py_DumpHexadecimal(fd,
|
|
||||||
tstate->thread_id,
|
|
||||||
sizeof(unsigned long) * 2);
|
|
||||||
|
|
||||||
// Write the thread name
|
|
||||||
#if defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP)
|
#if defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP)
|
||||||
char name[100];
|
char name[100];
|
||||||
pthread_t thread = (pthread_t)tstate->thread_id;
|
pthread_t thread = (pthread_t)tstate->thread_id;
|
||||||
|
|
@ -1157,6 +1199,49 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
// Windows implementation
|
||||||
|
if (pGetThreadDescription == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE thread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, tstate->thread_id);
|
||||||
|
if (thread == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *name;
|
||||||
|
HRESULT hr = pGetThreadDescription(thread, &name);
|
||||||
|
if (!FAILED(hr)) {
|
||||||
|
if (name[0] != 0) {
|
||||||
|
PUTS(fd, " [");
|
||||||
|
_Py_DumpWideString(fd, name);
|
||||||
|
PUTS(fd, "]");
|
||||||
|
}
|
||||||
|
LocalFree(name);
|
||||||
|
}
|
||||||
|
CloseHandle(thread);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
|
||||||
|
is_current is true, "Thread 0xHHHH:\n" otherwise.
|
||||||
|
|
||||||
|
This function is signal safe (except on Windows). */
|
||||||
|
|
||||||
|
static void
|
||||||
|
write_thread_id(int fd, PyThreadState *tstate, int is_current)
|
||||||
|
{
|
||||||
|
if (is_current)
|
||||||
|
PUTS(fd, "Current thread 0x");
|
||||||
|
else
|
||||||
|
PUTS(fd, "Thread 0x");
|
||||||
|
_Py_DumpHexadecimal(fd,
|
||||||
|
tstate->thread_id,
|
||||||
|
sizeof(unsigned long) * 2);
|
||||||
|
|
||||||
|
write_thread_name(fd, tstate);
|
||||||
|
|
||||||
PUTS(fd, " (most recent call first):\n");
|
PUTS(fd, " (most recent call first):\n");
|
||||||
}
|
}
|
||||||
|
|
@ -1351,3 +1436,20 @@ _Py_InitDumpStack(void)
|
||||||
(void)backtrace(callstack, 1);
|
(void)backtrace(callstack, 1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
_Py_DumpTraceback_Init(void)
|
||||||
|
{
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
if (pGetThreadDescription != NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll");
|
||||||
|
if (kernelbase != NULL) {
|
||||||
|
pGetThreadDescription = (PF_GET_THREAD_DESCRIPTION)GetProcAddress(
|
||||||
|
kernelbase, "GetThreadDescription");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue