mirror of https://github.com/python/cpython
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
This commit is contained in:
parent
aa8591e9ca
commit
ae83c78215
|
@ -142,7 +142,6 @@ struct _is {
|
||||||
// Initialized to _PyEval_EvalFrameDefault().
|
// Initialized to _PyEval_EvalFrameDefault().
|
||||||
_PyFrameEvalFunction eval_frame;
|
_PyFrameEvalFunction eval_frame;
|
||||||
|
|
||||||
PyDict_WatchCallback dict_watchers[DICT_MAX_WATCHERS];
|
|
||||||
PyFunction_WatchCallback func_watchers[FUNC_MAX_WATCHERS];
|
PyFunction_WatchCallback func_watchers[FUNC_MAX_WATCHERS];
|
||||||
// One bit is set for each non-NULL entry in func_watchers
|
// One bit is set for each non-NULL entry in func_watchers
|
||||||
uint8_t active_func_watchers;
|
uint8_t active_func_watchers;
|
||||||
|
|
|
@ -630,14 +630,16 @@ static PyMethodDef test_methods[] = {
|
||||||
{"clear_dict_watcher", clear_dict_watcher, METH_O, NULL},
|
{"clear_dict_watcher", clear_dict_watcher, METH_O, NULL},
|
||||||
{"watch_dict", watch_dict, METH_VARARGS, NULL},
|
{"watch_dict", watch_dict, METH_VARARGS, NULL},
|
||||||
{"unwatch_dict", unwatch_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.
|
// Type watchers.
|
||||||
{"add_type_watcher", add_type_watcher, METH_O, NULL},
|
{"add_type_watcher", add_type_watcher, METH_O, NULL},
|
||||||
{"clear_type_watcher", clear_type_watcher, METH_O, NULL},
|
{"clear_type_watcher", clear_type_watcher, METH_O, NULL},
|
||||||
{"watch_type", watch_type, METH_VARARGS, NULL},
|
{"watch_type", watch_type, METH_VARARGS, NULL},
|
||||||
{"unwatch_type", unwatch_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.
|
// Code object watchers.
|
||||||
{"add_code_watcher", add_code_watcher, METH_O, NULL},
|
{"add_code_watcher", add_code_watcher, METH_O, NULL},
|
||||||
|
|
|
@ -15,14 +15,21 @@ static void
|
||||||
notify_code_watchers(PyCodeEvent event, PyCodeObject *co)
|
notify_code_watchers(PyCodeEvent event, PyCodeObject *co)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
if (interp->active_code_watchers) {
|
assert(interp->_initialized);
|
||||||
assert(interp->_initialized);
|
uint8_t bits = interp->active_code_watchers;
|
||||||
for (int i = 0; i < CODE_MAX_WATCHERS; i++) {
|
int i = 0;
|
||||||
|
while (bits) {
|
||||||
|
assert(i < CODE_MAX_WATCHERS);
|
||||||
|
if (bits & 1) {
|
||||||
PyCode_WatchCallback cb = interp->code_watchers[i];
|
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);
|
PyErr_WriteUnraisable((PyObject *) co);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
i++;
|
||||||
|
bits >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,20 @@ static void
|
||||||
notify_func_watchers(PyInterpreterState *interp, PyFunction_WatchEvent event,
|
notify_func_watchers(PyInterpreterState *interp, PyFunction_WatchEvent event,
|
||||||
PyFunctionObject *func, PyObject *new_value)
|
PyFunctionObject *func, PyObject *new_value)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < FUNC_MAX_WATCHERS; i++) {
|
uint8_t bits = interp->active_func_watchers;
|
||||||
PyFunction_WatchCallback cb = interp->func_watchers[i];
|
int i = 0;
|
||||||
if ((cb != NULL) && (cb(event, func, new_value) < 0)) {
|
while (bits) {
|
||||||
PyErr_WriteUnraisable((PyObject *) func);
|
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)
|
PyObject *new_value)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
|
assert(interp->_initialized);
|
||||||
if (interp->active_func_watchers) {
|
if (interp->active_func_watchers) {
|
||||||
notify_func_watchers(interp, event, func, new_value);
|
notify_func_watchers(interp, event, func, new_value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -485,23 +485,24 @@ PyType_Modified(PyTypeObject *type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify registered type watchers, if any
|
||||||
if (type->tp_watched) {
|
if (type->tp_watched) {
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
int bits = type->tp_watched;
|
int bits = type->tp_watched;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(bits && i < TYPE_MAX_WATCHERS) {
|
while (bits) {
|
||||||
|
assert(i < TYPE_MAX_WATCHERS);
|
||||||
if (bits & 1) {
|
if (bits & 1) {
|
||||||
PyType_WatchCallback cb = interp->type_watchers[i];
|
PyType_WatchCallback cb = interp->type_watchers[i];
|
||||||
if (cb && (cb(type) < 0)) {
|
if (cb && (cb(type) < 0)) {
|
||||||
PyErr_WriteUnraisable((PyObject *)type);
|
PyErr_WriteUnraisable((PyObject *)type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i += 1;
|
i++;
|
||||||
bits >>= 1;
|
bits >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
|
type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
|
||||||
type->tp_version_tag = 0; /* 0 is not a valid version tag */
|
type->tp_version_tag = 0; /* 0 is not a valid version tag */
|
||||||
}
|
}
|
||||||
|
|
|
@ -461,6 +461,10 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
|
||||||
interp->dict_state.watchers[i] = NULL;
|
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++) {
|
for (int i=0; i < FUNC_MAX_WATCHERS; i++) {
|
||||||
interp->func_watchers[i] = NULL;
|
interp->func_watchers[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue