|
12 | 12 | #include "clinic/codeobject.c.h" |
13 | 13 |
|
14 | 14 |
|
| 15 | +static void |
| 16 | +notify_code_watchers(PyCodeEvent event, PyCodeObject *co) |
| 17 | +{ |
| 18 | + PyInterpreterState *interp = _PyInterpreterState_GET(); |
| 19 | + assert(interp->_initialized); |
| 20 | + for (int i = 0; i < CODE_MAX_WATCHERS; i++) { |
| 21 | + PyCode_WatchCallback cb = interp->code_watchers[i]; |
| 22 | + if ((cb != NULL) && (cb(event, co) < 0)) { |
| 23 | + PyErr_WriteUnraisable((PyObject *) co); |
| 24 | + } |
| 25 | + } |
| 26 | +} |
| 27 | + |
| 28 | +int |
| 29 | +PyCode_AddWatcher(PyCode_WatchCallback callback) |
| 30 | +{ |
| 31 | + PyInterpreterState *interp = _PyInterpreterState_GET(); |
| 32 | + assert(interp->_initialized); |
| 33 | + |
| 34 | + for (int i = 0; i < CODE_MAX_WATCHERS; i++) { |
| 35 | + if (!interp->code_watchers[i]) { |
| 36 | + interp->code_watchers[i] = callback; |
| 37 | + return i; |
| 38 | + } |
| 39 | + } |
| 40 | + |
| 41 | + PyErr_SetString(PyExc_RuntimeError, "no more code watcher IDs available"); |
| 42 | + return -1; |
| 43 | +} |
| 44 | + |
| 45 | +static inline int |
| 46 | +validate_watcher_id(PyInterpreterState *interp, int watcher_id) |
| 47 | +{ |
| 48 | + if (watcher_id < 0 || watcher_id >= CODE_MAX_WATCHERS) { |
| 49 | + PyErr_Format(PyExc_ValueError, "Invalid code watcher ID %d", watcher_id); |
| 50 | + return -1; |
| 51 | + } |
| 52 | + if (!interp->code_watchers[watcher_id]) { |
| 53 | + PyErr_Format(PyExc_ValueError, "No code watcher set for ID %d", watcher_id); |
| 54 | + return -1; |
| 55 | + } |
| 56 | + return 0; |
| 57 | +} |
| 58 | + |
| 59 | +int |
| 60 | +PyCode_ClearWatcher(int watcher_id) |
| 61 | +{ |
| 62 | + PyInterpreterState *interp = _PyInterpreterState_GET(); |
| 63 | + assert(interp->_initialized); |
| 64 | + if (validate_watcher_id(interp, watcher_id) < 0) { |
| 65 | + return -1; |
| 66 | + } |
| 67 | + interp->code_watchers[watcher_id] = NULL; |
| 68 | + return 0; |
| 69 | +} |
| 70 | + |
15 | 71 | /****************** |
16 | 72 | * generic helpers |
17 | 73 | ******************/ |
@@ -355,6 +411,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) |
355 | 411 | } |
356 | 412 | co->_co_firsttraceable = entry_point; |
357 | 413 | _PyCode_Quicken(co); |
| 414 | + notify_code_watchers(PY_CODE_EVENT_CREATE, co); |
358 | 415 | } |
359 | 416 |
|
360 | 417 | static int |
@@ -1615,6 +1672,8 @@ code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount, |
1615 | 1672 | static void |
1616 | 1673 | code_dealloc(PyCodeObject *co) |
1617 | 1674 | { |
| 1675 | + notify_code_watchers(PY_CODE_EVENT_DESTROY, co); |
| 1676 | + |
1618 | 1677 | if (co->co_extra != NULL) { |
1619 | 1678 | PyInterpreterState *interp = _PyInterpreterState_GET(); |
1620 | 1679 | _PyCodeObjectExtra *co_extra = co->co_extra; |
|
0 commit comments