summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Python/legacy_tracing.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tools/python3/Python/legacy_tracing.c')
-rw-r--r--contrib/tools/python3/Python/legacy_tracing.c489
1 files changed, 365 insertions, 124 deletions
diff --git a/contrib/tools/python3/Python/legacy_tracing.c b/contrib/tools/python3/Python/legacy_tracing.c
index 4a6565bebc1..d7a195cf166 100644
--- a/contrib/tools/python3/Python/legacy_tracing.c
+++ b/contrib/tools/python3/Python/legacy_tracing.c
@@ -2,12 +2,13 @@
* Provides callables to forward PEP 669 events to legacy events.
*/
-#include <stddef.h>
#include "Python.h"
-#include "opcode.h"
-#include "pycore_ceval.h"
+#include "pycore_ceval.h" // export _PyEval_SetProfile()
#include "pycore_object.h"
-#include "pycore_sysmodule.h"
+#include "pycore_sysmodule.h" // _PySys_Audit()
+
+#include "opcode.h"
+#include <stddef.h>
typedef struct _PyLegacyEventHandler {
PyObject_HEAD
@@ -15,6 +16,13 @@ typedef struct _PyLegacyEventHandler {
int event;
} _PyLegacyEventHandler;
+#ifdef Py_GIL_DISABLED
+#define LOCK_SETUP() PyMutex_Lock(&_PyRuntime.ceval.sys_trace_profile_mutex);
+#define UNLOCK_SETUP() PyMutex_Unlock(&_PyRuntime.ceval.sys_trace_profile_mutex);
+#else
+#define LOCK_SETUP()
+#define UNLOCK_SETUP()
+#endif
/* The Py_tracefunc function expects the following arguments:
* obj: the trace object (PyObject *)
* frame: the current frame (PyFrameObject *)
@@ -45,7 +53,7 @@ call_profile_func(_PyLegacyEventHandler *self, PyObject *arg)
}
static PyObject *
-sys_profile_func2(
+sys_profile_start(
_PyLegacyEventHandler *self, PyObject *const *args,
size_t nargsf, PyObject *kwnames
) {
@@ -55,7 +63,17 @@ sys_profile_func2(
}
static PyObject *
-sys_profile_func3(
+sys_profile_throw(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(kwnames == NULL);
+ assert(PyVectorcall_NARGS(nargsf) == 3);
+ return call_profile_func(self, Py_None);
+}
+
+static PyObject *
+sys_profile_return(
_PyLegacyEventHandler *self, PyObject *const *args,
size_t nargsf, PyObject *kwnames
) {
@@ -71,7 +89,7 @@ sys_profile_unwind(
) {
assert(kwnames == NULL);
assert(PyVectorcall_NARGS(nargsf) == 3);
- return call_profile_func(self, Py_None);
+ return call_profile_func(self, NULL);
}
static PyObject *
@@ -119,6 +137,54 @@ sys_profile_call_or_return(
Py_RETURN_NONE;
}
+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;
+ }
+
+ if (enable) {
+ if (events & (1 << PY_MONITORING_EVENT_INSTRUCTION)) {
+ return 0;
+ }
+ events |= (1 << PY_MONITORING_EVENT_INSTRUCTION);
+ } else {
+ if (!(events & (1 << PY_MONITORING_EVENT_INSTRUCTION))) {
+ return 0;
+ }
+ events &= (~(1 << PY_MONITORING_EVENT_INSTRUCTION));
+ }
+ 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)
{
@@ -132,8 +198,15 @@ call_trace_func(_PyLegacyEventHandler *self, PyObject *arg)
"Missing frame when calling trace function.");
return NULL;
}
+ if (frame->f_trace_opcodes) {
+ if (_PyEval_SetOpcodeTrace(frame, true) != 0) {
+ return NULL;
+ }
+ }
+
Py_INCREF(frame);
int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, arg);
+ frame->f_lineno = 0;
Py_DECREF(frame);
if (err) {
return NULL;
@@ -166,7 +239,7 @@ sys_trace_exception_func(
}
static PyObject *
-sys_trace_func2(
+sys_trace_start(
_PyLegacyEventHandler *self, PyObject *const *args,
size_t nargsf, PyObject *kwnames
) {
@@ -176,7 +249,7 @@ sys_trace_func2(
}
static PyObject *
-sys_trace_func3(
+sys_trace_throw(
_PyLegacyEventHandler *self, PyObject *const *args,
size_t nargsf, PyObject *kwnames
) {
@@ -186,6 +259,16 @@ sys_trace_func3(
}
static PyObject *
+sys_trace_unwind(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(kwnames == NULL);
+ assert(PyVectorcall_NARGS(nargsf) == 3);
+ return call_trace_func(self, NULL);
+}
+
+static PyObject *
sys_trace_return(
_PyLegacyEventHandler *self, PyObject *const *args,
size_t nargsf, PyObject *kwnames
@@ -222,11 +305,14 @@ sys_trace_instruction_func(
"Missing frame when calling trace function.");
return NULL;
}
- if (!frame->f_trace_opcodes) {
+ PyThreadState *tstate = _PyThreadState_GET();
+ if (!tstate->c_tracefunc || !frame->f_trace_opcodes) {
+ if (_PyEval_SetOpcodeTrace(frame, false) != 0) {
+ return NULL;
+ }
Py_RETURN_NONE;
}
Py_INCREF(frame);
- PyThreadState *tstate = _PyThreadState_GET();
int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, Py_None);
frame->f_lineno = 0;
Py_DECREF(frame);
@@ -269,7 +355,7 @@ sys_trace_line_func(
Py_RETURN_NONE;
}
assert(PyVectorcall_NARGS(nargsf) == 2);
- int line = _PyLong_AsInt(args[1]);
+ int line = PyLong_AsInt(args[1]);
assert(line >= 0);
PyFrameObject *frame = PyEval_GetFrame();
if (frame == NULL) {
@@ -277,7 +363,7 @@ sys_trace_line_func(
"Missing frame when calling trace function.");
return NULL;
}
- assert(args[0] == (PyObject *)frame->f_frame->f_code);
+ assert(args[0] == (PyObject *)_PyFrame_GetCode(frame->f_frame));
return trace_line(tstate, self, frame, line);
}
@@ -295,9 +381,9 @@ sys_trace_jump_func(
Py_RETURN_NONE;
}
assert(PyVectorcall_NARGS(nargsf) == 3);
- int from = _PyLong_AsInt(args[1])/sizeof(_Py_CODEUNIT);
+ int from = PyLong_AsInt(args[1])/sizeof(_Py_CODEUNIT);
assert(from >= 0);
- int to = _PyLong_AsInt(args[2])/sizeof(_Py_CODEUNIT);
+ int to = PyLong_AsInt(args[2])/sizeof(_Py_CODEUNIT);
assert(to >= 0);
if (to > from) {
/* Forward jump */
@@ -319,7 +405,6 @@ sys_trace_jump_func(
"Missing frame when calling trace function.");
return NULL;
}
- assert(code == frame->f_frame->f_code);
if (!frame->f_trace_lines) {
Py_RETURN_NONE;
}
@@ -369,69 +454,65 @@ is_tstate_valid(PyThreadState *tstate)
}
#endif
-int
-_PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
+static int
+setup_profile_callbacks(void *Py_UNUSED(arg))
{
- assert(is_tstate_valid(tstate));
- /* The caller must hold the GIL */
- assert(PyGILState_Check());
-
- /* Call _PySys_Audit() in the context of the current thread state,
- even if tstate is not the current thread state. */
- PyThreadState *current_tstate = _PyThreadState_GET();
- if (_PySys_Audit(current_tstate, "sys.setprofile", NULL) < 0) {
+ /* Setup PEP 669 monitoring callbacks and events. */
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ (vectorcallfunc)sys_profile_start, PyTrace_CALL,
+ PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) {
return -1;
}
- /* 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,
- (vectorcallfunc)sys_profile_func2, PyTrace_CALL,
- PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- (vectorcallfunc)sys_profile_func3, PyTrace_CALL,
- PY_MONITORING_EVENT_PY_THROW, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- (vectorcallfunc)sys_profile_func3, PyTrace_RETURN,
- PY_MONITORING_EVENT_PY_RETURN, PY_MONITORING_EVENT_PY_YIELD)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- (vectorcallfunc)sys_profile_unwind, PyTrace_RETURN,
- PY_MONITORING_EVENT_PY_UNWIND, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_CALL,
- PY_MONITORING_EVENT_CALL, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_RETURN,
- PY_MONITORING_EVENT_C_RETURN, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
- (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_EXCEPTION,
- PY_MONITORING_EVENT_C_RAISE, -1)) {
- return -1;
- }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ (vectorcallfunc)sys_profile_throw, PyTrace_CALL,
+ PY_MONITORING_EVENT_PY_THROW, -1)) {
+ return -1;
}
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ (vectorcallfunc)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,
+ (vectorcallfunc)sys_profile_unwind, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_UNWIND, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_CALL,
+ PY_MONITORING_EVENT_CALL, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_RETURN,
+ PY_MONITORING_EVENT_C_RETURN, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_EXCEPTION,
+ PY_MONITORING_EVENT_C_RAISE, -1)) {
+ return -1;
+ }
+return 0;
+}
+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;
PyObject *old_profileobj = tstate->c_profileobj;
tstate->c_profileobj = Py_XNewRef(arg);
- Py_XDECREF(old_profileobj);
tstate->interp->sys_profiling_threads += delta;
assert(tstate->interp->sys_profiling_threads >= 0);
+ return old_profileobj;
+}
+static int
+set_monitoring_profile_events(PyInterpreterState *interp)
+{
uint32_t events = 0;
- if (tstate->interp->sys_profiling_threads) {
+ 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) |
@@ -442,7 +523,7 @@ _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
}
int
-_PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
+_PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
{
assert(is_tstate_valid(tstate));
/* The caller must hold the GIL */
@@ -451,82 +532,242 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
/* Call _PySys_Audit() in the context of the current thread state,
even if tstate is not the current thread state. */
PyThreadState *current_tstate = _PyThreadState_GET();
- if (_PySys_Audit(current_tstate, "sys.settrace", NULL) < 0) {
+ if (_PySys_Audit(current_tstate, "sys.setprofile", NULL) < 0) {
return -1;
}
- assert(tstate->interp->sys_tracing_threads >= 0);
+ 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;
+ }
+
+ PyObject *old_profileobjs = NULL;
+ _PyEval_StopTheWorld(interp);
+ HEAD_LOCK(&_PyRuntime);
+ Py_ssize_t num_thread_states = 0;
+ for (PyThreadState *p = interp->threads.head; p; p = p->next) {
+ num_thread_states++;
+ }
+ old_profileobjs = PyTuple_New(num_thread_states);
+ if (old_profileobjs == NULL) {
+ HEAD_UNLOCK(&_PyRuntime);
+ _PyEval_StartTheWorld(interp);
+ return -1;
+ }
+ for (PyThreadState *tstate = interp->threads.head; tstate; tstate = tstate->next) {
+ 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 int
+setup_trace_callbacks(void *Py_UNUSED(arg))
+{
/* 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,
- (vectorcallfunc)sys_trace_func2, PyTrace_CALL,
- PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- (vectorcallfunc)sys_trace_func3, PyTrace_CALL,
- PY_MONITORING_EVENT_PY_THROW, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- (vectorcallfunc)sys_trace_return, PyTrace_RETURN,
- PY_MONITORING_EVENT_PY_RETURN, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- (vectorcallfunc)sys_trace_yield, PyTrace_RETURN,
- PY_MONITORING_EVENT_PY_YIELD, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- (vectorcallfunc)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,
- (vectorcallfunc)sys_trace_line_func, PyTrace_LINE,
- PY_MONITORING_EVENT_LINE, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- (vectorcallfunc)sys_trace_func3, PyTrace_RETURN,
- PY_MONITORING_EVENT_PY_UNWIND, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- (vectorcallfunc)sys_trace_jump_func, PyTrace_LINE,
- PY_MONITORING_EVENT_JUMP, -1)) {
- return -1;
- }
- if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
- (vectorcallfunc)sys_trace_instruction_func, PyTrace_OPCODE,
- PY_MONITORING_EVENT_INSTRUCTION, -1)) {
- return -1;
- }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)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,
+ (vectorcallfunc)sys_trace_throw, PyTrace_CALL,
+ PY_MONITORING_EVENT_PY_THROW, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_return, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_RETURN, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_yield, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_YIELD, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)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,
+ (vectorcallfunc)sys_trace_line_func, PyTrace_LINE,
+ PY_MONITORING_EVENT_LINE, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_unwind, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_UNWIND, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_jump_func, PyTrace_LINE,
+ PY_MONITORING_EVENT_JUMP, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_instruction_func, PyTrace_OPCODE,
+ PY_MONITORING_EVENT_INSTRUCTION, -1)) {
+ return -1;
+ }
+ return 0;
+}
+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;
PyObject *old_traceobj = tstate->c_traceobj;
tstate->c_traceobj = Py_XNewRef(arg);
- Py_XDECREF(old_traceobj);
tstate->interp->sys_tracing_threads += delta;
assert(tstate->interp->sys_tracing_threads >= 0);
+ return old_traceobj;
+}
+static int
+set_monitoring_trace_events(PyInterpreterState *interp)
+{
uint32_t events = 0;
- if (tstate->interp->sys_tracing_threads) {
+ 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_BRANCH) |
+ (1 << PY_MONITORING_EVENT_JUMP) |
(1 << PY_MONITORING_EVENT_PY_UNWIND) | (1 << PY_MONITORING_EVENT_PY_THROW) |
- (1 << PY_MONITORING_EVENT_STOP_ITERATION) |
- (1 << PY_MONITORING_EVENT_EXCEPTION_HANDLED);
- if (tstate->interp->f_opcode_trace_set) {
- events |= (1 << PY_MONITORING_EVENT_INSTRUCTION);
- }
+ (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
+_PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
+{
+ assert(is_tstate_valid(tstate));
+ /* The caller must hold the GIL */
+ assert(PyGILState_Check());
+
+ /* Call _PySys_Audit() in the context of the current thread state,
+ even if tstate is not the current thread state. */
+ PyThreadState *current_tstate = _PyThreadState_GET();
+ if (_PySys_Audit(current_tstate, "sys.settrace", NULL) < 0) {
+ return -1;
+ }
+
+ PyInterpreterState *interp = tstate->interp;
+ if (_PyOnceFlag_CallOnce(&interp->sys_trace_once_flag,
+ setup_trace_callbacks, NULL) < 0) {
+ return -1;
+ }
+
+ 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;
+ }
+
+ PyObject *old_trace_objs = NULL;
+ _PyEval_StopTheWorld(interp);
+ HEAD_LOCK(&_PyRuntime);
+ Py_ssize_t num_thread_states = 0;
+ for (PyThreadState *p = interp->threads.head; p; p = p->next) {
+ num_thread_states++;
+ }
+ old_trace_objs = PyTuple_New(num_thread_states);
+ if (old_trace_objs == NULL) {
+ HEAD_UNLOCK(&_PyRuntime);
+ _PyEval_StartTheWorld(interp);
+ return -1;
+ }
+ for (PyThreadState *tstate = interp->threads.head; tstate; tstate = tstate->next) {
+ PyObject *old = swap_trace_func_arg(tstate, func, arg);
+ PyTuple_SET_ITEM(old_trace_objs, --num_thread_states, old);
+ }
+ if (interp->sys_tracing_threads) {
+ for (PyThreadState *tstate = interp->threads.head; tstate; tstate = tstate->next) {
+ int err = maybe_set_opcode_trace(tstate);
+ if (err != 0) {
+ HEAD_UNLOCK(&_PyRuntime);
+ _PyEval_StartTheWorld(interp);
+ Py_XDECREF(old_trace_objs);
+ return -1;
+ }
+ }
+ }
+ 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;
+}