static void
set_global_version(PyThreadState *tstate, uint32_t version)
{
+ ASSERT_WORLD_STOPPED();
+
assert((version & _PY_EVAL_EVENTS_MASK) == 0);
PyInterpreterState *interp = tstate->interp;
set_version_raw(&interp->ceval.instrumentation_version, version);
static int
-instrument_all_executing_code_objects(PyInterpreterState *interp) {
+instrument_all_executing_code_objects(PyInterpreterState *interp)
+{
ASSERT_WORLD_STOPPED();
- _PyRuntimeState *runtime = &_PyRuntime;
- HEAD_LOCK(runtime);
- PyThreadState* ts = PyInterpreterState_ThreadHead(interp);
- HEAD_UNLOCK(runtime);
- while (ts) {
+ int err = 0;
+ _Py_FOR_EACH_TSTATE_BEGIN(interp, ts) {
_PyInterpreterFrame *frame = ts->current_frame;
while (frame) {
if (frame->owner < FRAME_OWNED_BY_INTERPRETER) {
- if (instrument_lock_held(_PyFrame_GetCode(frame), interp)) {
- return -1;
+ err = instrument_lock_held(_PyFrame_GetCode(frame), interp);
+ if (err) {
+ goto done;
}
}
frame = frame->previous;
}
- HEAD_LOCK(runtime);
- ts = PyThreadState_Next(ts);
- HEAD_UNLOCK(runtime);
}
- return 0;
+done:
+ _Py_FOR_EACH_TSTATE_END(interp);
+ return err;
}
static void
int
_PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events)
{
+ ASSERT_WORLD_STOPPED();
assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS);
PyThreadState *tstate = _PyThreadState_GET();
PyInterpreterState *interp = tstate->interp;
return -1;
}
- int res;
- _PyEval_StopTheWorld(interp);
uint32_t existing_events = get_events(&interp->monitors, tool_id);
if (existing_events == events) {
- res = 0;
- goto done;
+ return 0;
}
set_events(&interp->monitors, tool_id, events);
uint32_t new_version = global_version(interp) + MONITORING_VERSION_INCREMENT;
if (new_version == 0) {
PyErr_Format(PyExc_OverflowError, "events set too many times");
- res = -1;
- goto done;
+ return -1;
}
set_global_version(tstate, new_version);
#ifdef _Py_TIER2
_Py_Executors_InvalidateAll(interp, 1);
#endif
- res = instrument_all_executing_code_objects(interp);
-done:
- _PyEval_StartTheWorld(interp);
- return res;
+ return instrument_all_executing_code_objects(interp);
}
int
_PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet events)
{
+ ASSERT_WORLD_STOPPED();
+
assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS);
PyInterpreterState *interp = _PyInterpreterState_GET();
assert(events < (1 << _PY_MONITORING_LOCAL_EVENTS));
return -1;
}
- int res;
- _PyEval_StopTheWorld(interp);
if (allocate_instrumentation_data(code)) {
- res = -1;
- goto done;
+ return -1;
}
code->_co_monitoring->tool_versions[tool_id] = interp->monitoring_tool_versions[tool_id];
_Py_LocalMonitors *local = &code->_co_monitoring->local_monitors;
uint32_t existing_events = get_local_events(local, tool_id);
if (existing_events == events) {
- res = 0;
- goto done;
+ return 0;
}
set_local_events(local, tool_id, events);
- res = force_instrument_lock_held(code, interp);
-
-done:
- _PyEval_StartTheWorld(interp);
- return res;
+ return force_instrument_lock_held(code, interp);
}
int
}
}
+ _PyEval_StopTheWorld(interp);
if (_PyMonitoring_SetEvents(tool_id, 0) < 0) {
+ _PyEval_StartTheWorld(interp);
return -1;
}
- _PyEval_StopTheWorld(interp);
uint32_t version = global_version(interp) + MONITORING_VERSION_INCREMENT;
if (version == 0) {
PyErr_Format(PyExc_OverflowError, "events set too many times");
event_set &= ~(1 << PY_MONITORING_EVENT_BRANCH);
event_set |= (1 << PY_MONITORING_EVENT_BRANCH_RIGHT) | (1 << PY_MONITORING_EVENT_BRANCH_LEFT);
}
- if (_PyMonitoring_SetEvents(tool_id, event_set)) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ _PyEval_StopTheWorld(interp);
+ int err = _PyMonitoring_SetEvents(tool_id, event_set);
+ _PyEval_StartTheWorld(interp);
+ if (err) {
return NULL;
}
Py_RETURN_NONE;
return NULL;
}
- if (_PyMonitoring_SetLocalEvents((PyCodeObject*)code, tool_id, event_set)) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ _PyEval_StopTheWorld(interp);
+ int err = _PyMonitoring_SetLocalEvents((PyCodeObject*)code, tool_id, event_set);
+ _PyEval_StartTheWorld(interp);
+ if (err) {
return NULL;
}
Py_RETURN_NONE;
Py_RETURN_NONE;
}
-int
-_PyEval_SetOpcodeTrace(
- PyFrameObject *frame,
- bool enable
-) {
- assert(frame != NULL);
-
- PyCodeObject *code = _PyFrame_GetCode(frame->f_frame);
+static int
+set_opcode_trace_world_stopped(PyCodeObject *code, bool enable)
+{
_PyMonitoringEventSet events = 0;
-
if (_PyMonitoring_GetLocalEvents(code, PY_MONITORING_SYS_TRACE_ID, &events) < 0) {
return -1;
}
return _PyMonitoring_SetLocalEvents(code, PY_MONITORING_SYS_TRACE_ID, events);
}
+int
+_PyEval_SetOpcodeTrace(PyFrameObject *frame, bool enable)
+{
+ assert(frame != NULL);
+
+ PyCodeObject *code = _PyFrame_GetCode(frame->f_frame);
+
+#ifdef Py_GIL_DISABLED
+ // First check if a change is necessary outside of the stop-the-world pause
+ _PyMonitoringEventSet events = 0;
+ if (_PyMonitoring_GetLocalEvents(code, PY_MONITORING_SYS_TRACE_ID, &events) < 0) {
+ return -1;
+ }
+ int is_enabled = (events & (1 << PY_MONITORING_EVENT_INSTRUCTION)) != 0;
+ if (is_enabled == enable) {
+ return 0; // No change needed
+ }
+#endif
+
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ _PyEval_StopTheWorld(interp);
+ int res = set_opcode_trace_world_stopped(code, enable);
+ _PyEval_StartTheWorld(interp);
+ return res;
+}
+
static PyObject *
call_trace_func(_PyLegacyEventHandler *self, PyObject *arg)
{
}
#endif
-static Py_ssize_t
-setup_profile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg, PyObject **old_profileobj)
+static int
+setup_profile_callbacks(void *Py_UNUSED(arg))
{
- *old_profileobj = NULL;
/* Setup PEP 669 monitoring callbacks and events. */
- if (!tstate->interp->sys_profile_initialized) {
- tstate->interp->sys_profile_initialized = true;
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- sys_profile_start, PyTrace_CALL,
- PY_MONITORING_EVENT_PY_START,
- PY_MONITORING_EVENT_PY_RESUME)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- sys_profile_throw, PyTrace_CALL,
- PY_MONITORING_EVENT_PY_THROW, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- sys_profile_return, PyTrace_RETURN,
- PY_MONITORING_EVENT_PY_RETURN,
- PY_MONITORING_EVENT_PY_YIELD)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- sys_profile_unwind, PyTrace_RETURN,
- PY_MONITORING_EVENT_PY_UNWIND, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- sys_profile_call_or_return, PyTrace_C_CALL,
- PY_MONITORING_EVENT_CALL, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- sys_profile_call_or_return, PyTrace_C_RETURN,
- PY_MONITORING_EVENT_C_RETURN, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- sys_profile_call_or_return, PyTrace_C_EXCEPTION,
- PY_MONITORING_EVENT_C_RAISE, -1)) {
- return -1;
- }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ sys_profile_start, PyTrace_CALL,
+ PY_MONITORING_EVENT_PY_START,
+ PY_MONITORING_EVENT_PY_RESUME)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ sys_profile_throw, PyTrace_CALL,
+ PY_MONITORING_EVENT_PY_THROW, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ sys_profile_return, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_RETURN,
+ PY_MONITORING_EVENT_PY_YIELD)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ sys_profile_unwind, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_UNWIND, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ sys_profile_call_or_return, PyTrace_C_CALL,
+ PY_MONITORING_EVENT_CALL, -1)) {
+ return -1;
}
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ sys_profile_call_or_return, PyTrace_C_RETURN,
+ PY_MONITORING_EVENT_C_RETURN, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ sys_profile_call_or_return, PyTrace_C_EXCEPTION,
+ PY_MONITORING_EVENT_C_RAISE, -1)) {
+ return -1;
+ }
+ return 0;
+}
- _PyEval_StopTheWorld(tstate->interp);
+static PyObject *
+swap_profile_func_arg(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
+{
int delta = (func != NULL) - (tstate->c_profilefunc != NULL);
tstate->c_profilefunc = func;
- *old_profileobj = tstate->c_profileobj;
+ PyObject *old_profileobj = tstate->c_profileobj;
tstate->c_profileobj = Py_XNewRef(arg);
tstate->interp->sys_profiling_threads += delta;
assert(tstate->interp->sys_profiling_threads >= 0);
- Py_ssize_t profiling_threads = tstate->interp->sys_profiling_threads;
- _PyEval_StartTheWorld(tstate->interp);
- return profiling_threads;
+ return old_profileobj;
+}
+
+static int
+set_monitoring_profile_events(PyInterpreterState *interp)
+{
+ uint32_t events = 0;
+ if (interp->sys_profiling_threads) {
+ events =
+ (1 << PY_MONITORING_EVENT_PY_START) | (1 << PY_MONITORING_EVENT_PY_RESUME) |
+ (1 << PY_MONITORING_EVENT_PY_RETURN) | (1 << PY_MONITORING_EVENT_PY_YIELD) |
+ (1 << PY_MONITORING_EVENT_CALL) | (1 << PY_MONITORING_EVENT_PY_UNWIND) |
+ (1 << PY_MONITORING_EVENT_PY_THROW);
+ }
+ return _PyMonitoring_SetEvents(PY_MONITORING_SYS_PROFILE_ID, events);
}
int
return -1;
}
- // needs to be decref'd outside of the lock
- PyObject *old_profileobj;
- LOCK_SETUP();
- Py_ssize_t profiling_threads = setup_profile(tstate, func, arg, &old_profileobj);
- UNLOCK_SETUP();
- Py_XDECREF(old_profileobj);
+ PyInterpreterState *interp = tstate->interp;
+ if (_PyOnceFlag_CallOnce(&interp->sys_profile_once_flag,
+ setup_profile_callbacks, NULL) < 0) {
+ return -1;
+ }
+
+ _PyEval_StopTheWorld(interp);
+ PyObject *old_profileobj = swap_profile_func_arg(tstate, func, arg);
+ int ret = set_monitoring_profile_events(interp);
+ _PyEval_StartTheWorld(interp);
+ Py_XDECREF(old_profileobj); // needs to be decref'd outside of stop-the-world
+ return ret;
+}
+
+int
+_PyEval_SetProfileAllThreads(PyInterpreterState *interp, Py_tracefunc func, PyObject *arg)
+{
+ PyThreadState *current_tstate = _PyThreadState_GET();
+ assert(is_tstate_valid(current_tstate));
+ assert(current_tstate->interp == interp);
+
+ if (_PySys_Audit(current_tstate, "sys.setprofile", NULL) < 0) {
+ return -1;
+ }
+
+ if (_PyOnceFlag_CallOnce(&interp->sys_profile_once_flag,
+ setup_profile_callbacks, NULL) < 0) {
+ return -1;
+ }
- uint32_t events = 0;
- if (profiling_threads) {
- events =
- (1 << PY_MONITORING_EVENT_PY_START) | (1 << PY_MONITORING_EVENT_PY_RESUME) |
- (1 << PY_MONITORING_EVENT_PY_RETURN) | (1 << PY_MONITORING_EVENT_PY_YIELD) |
- (1 << PY_MONITORING_EVENT_CALL) | (1 << PY_MONITORING_EVENT_PY_UNWIND) |
- (1 << PY_MONITORING_EVENT_PY_THROW);
+ PyObject *old_profileobjs = NULL;
+ _PyEval_StopTheWorld(interp);
+ HEAD_LOCK(&_PyRuntime);
+ Py_ssize_t num_thread_states = 0;
+ _Py_FOR_EACH_TSTATE_UNLOCKED(interp, p) {
+ num_thread_states++;
}
- return _PyMonitoring_SetEvents(PY_MONITORING_SYS_PROFILE_ID, events);
+ old_profileobjs = PyTuple_New(num_thread_states);
+ if (old_profileobjs == NULL) {
+ HEAD_UNLOCK(&_PyRuntime);
+ _PyEval_StartTheWorld(interp);
+ return -1;
+ }
+ _Py_FOR_EACH_TSTATE_UNLOCKED(interp, tstate) {
+ PyObject *old = swap_profile_func_arg(tstate, func, arg);
+ PyTuple_SET_ITEM(old_profileobjs, --num_thread_states, old);
+ }
+ HEAD_UNLOCK(&_PyRuntime);
+ int ret = set_monitoring_profile_events(interp);
+ _PyEval_StartTheWorld(interp);
+ Py_XDECREF(old_profileobjs); // needs to be decref'd outside of stop-the-world
+ return ret;
}
-static Py_ssize_t
-setup_tracing(PyThreadState *tstate, Py_tracefunc func, PyObject *arg, PyObject **old_traceobj)
+static int
+setup_trace_callbacks(void *Py_UNUSED(arg))
{
- *old_traceobj = NULL;
/* Setup PEP 669 monitoring callbacks and events. */
- if (!tstate->interp->sys_trace_initialized) {
- tstate->interp->sys_trace_initialized = true;
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- sys_trace_start, PyTrace_CALL,
- PY_MONITORING_EVENT_PY_START,
- PY_MONITORING_EVENT_PY_RESUME)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- sys_trace_throw, PyTrace_CALL,
- PY_MONITORING_EVENT_PY_THROW, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- sys_trace_return, PyTrace_RETURN,
- PY_MONITORING_EVENT_PY_RETURN, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- sys_trace_yield, PyTrace_RETURN,
- PY_MONITORING_EVENT_PY_YIELD, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- sys_trace_exception_func, PyTrace_EXCEPTION,
- PY_MONITORING_EVENT_RAISE,
- PY_MONITORING_EVENT_STOP_ITERATION)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- sys_trace_line_func, PyTrace_LINE,
- PY_MONITORING_EVENT_LINE, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- sys_trace_unwind, PyTrace_RETURN,
- PY_MONITORING_EVENT_PY_UNWIND, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- sys_trace_jump_func, PyTrace_LINE,
- PY_MONITORING_EVENT_JUMP, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- sys_trace_instruction_func, PyTrace_OPCODE,
- PY_MONITORING_EVENT_INSTRUCTION, -1)) {
- return -1;
- }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ sys_trace_start, PyTrace_CALL,
+ PY_MONITORING_EVENT_PY_START,
+ PY_MONITORING_EVENT_PY_RESUME)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ sys_trace_throw, PyTrace_CALL,
+ PY_MONITORING_EVENT_PY_THROW, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ sys_trace_return, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_RETURN, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ sys_trace_yield, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_YIELD, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ sys_trace_exception_func, PyTrace_EXCEPTION,
+ PY_MONITORING_EVENT_RAISE,
+ PY_MONITORING_EVENT_STOP_ITERATION)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ sys_trace_line_func, PyTrace_LINE,
+ PY_MONITORING_EVENT_LINE, -1)) {
+ return -1;
}
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ sys_trace_unwind, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_UNWIND, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ sys_trace_jump_func, PyTrace_LINE,
+ PY_MONITORING_EVENT_JUMP, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ sys_trace_instruction_func, PyTrace_OPCODE,
+ PY_MONITORING_EVENT_INSTRUCTION, -1)) {
+ return -1;
+ }
+ return 0;
+}
- _PyEval_StopTheWorld(tstate->interp);
+static PyObject *
+swap_trace_func_arg(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
+{
int delta = (func != NULL) - (tstate->c_tracefunc != NULL);
tstate->c_tracefunc = func;
- *old_traceobj = tstate->c_traceobj;
+ PyObject *old_traceobj = tstate->c_traceobj;
tstate->c_traceobj = Py_XNewRef(arg);
tstate->interp->sys_tracing_threads += delta;
assert(tstate->interp->sys_tracing_threads >= 0);
- Py_ssize_t tracing_threads = tstate->interp->sys_tracing_threads;
- _PyEval_StartTheWorld(tstate->interp);
- return tracing_threads;
+ return old_traceobj;
+}
+
+static int
+set_monitoring_trace_events(PyInterpreterState *interp)
+{
+ uint32_t events = 0;
+ if (interp->sys_tracing_threads) {
+ events =
+ (1 << PY_MONITORING_EVENT_PY_START) | (1 << PY_MONITORING_EVENT_PY_RESUME) |
+ (1 << PY_MONITORING_EVENT_PY_RETURN) | (1 << PY_MONITORING_EVENT_PY_YIELD) |
+ (1 << PY_MONITORING_EVENT_RAISE) | (1 << PY_MONITORING_EVENT_LINE) |
+ (1 << PY_MONITORING_EVENT_JUMP) |
+ (1 << PY_MONITORING_EVENT_PY_UNWIND) | (1 << PY_MONITORING_EVENT_PY_THROW) |
+ (1 << PY_MONITORING_EVENT_STOP_ITERATION);
+ }
+ return _PyMonitoring_SetEvents(PY_MONITORING_SYS_TRACE_ID, events);
+}
+
+// Enable opcode tracing for the thread's current frame if needed.
+static int
+maybe_set_opcode_trace(PyThreadState *tstate)
+{
+ _PyInterpreterFrame *iframe = tstate->current_frame;
+ if (iframe == NULL) {
+ return 0;
+ }
+ PyFrameObject *frame = iframe->frame_obj;
+ if (frame == NULL || !frame->f_trace_opcodes) {
+ return 0;
+ }
+ return set_opcode_trace_world_stopped(_PyFrame_GetCode(iframe), true);
}
int
if (_PySys_Audit(current_tstate, "sys.settrace", NULL) < 0) {
return -1;
}
- // needs to be decref'd outside of the lock
- PyObject *old_traceobj;
- LOCK_SETUP();
- assert(tstate->interp->sys_tracing_threads >= 0);
- Py_ssize_t tracing_threads = setup_tracing(tstate, func, arg, &old_traceobj);
- UNLOCK_SETUP();
- Py_XDECREF(old_traceobj);
- if (tracing_threads < 0) {
+
+ PyInterpreterState *interp = tstate->interp;
+ if (_PyOnceFlag_CallOnce(&interp->sys_trace_once_flag,
+ setup_trace_callbacks, NULL) < 0) {
return -1;
}
- uint32_t events = 0;
- if (tracing_threads) {
- events =
- (1 << PY_MONITORING_EVENT_PY_START) | (1 << PY_MONITORING_EVENT_PY_RESUME) |
- (1 << PY_MONITORING_EVENT_PY_RETURN) | (1 << PY_MONITORING_EVENT_PY_YIELD) |
- (1 << PY_MONITORING_EVENT_RAISE) | (1 << PY_MONITORING_EVENT_LINE) |
- (1 << PY_MONITORING_EVENT_JUMP) |
- (1 << PY_MONITORING_EVENT_PY_UNWIND) | (1 << PY_MONITORING_EVENT_PY_THROW) |
- (1 << PY_MONITORING_EVENT_STOP_ITERATION);
+ int err = 0;
+ _PyEval_StopTheWorld(interp);
+ PyObject *old_traceobj = swap_trace_func_arg(tstate, func, arg);
+ err = set_monitoring_trace_events(interp);
+ if (err != 0) {
+ goto done;
+ }
+ if (interp->sys_tracing_threads) {
+ err = maybe_set_opcode_trace(tstate);
+ }
+done:
+ _PyEval_StartTheWorld(interp);
+ Py_XDECREF(old_traceobj); // needs to be decref'd outside stop-the-world
+ return err;
+}
+
+int
+_PyEval_SetTraceAllThreads(PyInterpreterState *interp, Py_tracefunc func, PyObject *arg)
+{
+ PyThreadState *current_tstate = _PyThreadState_GET();
+ assert(is_tstate_valid(current_tstate));
+ assert(current_tstate->interp == interp);
+
+ if (_PySys_Audit(current_tstate, "sys.settrace", NULL) < 0) {
+ return -1;
+ }
+
+ if (_PyOnceFlag_CallOnce(&interp->sys_trace_once_flag,
+ setup_trace_callbacks, NULL) < 0) {
+ return -1;
+ }
- PyFrameObject* frame = PyEval_GetFrame();
- if (frame && frame->f_trace_opcodes) {
- int ret = _PyEval_SetOpcodeTrace(frame, true);
- if (ret != 0) {
- return ret;
+ PyObject *old_trace_objs = NULL;
+ _PyEval_StopTheWorld(interp);
+ HEAD_LOCK(&_PyRuntime);
+ Py_ssize_t num_thread_states = 0;
+ _Py_FOR_EACH_TSTATE_UNLOCKED(interp, p) {
+ num_thread_states++;
+ }
+ old_trace_objs = PyTuple_New(num_thread_states);
+ if (old_trace_objs == NULL) {
+ HEAD_UNLOCK(&_PyRuntime);
+ _PyEval_StartTheWorld(interp);
+ return -1;
+ }
+ _Py_FOR_EACH_TSTATE_UNLOCKED(interp, tstate) {
+ PyObject *old = swap_trace_func_arg(tstate, func, arg);
+ PyTuple_SET_ITEM(old_trace_objs, --num_thread_states, old);
+ }
+ if (interp->sys_tracing_threads) {
+ _Py_FOR_EACH_TSTATE_UNLOCKED(interp, tstate) {
+ int err = maybe_set_opcode_trace(tstate);
+ if (err != 0) {
+ HEAD_UNLOCK(&_PyRuntime);
+ _PyEval_StartTheWorld(interp);
+ Py_XDECREF(old_trace_objs);
+ return -1;
}
}
}
-
- return _PyMonitoring_SetEvents(PY_MONITORING_SYS_TRACE_ID, events);
+ HEAD_UNLOCK(&_PyRuntime);
+ int err = set_monitoring_trace_events(interp);
+ _PyEval_StartTheWorld(interp);
+ Py_XDECREF(old_trace_objs); // needs to be decref'd outside of stop-the-world
+ return err;
}