summaryrefslogtreecommitdiffstats
path: root/Objects/funcobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/funcobject.c')
-rw-r--r--Objects/funcobject.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index cab8000..bf97edc 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -3,10 +3,68 @@
#include "Python.h"
#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals()
+#include "pycore_function.h" // FUNC_MAX_WATCHERS
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_Occurred()
#include "structmember.h" // PyMemberDef
+static void
+notify_func_watchers(PyInterpreterState *interp, PyFunction_WatchEvent event,
+ PyFunctionObject *func, PyObject *new_value)
+{
+ for (int i = 0; i < FUNC_MAX_WATCHERS; i++) {
+ PyFunction_WatchCallback cb = interp->func_watchers[i];
+ if ((cb != NULL) && (cb(event, func, new_value) < 0)) {
+ PyErr_WriteUnraisable((PyObject *) func);
+ }
+ }
+}
+
+static inline void
+handle_func_event(PyFunction_WatchEvent event, PyFunctionObject *func,
+ PyObject *new_value)
+{
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ if (interp->active_func_watchers) {
+ notify_func_watchers(interp, event, func, new_value);
+ }
+}
+
+int
+PyFunction_AddWatcher(PyFunction_WatchCallback callback)
+{
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ assert(interp->_initialized);
+ for (int i = 0; i < FUNC_MAX_WATCHERS; i++) {
+ if (interp->func_watchers[i] == NULL) {
+ interp->func_watchers[i] = callback;
+ interp->active_func_watchers |= (1 << i);
+ return i;
+ }
+ }
+ PyErr_SetString(PyExc_RuntimeError, "no more func watcher IDs available");
+ return -1;
+}
+
+int
+PyFunction_ClearWatcher(int watcher_id)
+{
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ if (watcher_id < 0 || watcher_id >= FUNC_MAX_WATCHERS) {
+ PyErr_Format(PyExc_ValueError, "invalid func watcher ID %d",
+ watcher_id);
+ return -1;
+ }
+ if (!interp->func_watchers[watcher_id]) {
+ PyErr_Format(PyExc_ValueError, "no func watcher set for ID %d",
+ watcher_id);
+ return -1;
+ }
+ interp->func_watchers[watcher_id] = NULL;
+ interp->active_func_watchers &= ~(1 << watcher_id);
+ return 0;
+}
+
PyFunctionObject *
_PyFunction_FromConstructor(PyFrameConstructor *constr)
{
@@ -31,6 +89,7 @@ _PyFunction_FromConstructor(PyFrameConstructor *constr)
op->vectorcall = _PyFunction_Vectorcall;
op->func_version = 0;
_PyObject_GC_TRACK(op);
+ handle_func_event(PyFunction_EVENT_CREATE, op, NULL);
return op;
}
@@ -105,6 +164,7 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
op->vectorcall = _PyFunction_Vectorcall;
op->func_version = 0;
_PyObject_GC_TRACK(op);
+ handle_func_event(PyFunction_EVENT_CREATE, op, NULL);
return (PyObject *)op;
error:
@@ -196,6 +256,8 @@ PyFunction_SetDefaults(PyObject *op, PyObject *defaults)
PyErr_SetString(PyExc_SystemError, "non-tuple default args");
return -1;
}
+ handle_func_event(PyFunction_EVENT_MODIFY_DEFAULTS,
+ (PyFunctionObject *) op, defaults);
((PyFunctionObject *)op)->func_version = 0;
Py_XSETREF(((PyFunctionObject *)op)->func_defaults, defaults);
return 0;
@@ -236,6 +298,8 @@ PyFunction_SetKwDefaults(PyObject *op, PyObject *defaults)
"non-dict keyword only default args");
return -1;
}
+ handle_func_event(PyFunction_EVENT_MODIFY_KWDEFAULTS,
+ (PyFunctionObject *) op, defaults);
((PyFunctionObject *)op)->func_version = 0;
Py_XSETREF(((PyFunctionObject *)op)->func_kwdefaults, defaults);
return 0;
@@ -389,6 +453,7 @@ func_set_code(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
nclosure, nfree);
return -1;
}
+ handle_func_event(PyFunction_EVENT_MODIFY_CODE, op, value);
op->func_version = 0;
Py_XSETREF(op->func_code, Py_NewRef(value));
return 0;
@@ -468,6 +533,7 @@ func_set_defaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored
return -1;
}
+ handle_func_event(PyFunction_EVENT_MODIFY_DEFAULTS, op, value);
op->func_version = 0;
Py_XSETREF(op->func_defaults, Py_XNewRef(value));
return 0;
@@ -508,6 +574,7 @@ func_set_kwdefaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignor
return -1;
}
+ handle_func_event(PyFunction_EVENT_MODIFY_KWDEFAULTS, op, value);
op->func_version = 0;
Py_XSETREF(op->func_kwdefaults, Py_XNewRef(value));
return 0;
@@ -687,6 +754,7 @@ func_clear(PyFunctionObject *op)
static void
func_dealloc(PyFunctionObject *op)
{
+ handle_func_event(PyFunction_EVENT_DESTROY, op, NULL);
_PyObject_GC_UNTRACK(op);
if (op->func_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) op);