https://github.com/python/cpython/commit/f36da66c716e892aacdf9453325ff05b89fe7e70
commit: f36da66c716e892aacdf9453325ff05b89fe7e70
branch: 3.14
author: Kumar Aditya <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-04-10T23:59:38+05:30
summary:
[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 d3b7b93cbbbf53061a95eb60cc116c9fec31c5b4)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-04-09-14-18-33.gh-issue-148037.aP3CSX.rst
M Include/internal/pycore_instruments.h
M Objects/codeobject.c
M Python/instrumentation.c
M Python/legacy_tracing.c
diff --git a/Include/internal/pycore_instruments.h
b/Include/internal/pycore_instruments.h
index 7658adca719e86..98684ff1024f6e 100644
--- a/Include/internal/pycore_instruments.h
+++ b/Include/internal/pycore_instruments.h
@@ -62,9 +62,6 @@ extern void
_Py_call_instrumentation_exc2(PyThreadState *tstate, int event,
_PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject
*arg1);
-extern int
-_Py_Instrumentation_GetLine(PyCodeObject *code, int index);
-
extern PyObject _PyInstrumentation_MISSING;
extern PyObject _PyInstrumentation_DISABLE;
@@ -120,6 +117,8 @@ typedef struct _PyCoMonitoringData {
uint8_t *per_instruction_tools;
} _PyCoMonitoringData;
+extern int
+_Py_Instrumentation_GetLine(PyCodeObject *code, _PyCoLineInstrumentationData
*line_data, int index);
#ifdef __cplusplus
}
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-09-14-18-33.gh-issue-148037.aP3CSX.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-09-14-18-33.gh-issue-148037.aP3CSX.rst
new file mode 100644
index 00000000000000..b0cef595129817
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-09-14-18-33.gh-issue-148037.aP3CSX.rst
@@ -0,0 +1 @@
+Remove critical section from :c:func:`!PyCode_Addr2Line` in free-threading.
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index f0b2e5f36c6060..acaa9f5501af12 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -1013,14 +1013,18 @@ PyCode_NewEmpty(const char *filename, const char
*funcname, int firstlineno)
* source location tracking (co_lines/co_positions)
******************/
-static int
-_PyCode_Addr2Line(PyCodeObject *co, int addrq)
+int
+PyCode_Addr2Line(PyCodeObject *co, int addrq)
{
if (addrq < 0) {
return co->co_firstlineno;
}
- if (co->_co_monitoring && co->_co_monitoring->lines) {
- return _Py_Instrumentation_GetLine(co, addrq/sizeof(_Py_CODEUNIT));
+ _PyCoMonitoringData *data =
_Py_atomic_load_ptr_acquire(&co->_co_monitoring);
+ if (data) {
+ _PyCoLineInstrumentationData *lines =
_Py_atomic_load_ptr_acquire(&data->lines);
+ if (lines) {
+ return _Py_Instrumentation_GetLine(co, lines,
addrq/sizeof(_Py_CODEUNIT));
+ }
}
assert(addrq >= 0 && addrq < _PyCode_NBYTES(co));
PyCodeAddressRange bounds;
@@ -1035,7 +1039,7 @@ _PyCode_SafeAddr2Line(PyCodeObject *co, int addrq)
return co->co_firstlineno;
}
if (co->_co_monitoring && co->_co_monitoring->lines) {
- return _Py_Instrumentation_GetLine(co, addrq/sizeof(_Py_CODEUNIT));
+ return _Py_Instrumentation_GetLine(co, co->_co_monitoring->lines,
addrq/sizeof(_Py_CODEUNIT));
}
if (!(addrq >= 0 && addrq < _PyCode_NBYTES(co))) {
return -1;
@@ -1045,16 +1049,6 @@ _PyCode_SafeAddr2Line(PyCodeObject *co, int addrq)
return _PyCode_CheckLineNumber(addrq, &bounds);
}
-int
-PyCode_Addr2Line(PyCodeObject *co, int addrq)
-{
- int lineno;
- Py_BEGIN_CRITICAL_SECTION(co);
- lineno = _PyCode_Addr2Line(co, addrq);
- Py_END_CRITICAL_SECTION();
- return lineno;
-}
-
void
_PyLineTable_InitAddressRange(const char *linetable, Py_ssize_t length, int
firstlineno, PyCodeAddressRange *range)
{
diff --git a/Python/instrumentation.c b/Python/instrumentation.c
index 32d6a204182892..d06cda7c589c74 100644
--- a/Python/instrumentation.c
+++ b/Python/instrumentation.c
@@ -1285,13 +1285,10 @@ _Py_call_instrumentation_exc2(
}
int
-_Py_Instrumentation_GetLine(PyCodeObject *code, int index)
+_Py_Instrumentation_GetLine(PyCodeObject *code, _PyCoLineInstrumentationData
*line_data, int index)
{
- _PyCoMonitoringData *monitoring = code->_co_monitoring;
- assert(monitoring != NULL);
- assert(monitoring->lines != NULL);
+ assert(line_data != NULL);
assert(index < Py_SIZE(code));
- _PyCoLineInstrumentationData *line_data = monitoring->lines;
int line_delta = get_line_delta(line_data, index);
int line = compute_line(code, line_delta);
return line;
@@ -1309,11 +1306,11 @@ _Py_call_instrumentation_line(PyThreadState *tstate,
_PyInterpreterFrame* frame,
_PyCoMonitoringData *monitoring = code->_co_monitoring;
_PyCoLineInstrumentationData *line_data = monitoring->lines;
PyInterpreterState *interp = tstate->interp;
- int line = _Py_Instrumentation_GetLine(code, i);
+ int line = _Py_Instrumentation_GetLine(code, line_data, i);
assert(line >= 0);
assert(prev != NULL);
int prev_index = (int)(prev - bytecode);
- int prev_line = _Py_Instrumentation_GetLine(code, prev_index);
+ int prev_line = _Py_Instrumentation_GetLine(code, line_data, prev_index);
if (prev_line == line) {
int prev_opcode = bytecode[prev_index].op.code;
/* RESUME and INSTRUMENTED_RESUME are needed for the operation of
@@ -1510,11 +1507,9 @@ initialize_tools(PyCodeObject *code)
}
static void
-initialize_lines(PyCodeObject *code, int bytes_per_entry)
+initialize_lines(_PyCoLineInstrumentationData *line_data, PyCodeObject *code,
int bytes_per_entry)
{
ASSERT_WORLD_STOPPED_OR_LOCKED(code);
- _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines;
-
assert(line_data != NULL);
line_data->bytes_per_entry = bytes_per_entry;
int code_len = (int)Py_SIZE(code);
@@ -1655,18 +1650,19 @@ allocate_instrumentation_data(PyCodeObject *code)
ASSERT_WORLD_STOPPED_OR_LOCKED(code);
if (code->_co_monitoring == NULL) {
- code->_co_monitoring = PyMem_Malloc(sizeof(_PyCoMonitoringData));
- if (code->_co_monitoring == NULL) {
+ _PyCoMonitoringData *monitoring =
PyMem_Malloc(sizeof(_PyCoMonitoringData));
+ if (monitoring == NULL) {
PyErr_NoMemory();
return -1;
}
- code->_co_monitoring->local_monitors = (_Py_LocalMonitors){ 0 };
- code->_co_monitoring->active_monitors = (_Py_LocalMonitors){ 0 };
- code->_co_monitoring->tools = NULL;
- code->_co_monitoring->lines = NULL;
- code->_co_monitoring->line_tools = NULL;
- code->_co_monitoring->per_instruction_opcodes = NULL;
- code->_co_monitoring->per_instruction_tools = NULL;
+ monitoring->local_monitors = (_Py_LocalMonitors){ 0 };
+ monitoring->active_monitors = (_Py_LocalMonitors){ 0 };
+ monitoring->tools = NULL;
+ monitoring->lines = NULL;
+ monitoring->line_tools = NULL;
+ monitoring->per_instruction_opcodes = NULL;
+ monitoring->per_instruction_tools = NULL;
+ _Py_atomic_store_ptr_release(&code->_co_monitoring, monitoring);
}
return 0;
}
@@ -1731,12 +1727,13 @@ update_instrumentation_data(PyCodeObject *code,
PyInterpreterState *interp)
else {
bytes_per_entry = 5;
}
- code->_co_monitoring->lines = PyMem_Malloc(1 + code_len *
bytes_per_entry);
- if (code->_co_monitoring->lines == NULL) {
+ _PyCoLineInstrumentationData *lines = PyMem_Malloc(1 + code_len *
bytes_per_entry);
+ if (lines == NULL) {
PyErr_NoMemory();
return -1;
}
- initialize_lines(code, bytes_per_entry);
+ initialize_lines(lines, code, bytes_per_entry);
+ _Py_atomic_store_ptr_release(&code->_co_monitoring->lines, lines);
}
if (multitools && code->_co_monitoring->line_tools == NULL) {
code->_co_monitoring->line_tools = PyMem_Malloc(code_len);
diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c
index 9c72fab298201e..2e29e1aa208ac0 100644
--- a/Python/legacy_tracing.c
+++ b/Python/legacy_tracing.c
@@ -398,8 +398,8 @@ sys_trace_jump_func(
assert(PyCode_Check(code));
/* We can call _Py_Instrumentation_GetLine because we always set
* line events for tracing */
- int to_line = _Py_Instrumentation_GetLine(code, to);
- int from_line = _Py_Instrumentation_GetLine(code, from);
+ int to_line = _Py_Instrumentation_GetLine(code,
code->_co_monitoring->lines, to);
+ int from_line = _Py_Instrumentation_GetLine(code,
code->_co_monitoring->lines, from);
if (to_line != from_line) {
/* Will be handled by target INSTRUMENTED_LINE */
return &_PyInstrumentation_DISABLE;
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]