Skip to content

Commit 313145e

Browse files
authored
gh-125434: Display thread name in faulthandler on Windows (#140675)
1 parent 1753ccb commit 313145e

File tree

4 files changed

+80
-14
lines changed

4 files changed

+80
-14
lines changed

Include/internal/pycore_traceback.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ extern int _Py_WriteIndent(int, PyObject *);
103103
PyAPI_FUNC(void) _Py_InitDumpStack(void);
104104
PyAPI_FUNC(void) _Py_DumpStack(int fd);
105105

106+
extern void _Py_DumpTraceback_Init(void);
107+
106108
#ifdef __cplusplus
107109
}
108110
#endif
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Display thread name in :mod:`faulthandler` on Windows. Patch by Victor
2+
Stinner.

Python/pylifecycle.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ pycore_init_runtime(_PyRuntimeState *runtime,
506506
_PyRuntimeState_SetFinalizing(runtime, NULL);
507507

508508
_Py_InitVersion();
509+
_Py_DumpTraceback_Init();
509510

510511
status = _Py_HashRandomization_Init(config);
511512
if (_PyStatus_EXCEPTION(status)) {

Python/traceback.c

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ class traceback "PyTracebackObject *" "&PyTraceback_Type"
6969

7070
#include "clinic/traceback.c.h"
7171

72+
73+
#ifdef MS_WINDOWS
74+
typedef HRESULT (WINAPI *PF_GET_THREAD_DESCRIPTION)(HANDLE, PCWSTR*);
75+
static PF_GET_THREAD_DESCRIPTION pGetThreadDescription = NULL;
76+
#endif
77+
78+
7279
static PyObject *
7380
tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti,
7481
int lineno)
@@ -1107,23 +1114,12 @@ _Py_DumpTraceback(int fd, PyThreadState *tstate)
11071114
# endif
11081115
#endif
11091116

1110-
/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
1111-
is_current is true, "Thread 0xHHHH:\n" otherwise.
1112-
1113-
This function is signal safe. */
11141117

1118+
// Write the thread name
11151119
static void
1116-
write_thread_id(int fd, PyThreadState *tstate, int is_current)
1120+
write_thread_name(int fd, PyThreadState *tstate)
11171121
{
1118-
if (is_current)
1119-
PUTS(fd, "Current thread 0x");
1120-
else
1121-
PUTS(fd, "Thread 0x");
1122-
_Py_DumpHexadecimal(fd,
1123-
tstate->thread_id,
1124-
sizeof(unsigned long) * 2);
1125-
1126-
// Write the thread name
1122+
#ifndef MS_WINDOWS
11271123
#if defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP)
11281124
char name[100];
11291125
pthread_t thread = (pthread_t)tstate->thread_id;
@@ -1142,6 +1138,54 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current)
11421138
}
11431139
}
11441140
#endif
1141+
#else
1142+
// Windows implementation
1143+
if (pGetThreadDescription == NULL) {
1144+
return;
1145+
}
1146+
1147+
HANDLE thread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, tstate->thread_id);
1148+
if (thread == NULL) {
1149+
return;
1150+
}
1151+
1152+
wchar_t *wname;
1153+
HRESULT hr = pGetThreadDescription(thread, &wname);
1154+
if (!FAILED(hr)) {
1155+
char *name = _Py_EncodeLocaleRaw(wname, NULL);
1156+
if (name != NULL) {
1157+
size_t len = strlen(name);
1158+
if (len) {
1159+
PUTS(fd, " [");
1160+
(void)_Py_write_noraise(fd, name, len);
1161+
PUTS(fd, "]");
1162+
}
1163+
PyMem_RawFree(name);
1164+
}
1165+
LocalFree(wname);
1166+
}
1167+
CloseHandle(thread);
1168+
#endif
1169+
}
1170+
1171+
1172+
/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
1173+
is_current is true, "Thread 0xHHHH:\n" otherwise.
1174+
1175+
This function is signal safe (except on Windows). */
1176+
1177+
static void
1178+
write_thread_id(int fd, PyThreadState *tstate, int is_current)
1179+
{
1180+
if (is_current)
1181+
PUTS(fd, "Current thread 0x");
1182+
else
1183+
PUTS(fd, "Thread 0x");
1184+
_Py_DumpHexadecimal(fd,
1185+
tstate->thread_id,
1186+
sizeof(unsigned long) * 2);
1187+
1188+
write_thread_name(fd, tstate);
11451189

11461190
PUTS(fd, " (most recent call first):\n");
11471191
}
@@ -1336,3 +1380,20 @@ _Py_InitDumpStack(void)
13361380
(void)backtrace(callstack, 1);
13371381
#endif
13381382
}
1383+
1384+
1385+
void
1386+
_Py_DumpTraceback_Init(void)
1387+
{
1388+
#ifdef MS_WINDOWS
1389+
if (pGetThreadDescription != NULL) {
1390+
return;
1391+
}
1392+
1393+
HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll");
1394+
if (kernelbase != NULL) {
1395+
pGetThreadDescription = (PF_GET_THREAD_DESCRIPTION)GetProcAddress(
1396+
kernelbase, "GetThreadDescription");
1397+
}
1398+
#endif
1399+
}

0 commit comments

Comments
 (0)