Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-100000: Cleanup and polish various watchers code #99998

Merged
merged 7 commits into from
Dec 14, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,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;
Expand Down
6 changes: 4 additions & 2 deletions Modules/_testcapi/watchers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down
15 changes: 11 additions & 4 deletions Objects/codeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,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;
}
}

Expand Down
16 changes: 12 additions & 4 deletions Objects/funcobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,18 @@ 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];
if ((cb != NULL) && (cb(event, func, new_value) < 0)) {
itamaro marked this conversation as resolved.
Show resolved Hide resolved
PyErr_WriteUnraisable((PyObject *) func);
}
}
i++;
bits >>= 1;
}
}

Expand All @@ -25,6 +32,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);
}
Expand Down
7 changes: 4 additions & 3 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
}
Expand Down
4 changes: 4 additions & 0 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down