summaryrefslogtreecommitdiffstats
path: root/Python/legacy_tracing.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/legacy_tracing.c')
-rw-r--r--Python/legacy_tracing.c94
1 files changed, 64 insertions, 30 deletions
diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c
index ccbb3eb..d7aae7d 100644
--- a/Python/legacy_tracing.c
+++ b/Python/legacy_tracing.c
@@ -16,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 *)
@@ -414,19 +421,10 @@ is_tstate_valid(PyThreadState *tstate)
}
#endif
-int
-_PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
+static Py_ssize_t
+setup_profile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg, PyObject **old_profileobj)
{
- 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) {
- return -1;
- }
+ *old_profileobj = NULL;
/* Setup PEP 669 monitoring callbacks and events. */
if (!tstate->interp->sys_profile_initialized) {
tstate->interp->sys_profile_initialized = true;
@@ -469,25 +467,15 @@ _PyEval_SetProfile(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;
+ *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);
-
- uint32_t events = 0;
- if (tstate->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);
+ return tstate->interp->sys_profiling_threads;
}
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 */
@@ -496,11 +484,32 @@ _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);
+ // 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);
+
+ 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);
+ }
+ return _PyMonitoring_SetEvents(PY_MONITORING_SYS_PROFILE_ID, events);
+}
+
+static Py_ssize_t
+setup_tracing(PyThreadState *tstate, Py_tracefunc func, PyObject *arg, PyObject **old_traceobj)
+{
+ *old_traceobj = NULL;
/* Setup PEP 669 monitoring callbacks and events. */
if (!tstate->interp->sys_trace_initialized) {
tstate->interp->sys_trace_initialized = true;
@@ -553,14 +562,39 @@ _PyEval_SetTrace(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;
+ *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 tstate->interp->sys_tracing_threads;
+}
+
+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;
+ }
+ assert(tstate->interp->sys_tracing_threads >= 0);
+ // needs to be decref'd outside of the lock
+ PyObject *old_traceobj;
+ LOCK_SETUP();
+ Py_ssize_t tracing_threads = setup_tracing(tstate, func, arg, &old_traceobj);
+ UNLOCK_SETUP();
+ Py_XDECREF(old_traceobj);
+ if (tracing_threads < 0) {
+ return -1;
+ }
uint32_t events = 0;
- if (tstate->interp->sys_tracing_threads) {
+ 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) |