Skip to content

Commit f36da66

Browse files
[3.14] gh-148037: remove critical section from PyCode_Addr2Line (GH… (#148353)
[3.14] gh-148037: remove critical section from `PyCode_Addr2Line` (GH-148103) (cherry picked from commit d3b7b93)
1 parent 288cbac commit f36da66

File tree

5 files changed

+33
-42
lines changed

5 files changed

+33
-42
lines changed

Include/internal/pycore_instruments.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,6 @@ extern void
6262
_Py_call_instrumentation_exc2(PyThreadState *tstate, int event,
6363
_PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1);
6464

65-
extern int
66-
_Py_Instrumentation_GetLine(PyCodeObject *code, int index);
67-
6865
extern PyObject _PyInstrumentation_MISSING;
6966
extern PyObject _PyInstrumentation_DISABLE;
7067

@@ -120,6 +117,8 @@ typedef struct _PyCoMonitoringData {
120117
uint8_t *per_instruction_tools;
121118
} _PyCoMonitoringData;
122119

120+
extern int
121+
_Py_Instrumentation_GetLine(PyCodeObject *code, _PyCoLineInstrumentationData *line_data, int index);
123122

124123
#ifdef __cplusplus
125124
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove critical section from :c:func:`!PyCode_Addr2Line` in free-threading.

Objects/codeobject.c

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,14 +1013,18 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
10131013
* source location tracking (co_lines/co_positions)
10141014
******************/
10151015

1016-
static int
1017-
_PyCode_Addr2Line(PyCodeObject *co, int addrq)
1016+
int
1017+
PyCode_Addr2Line(PyCodeObject *co, int addrq)
10181018
{
10191019
if (addrq < 0) {
10201020
return co->co_firstlineno;
10211021
}
1022-
if (co->_co_monitoring && co->_co_monitoring->lines) {
1023-
return _Py_Instrumentation_GetLine(co, addrq/sizeof(_Py_CODEUNIT));
1022+
_PyCoMonitoringData *data = _Py_atomic_load_ptr_acquire(&co->_co_monitoring);
1023+
if (data) {
1024+
_PyCoLineInstrumentationData *lines = _Py_atomic_load_ptr_acquire(&data->lines);
1025+
if (lines) {
1026+
return _Py_Instrumentation_GetLine(co, lines, addrq/sizeof(_Py_CODEUNIT));
1027+
}
10241028
}
10251029
assert(addrq >= 0 && addrq < _PyCode_NBYTES(co));
10261030
PyCodeAddressRange bounds;
@@ -1035,7 +1039,7 @@ _PyCode_SafeAddr2Line(PyCodeObject *co, int addrq)
10351039
return co->co_firstlineno;
10361040
}
10371041
if (co->_co_monitoring && co->_co_monitoring->lines) {
1038-
return _Py_Instrumentation_GetLine(co, addrq/sizeof(_Py_CODEUNIT));
1042+
return _Py_Instrumentation_GetLine(co, co->_co_monitoring->lines, addrq/sizeof(_Py_CODEUNIT));
10391043
}
10401044
if (!(addrq >= 0 && addrq < _PyCode_NBYTES(co))) {
10411045
return -1;
@@ -1045,16 +1049,6 @@ _PyCode_SafeAddr2Line(PyCodeObject *co, int addrq)
10451049
return _PyCode_CheckLineNumber(addrq, &bounds);
10461050
}
10471051

1048-
int
1049-
PyCode_Addr2Line(PyCodeObject *co, int addrq)
1050-
{
1051-
int lineno;
1052-
Py_BEGIN_CRITICAL_SECTION(co);
1053-
lineno = _PyCode_Addr2Line(co, addrq);
1054-
Py_END_CRITICAL_SECTION();
1055-
return lineno;
1056-
}
1057-
10581052
void
10591053
_PyLineTable_InitAddressRange(const char *linetable, Py_ssize_t length, int firstlineno, PyCodeAddressRange *range)
10601054
{

Python/instrumentation.c

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,13 +1285,10 @@ _Py_call_instrumentation_exc2(
12851285
}
12861286

12871287
int
1288-
_Py_Instrumentation_GetLine(PyCodeObject *code, int index)
1288+
_Py_Instrumentation_GetLine(PyCodeObject *code, _PyCoLineInstrumentationData *line_data, int index)
12891289
{
1290-
_PyCoMonitoringData *monitoring = code->_co_monitoring;
1291-
assert(monitoring != NULL);
1292-
assert(monitoring->lines != NULL);
1290+
assert(line_data != NULL);
12931291
assert(index < Py_SIZE(code));
1294-
_PyCoLineInstrumentationData *line_data = monitoring->lines;
12951292
int line_delta = get_line_delta(line_data, index);
12961293
int line = compute_line(code, line_delta);
12971294
return line;
@@ -1309,11 +1306,11 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
13091306
_PyCoMonitoringData *monitoring = code->_co_monitoring;
13101307
_PyCoLineInstrumentationData *line_data = monitoring->lines;
13111308
PyInterpreterState *interp = tstate->interp;
1312-
int line = _Py_Instrumentation_GetLine(code, i);
1309+
int line = _Py_Instrumentation_GetLine(code, line_data, i);
13131310
assert(line >= 0);
13141311
assert(prev != NULL);
13151312
int prev_index = (int)(prev - bytecode);
1316-
int prev_line = _Py_Instrumentation_GetLine(code, prev_index);
1313+
int prev_line = _Py_Instrumentation_GetLine(code, line_data, prev_index);
13171314
if (prev_line == line) {
13181315
int prev_opcode = bytecode[prev_index].op.code;
13191316
/* RESUME and INSTRUMENTED_RESUME are needed for the operation of
@@ -1510,11 +1507,9 @@ initialize_tools(PyCodeObject *code)
15101507
}
15111508

15121509
static void
1513-
initialize_lines(PyCodeObject *code, int bytes_per_entry)
1510+
initialize_lines(_PyCoLineInstrumentationData *line_data, PyCodeObject *code, int bytes_per_entry)
15141511
{
15151512
ASSERT_WORLD_STOPPED_OR_LOCKED(code);
1516-
_PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines;
1517-
15181513
assert(line_data != NULL);
15191514
line_data->bytes_per_entry = bytes_per_entry;
15201515
int code_len = (int)Py_SIZE(code);
@@ -1655,18 +1650,19 @@ allocate_instrumentation_data(PyCodeObject *code)
16551650
ASSERT_WORLD_STOPPED_OR_LOCKED(code);
16561651

16571652
if (code->_co_monitoring == NULL) {
1658-
code->_co_monitoring = PyMem_Malloc(sizeof(_PyCoMonitoringData));
1659-
if (code->_co_monitoring == NULL) {
1653+
_PyCoMonitoringData *monitoring = PyMem_Malloc(sizeof(_PyCoMonitoringData));
1654+
if (monitoring == NULL) {
16601655
PyErr_NoMemory();
16611656
return -1;
16621657
}
1663-
code->_co_monitoring->local_monitors = (_Py_LocalMonitors){ 0 };
1664-
code->_co_monitoring->active_monitors = (_Py_LocalMonitors){ 0 };
1665-
code->_co_monitoring->tools = NULL;
1666-
code->_co_monitoring->lines = NULL;
1667-
code->_co_monitoring->line_tools = NULL;
1668-
code->_co_monitoring->per_instruction_opcodes = NULL;
1669-
code->_co_monitoring->per_instruction_tools = NULL;
1658+
monitoring->local_monitors = (_Py_LocalMonitors){ 0 };
1659+
monitoring->active_monitors = (_Py_LocalMonitors){ 0 };
1660+
monitoring->tools = NULL;
1661+
monitoring->lines = NULL;
1662+
monitoring->line_tools = NULL;
1663+
monitoring->per_instruction_opcodes = NULL;
1664+
monitoring->per_instruction_tools = NULL;
1665+
_Py_atomic_store_ptr_release(&code->_co_monitoring, monitoring);
16701666
}
16711667
return 0;
16721668
}
@@ -1731,12 +1727,13 @@ update_instrumentation_data(PyCodeObject *code, PyInterpreterState *interp)
17311727
else {
17321728
bytes_per_entry = 5;
17331729
}
1734-
code->_co_monitoring->lines = PyMem_Malloc(1 + code_len * bytes_per_entry);
1735-
if (code->_co_monitoring->lines == NULL) {
1730+
_PyCoLineInstrumentationData *lines = PyMem_Malloc(1 + code_len * bytes_per_entry);
1731+
if (lines == NULL) {
17361732
PyErr_NoMemory();
17371733
return -1;
17381734
}
1739-
initialize_lines(code, bytes_per_entry);
1735+
initialize_lines(lines, code, bytes_per_entry);
1736+
_Py_atomic_store_ptr_release(&code->_co_monitoring->lines, lines);
17401737
}
17411738
if (multitools && code->_co_monitoring->line_tools == NULL) {
17421739
code->_co_monitoring->line_tools = PyMem_Malloc(code_len);

Python/legacy_tracing.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,8 @@ sys_trace_jump_func(
398398
assert(PyCode_Check(code));
399399
/* We can call _Py_Instrumentation_GetLine because we always set
400400
* line events for tracing */
401-
int to_line = _Py_Instrumentation_GetLine(code, to);
402-
int from_line = _Py_Instrumentation_GetLine(code, from);
401+
int to_line = _Py_Instrumentation_GetLine(code, code->_co_monitoring->lines, to);
402+
int from_line = _Py_Instrumentation_GetLine(code, code->_co_monitoring->lines, from);
403403
if (to_line != from_line) {
404404
/* Will be handled by target INSTRUMENTED_LINE */
405405
return &_PyInstrumentation_DISABLE;

0 commit comments

Comments
 (0)