1 #include "parts.h"
2 #include "util.h"
3
4 #include "monitoring.h"
5
6 #define Py_BUILD_CORE
7 #include "internal/pycore_instruments.h"
8
9 typedef struct {
10 PyObject_HEAD
11 PyMonitoringState *monitoring_states;
12 uint64_t version;
13 int num_events;
14 /* Other fields */
15 } PyCodeLikeObject;
16
17
18 static PyObject *
CodeLike_new(PyTypeObject * type,PyObject * args,PyObject * kwds)19 CodeLike_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
20 {
21 int num_events;
22 if (!PyArg_ParseTuple(args, "i", &num_events)) {
23 return NULL;
24 }
25 PyMonitoringState *states = (PyMonitoringState *)PyMem_Calloc(
26 num_events, sizeof(PyMonitoringState));
27 if (states == NULL) {
28 return NULL;
29 }
30 PyCodeLikeObject *self = (PyCodeLikeObject *) type->tp_alloc(type, 0);
31 if (self != NULL) {
32 self->version = 0;
33 self->monitoring_states = states;
34 self->num_events = num_events;
35 }
36 else {
37 PyMem_Free(states);
38 }
39 return (PyObject *) self;
40 }
41
42 static void
CodeLike_dealloc(PyCodeLikeObject * self)43 CodeLike_dealloc(PyCodeLikeObject *self)
44 {
45 if (self->monitoring_states) {
46 PyMem_Free(self->monitoring_states);
47 }
48 Py_TYPE(self)->tp_free((PyObject *) self);
49 }
50
51 static PyObject *
CodeLike_str(PyCodeLikeObject * self)52 CodeLike_str(PyCodeLikeObject *self)
53 {
54 PyObject *res = NULL;
55 PyObject *sep = NULL;
56 PyObject *parts = NULL;
57 if (self->monitoring_states) {
58 parts = PyList_New(0);
59 if (parts == NULL) {
60 goto end;
61 }
62
63 PyObject *heading = PyUnicode_FromString("PyCodeLikeObject");
64 if (heading == NULL) {
65 goto end;
66 }
67 int err = PyList_Append(parts, heading);
68 Py_DECREF(heading);
69 if (err < 0) {
70 goto end;
71 }
72
73 for (int i = 0; i < self->num_events; i++) {
74 PyObject *part = PyUnicode_FromFormat(" %d", self->monitoring_states[i].active);
75 if (part == NULL) {
76 goto end;
77 }
78 int err = PyList_Append(parts, part);
79 Py_XDECREF(part);
80 if (err < 0) {
81 goto end;
82 }
83 }
84 sep = PyUnicode_FromString(": ");
85 if (sep == NULL) {
86 goto end;
87 }
88 res = PyUnicode_Join(sep, parts);
89 }
90 end:
91 Py_XDECREF(sep);
92 Py_XDECREF(parts);
93 return res;
94 }
95
96 static PyTypeObject PyCodeLike_Type = {
97 .ob_base = PyVarObject_HEAD_INIT(NULL, 0)
98 .tp_name = "monitoring.CodeLike",
99 .tp_doc = PyDoc_STR("CodeLike objects"),
100 .tp_basicsize = sizeof(PyCodeLikeObject),
101 .tp_itemsize = 0,
102 .tp_flags = Py_TPFLAGS_DEFAULT,
103 .tp_new = CodeLike_new,
104 .tp_dealloc = (destructor) CodeLike_dealloc,
105 .tp_str = (reprfunc) CodeLike_str,
106 };
107
108 #define RAISE_UNLESS_CODELIKE(v) if (!Py_IS_TYPE((v), &PyCodeLike_Type)) { \
109 PyErr_Format(PyExc_TypeError, "expected a code-like, got %s", Py_TYPE(v)->tp_name); \
110 return NULL; \
111 }
112
113 /*******************************************************************/
114
115 static PyMonitoringState *
setup_fire(PyObject * codelike,int offset,PyObject * exc)116 setup_fire(PyObject *codelike, int offset, PyObject *exc)
117 {
118 RAISE_UNLESS_CODELIKE(codelike);
119 PyCodeLikeObject *cl = ((PyCodeLikeObject *)codelike);
120 assert(offset >= 0 && offset < cl->num_events);
121 PyMonitoringState *state = &cl->monitoring_states[offset];
122
123 if (exc != NULL) {
124 PyErr_SetRaisedException(Py_NewRef(exc));
125 }
126 return state;
127 }
128
129 static int
teardown_fire(int res,PyMonitoringState * state,PyObject * exception)130 teardown_fire(int res, PyMonitoringState *state, PyObject *exception)
131 {
132 if (res == -1) {
133 return -1;
134 }
135 if (exception) {
136 assert(PyErr_Occurred());
137 assert(((PyObject*)Py_TYPE(exception)) == PyErr_Occurred());
138 }
139
140 else {
141 assert(!PyErr_Occurred());
142 }
143 PyErr_Clear();
144 return state->active;
145 }
146
147 static PyObject *
fire_event_py_start(PyObject * self,PyObject * args)148 fire_event_py_start(PyObject *self, PyObject *args)
149 {
150 PyObject *codelike;
151 int offset;
152 if (!PyArg_ParseTuple(args, "Oi", &codelike, &offset)) {
153 return NULL;
154 }
155 PyObject *exception = NULL;
156 PyMonitoringState *state = setup_fire(codelike, offset, exception);
157 if (state == NULL) {
158 return NULL;
159 }
160 int res = PyMonitoring_FirePyStartEvent(state, codelike, offset);
161 RETURN_INT(teardown_fire(res, state, exception));
162 }
163
164 static PyObject *
fire_event_py_resume(PyObject * self,PyObject * args)165 fire_event_py_resume(PyObject *self, PyObject *args)
166 {
167 PyObject *codelike;
168 int offset;
169 if (!PyArg_ParseTuple(args, "Oi", &codelike, &offset)) {
170 return NULL;
171 }
172 PyObject *exception = NULL;
173 PyMonitoringState *state = setup_fire(codelike, offset, exception);
174 if (state == NULL) {
175 return NULL;
176 }
177 int res = PyMonitoring_FirePyResumeEvent(state, codelike, offset);
178 RETURN_INT(teardown_fire(res, state, exception));
179 }
180
181 static PyObject *
fire_event_py_return(PyObject * self,PyObject * args)182 fire_event_py_return(PyObject *self, PyObject *args)
183 {
184 PyObject *codelike;
185 int offset;
186 PyObject *retval;
187 if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &retval)) {
188 return NULL;
189 }
190 PyObject *exception = NULL;
191 PyMonitoringState *state = setup_fire(codelike, offset, exception);
192 if (state == NULL) {
193 return NULL;
194 }
195 int res = PyMonitoring_FirePyReturnEvent(state, codelike, offset, retval);
196 RETURN_INT(teardown_fire(res, state, exception));
197 }
198
199 static PyObject *
fire_event_c_return(PyObject * self,PyObject * args)200 fire_event_c_return(PyObject *self, PyObject *args)
201 {
202 PyObject *codelike;
203 int offset;
204 PyObject *retval;
205 if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &retval)) {
206 return NULL;
207 }
208 PyObject *exception = NULL;
209 PyMonitoringState *state = setup_fire(codelike, offset, exception);
210 if (state == NULL) {
211 return NULL;
212 }
213 int res = PyMonitoring_FireCReturnEvent(state, codelike, offset, retval);
214 RETURN_INT(teardown_fire(res, state, exception));
215 }
216
217 static PyObject *
fire_event_py_yield(PyObject * self,PyObject * args)218 fire_event_py_yield(PyObject *self, PyObject *args)
219 {
220 PyObject *codelike;
221 int offset;
222 PyObject *retval;
223 if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &retval)) {
224 return NULL;
225 }
226 PyObject *exception = NULL;
227 PyMonitoringState *state = setup_fire(codelike, offset, exception);
228 if (state == NULL) {
229 return NULL;
230 }
231 int res = PyMonitoring_FirePyYieldEvent(state, codelike, offset, retval);
232 RETURN_INT(teardown_fire(res, state, exception));
233 }
234
235 static PyObject *
fire_event_call(PyObject * self,PyObject * args)236 fire_event_call(PyObject *self, PyObject *args)
237 {
238 PyObject *codelike;
239 int offset;
240 PyObject *callable, *arg0;
241 if (!PyArg_ParseTuple(args, "OiOO", &codelike, &offset, &callable, &arg0)) {
242 return NULL;
243 }
244 PyObject *exception = NULL;
245 PyMonitoringState *state = setup_fire(codelike, offset, exception);
246 if (state == NULL) {
247 return NULL;
248 }
249 int res = PyMonitoring_FireCallEvent(state, codelike, offset, callable, arg0);
250 RETURN_INT(teardown_fire(res, state, exception));
251 }
252
253 static PyObject *
fire_event_line(PyObject * self,PyObject * args)254 fire_event_line(PyObject *self, PyObject *args)
255 {
256 PyObject *codelike;
257 int offset, lineno;
258 if (!PyArg_ParseTuple(args, "Oii", &codelike, &offset, &lineno)) {
259 return NULL;
260 }
261 PyObject *exception = NULL;
262 PyMonitoringState *state = setup_fire(codelike, offset, exception);
263 if (state == NULL) {
264 return NULL;
265 }
266 int res = PyMonitoring_FireLineEvent(state, codelike, offset, lineno);
267 RETURN_INT(teardown_fire(res, state, exception));
268 }
269
270 static PyObject *
fire_event_jump(PyObject * self,PyObject * args)271 fire_event_jump(PyObject *self, PyObject *args)
272 {
273 PyObject *codelike;
274 int offset;
275 PyObject *target_offset;
276 if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &target_offset)) {
277 return NULL;
278 }
279 PyObject *exception = NULL;
280 PyMonitoringState *state = setup_fire(codelike, offset, exception);
281 if (state == NULL) {
282 return NULL;
283 }
284 int res = PyMonitoring_FireJumpEvent(state, codelike, offset, target_offset);
285 RETURN_INT(teardown_fire(res, state, exception));
286 }
287
288 static PyObject *
fire_event_branch(PyObject * self,PyObject * args)289 fire_event_branch(PyObject *self, PyObject *args)
290 {
291 PyObject *codelike;
292 int offset;
293 PyObject *target_offset;
294 if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &target_offset)) {
295 return NULL;
296 }
297 PyObject *exception = NULL;
298 PyMonitoringState *state = setup_fire(codelike, offset, exception);
299 if (state == NULL) {
300 return NULL;
301 }
302 int res = PyMonitoring_FireBranchEvent(state, codelike, offset, target_offset);
303 RETURN_INT(teardown_fire(res, state, exception));
304 }
305
306 static PyObject *
fire_event_py_throw(PyObject * self,PyObject * args)307 fire_event_py_throw(PyObject *self, PyObject *args)
308 {
309 PyObject *codelike;
310 int offset;
311 PyObject *exception;
312 if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &exception)) {
313 return NULL;
314 }
315 NULLABLE(exception);
316 PyMonitoringState *state = setup_fire(codelike, offset, exception);
317 if (state == NULL) {
318 return NULL;
319 }
320 int res = PyMonitoring_FirePyThrowEvent(state, codelike, offset);
321 RETURN_INT(teardown_fire(res, state, exception));
322 }
323
324 static PyObject *
fire_event_raise(PyObject * self,PyObject * args)325 fire_event_raise(PyObject *self, PyObject *args)
326 {
327 PyObject *codelike;
328 int offset;
329 PyObject *exception;
330 if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &exception)) {
331 return NULL;
332 }
333 NULLABLE(exception);
334 PyMonitoringState *state = setup_fire(codelike, offset, exception);
335 if (state == NULL) {
336 return NULL;
337 }
338 int res = PyMonitoring_FireRaiseEvent(state, codelike, offset);
339 RETURN_INT(teardown_fire(res, state, exception));
340 }
341
342 static PyObject *
fire_event_c_raise(PyObject * self,PyObject * args)343 fire_event_c_raise(PyObject *self, PyObject *args)
344 {
345 PyObject *codelike;
346 int offset;
347 PyObject *exception;
348 if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &exception)) {
349 return NULL;
350 }
351 NULLABLE(exception);
352 PyMonitoringState *state = setup_fire(codelike, offset, exception);
353 if (state == NULL) {
354 return NULL;
355 }
356 int res = PyMonitoring_FireCRaiseEvent(state, codelike, offset);
357 RETURN_INT(teardown_fire(res, state, exception));
358 }
359
360 static PyObject *
fire_event_reraise(PyObject * self,PyObject * args)361 fire_event_reraise(PyObject *self, PyObject *args)
362 {
363 PyObject *codelike;
364 int offset;
365 PyObject *exception;
366 if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &exception)) {
367 return NULL;
368 }
369 NULLABLE(exception);
370 PyMonitoringState *state = setup_fire(codelike, offset, exception);
371 if (state == NULL) {
372 return NULL;
373 }
374 int res = PyMonitoring_FireReraiseEvent(state, codelike, offset);
375 RETURN_INT(teardown_fire(res, state, exception));
376 }
377
378 static PyObject *
fire_event_exception_handled(PyObject * self,PyObject * args)379 fire_event_exception_handled(PyObject *self, PyObject *args)
380 {
381 PyObject *codelike;
382 int offset;
383 PyObject *exception;
384 if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &exception)) {
385 return NULL;
386 }
387 NULLABLE(exception);
388 PyMonitoringState *state = setup_fire(codelike, offset, exception);
389 if (state == NULL) {
390 return NULL;
391 }
392 int res = PyMonitoring_FireExceptionHandledEvent(state, codelike, offset);
393 RETURN_INT(teardown_fire(res, state, exception));
394 }
395
396 static PyObject *
fire_event_py_unwind(PyObject * self,PyObject * args)397 fire_event_py_unwind(PyObject *self, PyObject *args)
398 {
399 PyObject *codelike;
400 int offset;
401 PyObject *exception;
402 if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &exception)) {
403 return NULL;
404 }
405 NULLABLE(exception);
406 PyMonitoringState *state = setup_fire(codelike, offset, exception);
407 if (state == NULL) {
408 return NULL;
409 }
410 int res = PyMonitoring_FirePyUnwindEvent(state, codelike, offset);
411 RETURN_INT(teardown_fire(res, state, exception));
412 }
413
414 static PyObject *
fire_event_stop_iteration(PyObject * self,PyObject * args)415 fire_event_stop_iteration(PyObject *self, PyObject *args)
416 {
417 PyObject *codelike;
418 int offset;
419 PyObject *value;
420 if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &value)) {
421 return NULL;
422 }
423 NULLABLE(value);
424 PyObject *exception = NULL;
425 PyMonitoringState *state = setup_fire(codelike, offset, exception);
426 if (state == NULL) {
427 return NULL;
428 }
429 int res = PyMonitoring_FireStopIterationEvent(state, codelike, offset, value);
430 RETURN_INT(teardown_fire(res, state, exception));
431 }
432
433 /*******************************************************************/
434
435 static PyObject *
enter_scope(PyObject * self,PyObject * args)436 enter_scope(PyObject *self, PyObject *args)
437 {
438 PyObject *codelike;
439 int event1, event2=0;
440 Py_ssize_t num_events = PyTuple_Size(args) - 1;
441 if (num_events == 1) {
442 if (!PyArg_ParseTuple(args, "Oi", &codelike, &event1)) {
443 return NULL;
444 }
445 }
446 else {
447 assert(num_events == 2);
448 if (!PyArg_ParseTuple(args, "Oii", &codelike, &event1, &event2)) {
449 return NULL;
450 }
451 }
452 RAISE_UNLESS_CODELIKE(codelike);
453 PyCodeLikeObject *cl = (PyCodeLikeObject *) codelike;
454
455 uint8_t events[] = { event1, event2 };
456
457 PyMonitoring_EnterScope(cl->monitoring_states,
458 &cl->version,
459 events,
460 num_events);
461
462 Py_RETURN_NONE;
463 }
464
465 static PyObject *
exit_scope(PyObject * self,PyObject * args)466 exit_scope(PyObject *self, PyObject *args)
467 {
468 PyMonitoring_ExitScope();
469 Py_RETURN_NONE;
470 }
471
472 static PyMethodDef TestMethods[] = {
473 {"fire_event_py_start", fire_event_py_start, METH_VARARGS},
474 {"fire_event_py_resume", fire_event_py_resume, METH_VARARGS},
475 {"fire_event_py_return", fire_event_py_return, METH_VARARGS},
476 {"fire_event_c_return", fire_event_c_return, METH_VARARGS},
477 {"fire_event_py_yield", fire_event_py_yield, METH_VARARGS},
478 {"fire_event_call", fire_event_call, METH_VARARGS},
479 {"fire_event_line", fire_event_line, METH_VARARGS},
480 {"fire_event_jump", fire_event_jump, METH_VARARGS},
481 {"fire_event_branch", fire_event_branch, METH_VARARGS},
482 {"fire_event_py_throw", fire_event_py_throw, METH_VARARGS},
483 {"fire_event_raise", fire_event_raise, METH_VARARGS},
484 {"fire_event_c_raise", fire_event_c_raise, METH_VARARGS},
485 {"fire_event_reraise", fire_event_reraise, METH_VARARGS},
486 {"fire_event_exception_handled", fire_event_exception_handled, METH_VARARGS},
487 {"fire_event_py_unwind", fire_event_py_unwind, METH_VARARGS},
488 {"fire_event_stop_iteration", fire_event_stop_iteration, METH_VARARGS},
489 {"monitoring_enter_scope", enter_scope, METH_VARARGS},
490 {"monitoring_exit_scope", exit_scope, METH_VARARGS},
491 {NULL},
492 };
493
494 int
_PyTestCapi_Init_Monitoring(PyObject * m)495 _PyTestCapi_Init_Monitoring(PyObject *m)
496 {
497 if (PyType_Ready(&PyCodeLike_Type) < 0) {
498 return -1;
499 }
500 if (PyModule_AddObjectRef(m, "CodeLike", (PyObject *) &PyCodeLike_Type) < 0) {
501 Py_DECREF(m);
502 return -1;
503 }
504 if (PyModule_AddFunctions(m, TestMethods) < 0) {
505 return -1;
506 }
507 return 0;
508 }
509