mirror of
https://github.com/python/cpython.git
synced 2025-08-23 02:04:56 +00:00
gh-116818: Make sys.settrace
, sys.setprofile
, and monitoring thread-safe (#116775)
Makes sys.settrace, sys.setprofile, and monitoring generally thread-safe. Mostly uses a stop-the-world approach and synchronization around the code object's _co_instrumentation_version. There may be a little bit of extra synchronization around the monitoring data that's required to be TSAN clean.
This commit is contained in:
parent
b45af00bad
commit
07525c9a85
18 changed files with 530 additions and 63 deletions
|
@ -20,6 +20,7 @@
|
|||
#include "pycore_object.h" // _PyObject_GC_TRACK()
|
||||
#include "pycore_opcode_metadata.h" // uop names
|
||||
#include "pycore_opcode_utils.h" // MAKE_FUNCTION_*
|
||||
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR_ACQUIRE
|
||||
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
|
||||
#include "pycore_pystate.h" // _PyInterpreterState_GET()
|
||||
#include "pycore_range.h" // _PyRangeIterObject
|
||||
|
@ -150,10 +151,11 @@ dummy_func(
|
|||
uintptr_t global_version =
|
||||
_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) &
|
||||
~_PY_EVAL_EVENTS_MASK;
|
||||
uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version;
|
||||
PyCodeObject *code = _PyFrame_GetCode(frame);
|
||||
uintptr_t code_version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(code->_co_instrumentation_version);
|
||||
assert((code_version & 255) == 0);
|
||||
if (code_version != global_version) {
|
||||
int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
|
||||
int err = _Py_Instrument(code, tstate->interp);
|
||||
ERROR_IF(err, error);
|
||||
next_instr = this_instr;
|
||||
}
|
||||
|
@ -171,14 +173,14 @@ dummy_func(
|
|||
_Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING;
|
||||
#endif
|
||||
uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker);
|
||||
uintptr_t version = _PyFrame_GetCode(frame)->_co_instrumentation_version;
|
||||
uintptr_t version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version);
|
||||
assert((version & _PY_EVAL_EVENTS_MASK) == 0);
|
||||
DEOPT_IF(eval_breaker != version);
|
||||
}
|
||||
|
||||
inst(INSTRUMENTED_RESUME, (--)) {
|
||||
uintptr_t global_version = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK;
|
||||
uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version;
|
||||
uintptr_t code_version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version);
|
||||
if (code_version != global_version) {
|
||||
if (_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp)) {
|
||||
ERROR_NO_POP();
|
||||
|
@ -2377,7 +2379,14 @@ dummy_func(
|
|||
};
|
||||
|
||||
tier1 inst(ENTER_EXECUTOR, (--)) {
|
||||
int prevoparg = oparg;
|
||||
CHECK_EVAL_BREAKER();
|
||||
if (this_instr->op.code != ENTER_EXECUTOR ||
|
||||
this_instr->op.arg != prevoparg) {
|
||||
next_instr = this_instr;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
PyCodeObject *code = _PyFrame_GetCode(frame);
|
||||
_PyExecutorObject *executor = code->co_executors->executors[oparg & 255];
|
||||
assert(executor->vm_data.index == INSTR_OFFSET() - 1);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue