Skip to content

Commit b8c33e1

Browse files
iritkatrielpull[bot]
authored andcommitted
gh-111997: C-API for signalling monitoring events (#116413)
1 parent 244f79a commit b8c33e1

20 files changed

+1442
-37
lines changed

Doc/c-api/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ document the API functions in detail.
2525
memory.rst
2626
objimpl.rst
2727
apiabiversion.rst
28+
monitoring.rst

Doc/c-api/monitoring.rst

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
.. highlight:: c
2+
3+
.. _monitoring:
4+
5+
Monitorong C API
6+
================
7+
8+
Added in version 3.13.
9+
10+
An extension may need to interact with the event monitoring system. Subscribing
11+
to events and registering callbacks can be done via the Python API exposed in
12+
:mod:`sys.monitoring`.
13+
14+
Generating Execution Events
15+
===========================
16+
17+
The functions below make it possible for an extension to fire monitoring
18+
events as it emulates the execution of Python code. Each of these functions
19+
accepts a ``PyMonitoringState`` struct which contains concise information
20+
about the activation state of events, as well as the event arguments, which
21+
include a ``PyObject*`` representing the code object, the instruction offset
22+
and sometimes additional, event-specific arguments (see :mod:`sys.monitoring`
23+
for details about the signatures of the different event callbacks).
24+
The ``codelike`` argument should be an instance of :class:`types.CodeType`
25+
or of a type that emulates it.
26+
27+
The VM disables tracing when firing an event, so there is no need for user
28+
code to do that.
29+
30+
Monitoring functions should not be called with an exception set,
31+
except those listed below as working with the current exception.
32+
33+
.. c:type:: PyMonitoringState
34+
35+
Representation of the state of an event type. It is allocated by the user
36+
while its contents are maintained by the monitoring API functions described below.
37+
38+
39+
All of the functions below return 0 on success and -1 (with an exception set) on error.
40+
41+
See :mod:`sys.monitoring` for descriptions of the events.
42+
43+
.. c:function:: int PyMonitoring_FirePyStartEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
44+
45+
Fire a ``PY_START`` event.
46+
47+
48+
.. c:function:: int PyMonitoring_FirePyResumeEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
49+
50+
Fire a ``PY_RESUME`` event.
51+
52+
53+
.. c:function:: int PyMonitoring_FirePyReturnEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject* retval)
54+
55+
Fire a ``PY_RETURN`` event.
56+
57+
58+
.. c:function:: int PyMonitoring_FirePyYieldEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject* retval)
59+
60+
Fire a ``PY_YIELD`` event.
61+
62+
63+
.. c:function:: int PyMonitoring_FireCallEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject* callable, PyObject *arg0)
64+
65+
Fire a ``CALL`` event.
66+
67+
68+
.. c:function:: int PyMonitoring_FireLineEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, int lineno)
69+
70+
Fire a ``LINE`` event.
71+
72+
73+
.. c:function:: int PyMonitoring_FireJumpEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *target_offset)
74+
75+
Fire a ``JUMP`` event.
76+
77+
78+
.. c:function:: int PyMonitoring_FireBranchEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *target_offset)
79+
80+
Fire a ``BRANCH`` event.
81+
82+
83+
.. c:function:: int PyMonitoring_FireCReturnEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *retval)
84+
85+
Fire a ``C_RETURN`` event.
86+
87+
88+
.. c:function:: int PyMonitoring_FirePyThrowEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
89+
90+
Fire a ``PY_THROW`` event with the current exception (as returned by
91+
:c:func:`PyErr_GetRaisedException`).
92+
93+
94+
.. c:function:: int PyMonitoring_FireRaiseEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
95+
96+
Fire a ``RAISE`` event with the current exception (as returned by
97+
:c:func:`PyErr_GetRaisedException`).
98+
99+
100+
.. c:function:: int PyMonitoring_FireCRaiseEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
101+
102+
Fire a ``C_RAISE`` event with the current exception (as returned by
103+
:c:func:`PyErr_GetRaisedException`).
104+
105+
106+
.. c:function:: int PyMonitoring_FireReraiseEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
107+
108+
Fire a ``RERAISE`` event with the current exception (as returned by
109+
:c:func:`PyErr_GetRaisedException`).
110+
111+
112+
.. c:function:: int PyMonitoring_FireExceptionHandledEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
113+
114+
Fire an ``EXCEPTION_HANDLED`` event with the current exception (as returned by
115+
:c:func:`PyErr_GetRaisedException`).
116+
117+
118+
.. c:function:: int PyMonitoring_FirePyUnwindEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
119+
120+
Fire a ``PY_UNWIND`` event with the current exception (as returned by
121+
:c:func:`PyErr_GetRaisedException`).
122+
123+
124+
.. c:function:: int PyMonitoring_FireStopIterationEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
125+
126+
Fire a ``STOP_ITERATION`` event with the current exception (as returned by
127+
:c:func:`PyErr_GetRaisedException`).
128+
129+
130+
Managing the Monitoring State
131+
-----------------------------
132+
133+
Monitoring states can be managed with the help of monitoring scopes. A scope
134+
would typically correspond to a python function.
135+
136+
.. :c:function:: int PyMonitoring_EnterScope(PyMonitoringState *state_array, uint64_t *version, const uint8_t *event_types, Py_ssize_t length)
137+
138+
Enter a monitored scope. ``event_types`` is an array of the event IDs for
139+
events that may be fired from the scope. For example, the ID of a ``PY_START``
140+
event is the value ``PY_MONITORING_EVENT_PY_START``, which is numerically equal
141+
to the base-2 logarithm of ``sys.monitoring.events.PY_START``.
142+
``state_array`` is an array with a monitoring state entry for each event in
143+
``event_types``, it is allocated by the user but populated by
144+
``PyMonitoring_EnterScope`` with information about the activation state of
145+
the event. The size of ``event_types`` (and hence also of ``state_array``)
146+
is given in ``length``.
147+
148+
The ``version`` argument is a pointer to a value which should be allocated
149+
by the user together with ``state_array`` and initialized to 0,
150+
and then set only by ``PyMonitoring_EnterScope`` itelf. It allows this
151+
function to determine whether event states have changed since the previous call,
152+
and to return quickly if they have not.
153+
154+
The scopes referred to here are lexical scopes: a function, class or method.
155+
``PyMonitoring_EnterScope`` should be called whenever the lexical scope is
156+
entered. Scopes can be reentered, reusing the same *state_array* and *version*,
157+
in situations like when emulating a recursive Python function. When a code-like's
158+
execution is paused, such as when emulating a generator, the scope needs to
159+
be exited and re-entered.
160+
161+
162+
.. :c:function:: int PyMonitoring_ExitScope(void)
163+
164+
Exit the last scope that was entered with ``PyMonitoring_EnterScope``.

Doc/conf.py

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
('c:func', 'vsnprintf'),
132132
# Standard C types
133133
('c:type', 'FILE'),
134+
('c:type', 'int32_t'),
134135
('c:type', 'int64_t'),
135136
('c:type', 'intmax_t'),
136137
('c:type', 'off_t'),

Doc/library/sys.monitoring.rst

+4-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,10 @@ No events are active by default.
255255
Per code object events
256256
''''''''''''''''''''''
257257

258-
Events can also be controlled on a per code object basis.
258+
Events can also be controlled on a per code object basis. The functions
259+
defined below which accept a :class:`types.CodeType` should be prepared
260+
to accept a look-alike object from functions which are not defined
261+
in Python (see :ref:`monitoring`).
259262

260263
.. function:: get_local_events(tool_id: int, code: CodeType, /) -> int
261264

Include/Python.h

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
#include "setobject.h"
8585
#include "methodobject.h"
8686
#include "moduleobject.h"
87+
#include "monitoring.h"
8788
#include "cpython/funcobject.h"
8889
#include "cpython/classobject.h"
8990
#include "fileobject.h"

0 commit comments

Comments
 (0)