[Python-checkins] GH-100000: Cleanup and polish various watchers code (GH-99998)
markshannon
webhook-mailer at python.org
Wed Dec 14 14:14:26 EST 2022
https://github.com/python/cpython/commit/ae83c782155ffe86830c3255e338f366e331ad30
commit: ae83c782155ffe86830c3255e338f366e331ad30
branch: main
author: Itamar Ostricher <itamarost at gmail.com>
committer: markshannon <mark at hotpy.org>
date: 2022-12-14T19:14:16Z
summary:
GH-100000: Cleanup and polish various watchers code (GH-99998)
* Initialize `type_watchers` array to `NULL`s
* Optimize code watchers notification
* Optimize func watchers notification
files:
M Include/internal/pycore_interp.h
M Modules/_testcapi/watchers.c
M Objects/codeobject.c
M Objects/funcobject.c
M Objects/typeobject.c
M Python/pystate.c
diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h
index ffda1351952d..0e3d46852f2e 100644
--- a/Include/internal/pycore_interp.h
+++ b/Include/internal/pycore_interp.h
@@ -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;
diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c
index 1d91c206f630..2e8fe1dbf786 100644
--- a/Modules/_testcapi/watchers.c
+++ b/Modules/_testcapi/watchers.c
@@ -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},
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index f455cc603aae..1e5a92270be8 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -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;
}
}
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index 9df06520586a..d5cf5b9277b3 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -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);
}
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index ae80f5a8fd88..2c3b39521a6d 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -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 */
}
diff --git a/Python/pystate.c b/Python/pystate.c
index ea3c22c5d71a..f52fc38b3586 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -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;
}
More information about the Python-checkins
mailing list