• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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