Skip to content

Commit ada98d0

Browse files
committed
Add a trace helper to log the thread interactions before deadlocks.
1 parent a594741 commit ada98d0

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

src/lxml/tests/_testlock.pyx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,46 @@ cdef class _RWLock:
7777
self._lock.unlock_write()
7878
else:
7979
self._lock.unlock_write_with(second_lock._lock)
80+
81+
82+
def trace(test_function):
83+
"""Compiled test trace helper.
84+
"""
85+
import sys
86+
from functools import partial, wraps
87+
from threading import get_ident as get_thread_id
88+
89+
_print = sys.stdout.write
90+
sysmon = sys.monitoring
91+
tool_id = sysmon.DEBUGGER_ID
92+
93+
print_lock: cython.pymutex
94+
95+
test_function_startline = test_function.__code__.co_firstlineno
96+
97+
def trace_event(event, code, instruction_offset, *arg):
98+
filename: str = code.co_filename
99+
if 'test_' in filename and code.co_firstlineno < test_function_startline:
100+
return sysmon.DISABLE
101+
if 'lock' not in filename and 'etree' not in filename:
102+
return sysmon.DISABLE
103+
104+
message = f"[{get_thread_id() & 0xffffffff:08x}] {event:6} {code.co_name}\n"
105+
with print_lock:
106+
_print(message)
107+
108+
@wraps(test_function)
109+
def method(*args):
110+
sysmon.use_tool_id(tool_id, "tracer")
111+
sysmon.set_events(tool_id, sysmon.events.PY_START | sysmon.events.PY_RETURN)
112+
113+
sysmon.register_callback(
114+
tool_id, sysmon.events.PY_START, partial(trace_event, 'call'))
115+
sysmon.register_callback(
116+
tool_id, sysmon.events.PY_RETURN, partial(trace_event, 'return'))
117+
118+
test_function(*args)
119+
120+
sysmon.clear_tool_id(tool_id)
121+
122+
return method

src/lxml/tests/test_rwlock.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from contextlib import contextmanager
55
from functools import partial, wraps
66

7-
from lxml.tests._testlock import _RWLock as RWLock
7+
from lxml.tests._testlock import _RWLock as RWLock, trace
88

99

1010
def diff_perf_counters(start_counters, end_counters):

0 commit comments

Comments
 (0)