]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-100000: Cleanup and polish various watchers code (GH-99998)
authorItamar Ostricher <itamarost@gmail.com>
Wed, 14 Dec 2022 19:14:16 +0000 (11:14 -0800)
committerGitHub <noreply@github.com>
Wed, 14 Dec 2022 19:14:16 +0000 (19:14 +0000)
* Initialize `type_watchers` array to `NULL`s
* Optimize code watchers notification
* Optimize func watchers notification

Include/internal/pycore_interp.h
Modules/_testcapi/watchers.c
Objects/codeobject.c
Objects/funcobject.c
Objects/typeobject.c
Python/pystate.c

index ffda1351952d2aba7d9b0a3299ac08b1ee85f42f..0e3d46852f2e6d3c509f6f79834e805d074c3707 100644 (file)
@@ -142,7 +142,6 @@ struct _is {
     // Initialized to _PyEval_EvalFrameDefault().
     _PyFrameEvalFunction eval_frame;
 
-    PyDict_WatchCallback dict_watchers[DICT_MAX_WATCHERS];
     PyFunction_WatchCallback func_watchers[FUNC_MAX_WATCHERS];
     // One bit is set for each non-NULL entry in func_watchers
     uint8_t active_func_watchers;
index 1d91c206f630927dc120129d244aba7c0e442432..2e8fe1dbf78651a29151586bd9a8f016ed4c799a 100644 (file)
@@ -630,14 +630,16 @@ static PyMethodDef test_methods[] = {
     {"clear_dict_watcher",       clear_dict_watcher,      METH_O,       NULL},
     {"watch_dict",               watch_dict,              METH_VARARGS, NULL},
     {"unwatch_dict",             unwatch_dict,            METH_VARARGS, NULL},
-    {"get_dict_watcher_events",  get_dict_watcher_events, METH_NOARGS,  NULL},
+    {"get_dict_watcher_events",
+     (PyCFunction) get_dict_watcher_events,               METH_NOARGS,  NULL},
 
     // Type watchers.
     {"add_type_watcher",         add_type_watcher,        METH_O,       NULL},
     {"clear_type_watcher",       clear_type_watcher,      METH_O,       NULL},
     {"watch_type",               watch_type,              METH_VARARGS, NULL},
     {"unwatch_type",             unwatch_type,            METH_VARARGS, NULL},
-    {"get_type_modified_events", get_type_modified_events, METH_NOARGS, NULL},
+    {"get_type_modified_events",
+     (PyCFunction) get_type_modified_events,              METH_NOARGS, NULL},
 
     // Code object watchers.
     {"add_code_watcher",         add_code_watcher,        METH_O,       NULL},
index f455cc603aae9cc6bcebc22d57ddd8d0b143702b..1e5a92270be84e6a8b516d5bd3a9ae55dd2fc2e6 100644 (file)
@@ -15,14 +15,21 @@ static void
 notify_code_watchers(PyCodeEvent event, PyCodeObject *co)
 {
     PyInterpreterState *interp = _PyInterpreterState_GET();
-    if (interp->active_code_watchers) {
-        assert(interp->_initialized);
-        for (int i = 0; i < CODE_MAX_WATCHERS; i++) {
+    assert(interp->_initialized);
+    uint8_t bits = interp->active_code_watchers;
+    int i = 0;
+    while (bits) {
+        assert(i < CODE_MAX_WATCHERS);
+        if (bits & 1) {
             PyCode_WatchCallback cb = interp->code_watchers[i];
-            if ((cb != NULL) && (cb(event, co) < 0)) {
+            // callback must be non-null if the watcher bit is set
+            assert(cb != NULL);
+            if (cb(event, co) < 0) {
                 PyErr_WriteUnraisable((PyObject *) co);
             }
         }
+        i++;
+        bits >>= 1;
     }
 }
 
index 9df06520586ab71b5d943a0f59d8712a2eb025fd..d5cf5b9277b3f1a3569303b6fe4f3080343f0794 100644 (file)
@@ -12,11 +12,20 @@ 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);
+    uint8_t bits = interp->active_func_watchers;
+    int i = 0;
+    while (bits) {
+        assert(i < FUNC_MAX_WATCHERS);
+        if (bits & 1) {
+            PyFunction_WatchCallback cb = interp->func_watchers[i];
+            // callback must be non-null if the watcher bit is set
+            assert(cb != NULL);
+            if (cb(event, func, new_value) < 0) {
+                PyErr_WriteUnraisable((PyObject *) func);
+            }
         }
+        i++;
+        bits >>= 1;
     }
 }
 
@@ -25,6 +34,7 @@ handle_func_event(PyFunction_WatchEvent event, PyFunctionObject *func,
                   PyObject *new_value)
 {
     PyInterpreterState *interp = _PyInterpreterState_GET();
+    assert(interp->_initialized);
     if (interp->active_func_watchers) {
         notify_func_watchers(interp, event, func, new_value);
     }
index ae80f5a8fd88e0e9243215eb19af030400e62ea6..2c3b39521a6d9ffee550198a1b506be17c208947 100644 (file)
@@ -485,23 +485,24 @@ PyType_Modified(PyTypeObject *type)
         }
     }
 
+    // Notify registered type watchers, if any
     if (type->tp_watched) {
         PyInterpreterState *interp = _PyInterpreterState_GET();
         int bits = type->tp_watched;
         int i = 0;
-        while(bits && i < TYPE_MAX_WATCHERS) {
+        while (bits) {
+            assert(i < TYPE_MAX_WATCHERS);
             if (bits & 1) {
                 PyType_WatchCallback cb = interp->type_watchers[i];
                 if (cb && (cb(type) < 0)) {
                     PyErr_WriteUnraisable((PyObject *)type);
                 }
             }
-            i += 1;
+            i++;
             bits >>= 1;
         }
     }
 
-
     type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
     type->tp_version_tag = 0; /* 0 is not a valid version tag */
 }
index ea3c22c5d71ad6e248e1d12b78ea1d7a03c3b466..f52fc38b358689cb44c64c2e1b9d34b836349ce4 100644 (file)
@@ -461,6 +461,10 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
         interp->dict_state.watchers[i] = NULL;
     }
 
+    for (int i=0; i < TYPE_MAX_WATCHERS; i++) {
+        interp->type_watchers[i] = NULL;
+    }
+
     for (int i=0; i < FUNC_MAX_WATCHERS; i++) {
         interp->func_watchers[i] = NULL;
     }