>From 984109b9b204c82ce2e6482210425a70b7b7e867 Mon Sep 17 00:00:00 2001 From: Noam Postavsky Date: Sun, 13 Dec 2015 14:47:58 -0500 Subject: [PATCH v6 6/6] Document watchpoints * doc/lispref/debugging.texi (Variable Debugging): * doc/lispref/variables.texi (Watching Variables): New section. * etc/NEWS: Add entry for watchpoints --- doc/lispref/debugging.texi | 32 +++++++++++++++++++++++ doc/lispref/variables.texi | 63 ++++++++++++++++++++++++++++++++++++++++++++++ etc/NEWS | 5 ++++ src/data.c | 9 +++++++ 4 files changed, 109 insertions(+) diff --git a/doc/lispref/debugging.texi b/doc/lispref/debugging.texi index 6c0908a..8cae203 100644 --- a/doc/lispref/debugging.texi +++ b/doc/lispref/debugging.texi @@ -69,6 +69,7 @@ Debugger * Error Debugging:: Entering the debugger when an error happens. * Infinite Loops:: Stopping and debugging a program that doesn't exit. * Function Debugging:: Entering it when a certain function is called. +* Variable Debugging:: Entering it when a variable is modified. * Explicit Debug:: Entering it at a certain point in the program. * Using Debugger:: What the debugger does; what you see while in it. * Debugger Commands:: Commands used while in the debugger. @@ -290,6 +291,37 @@ Function Debugging not currently set up to break on entry. @end deffn +@node Variable Debugging +@subsection Entering the debugger when a variable is modified +@cindex variable write debugging +@cindex debugging changes to variables + +Sometimes a problem with a function is due to a wrong setting of a +variable. Setting up the debugger to trigger whenever the variable is +changed is quick way to find the origin of the setting. + +@deffn Command debug-on-variable-change variable +This function arranges causes the debugger to be called whenever +@var{variable} is modified. + +It is implemented using the watchpoint mechanism, so it inherits the +same characteristics and limitations: all aliases of @var{variable} +will be watched together, only dynamic variables can be watched, and +changes to the objects referenced by variables are not detected. For +details, see @xref{Watching Variables}. + +@end deffn + +@deffn Command cancel-debug-on-variable-change &optional variable +This function undoes the effect of @code{debug-on-variable-change} on +@var{variable}. When called interactively, it prompts for +@var{variable} in the minibuffer. If @var{variable} is omitted or +@code{nil}, it cancels break-on-change for all variables. Calling +@code{cancel-debug-on-variable-change} does nothing to a variable +which is not currently set up to break on change. +@end deffn + + @node Explicit Debug @subsection Explicit Entry to the Debugger @cindex debugger, explicit entry diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi index 418a416..07f787c 100644 --- a/doc/lispref/variables.texi +++ b/doc/lispref/variables.texi @@ -34,6 +34,7 @@ Variables * Accessing Variables:: Examining values of variables whose names are known only at run time. * Setting Variables:: Storing new values in variables. +* Watching Variables:: Running a function when a variable is changed. * Variable Scoping:: How Lisp chooses among local and global values. * Buffer-Local Variables:: Variable values in effect only in one buffer. * File Local Variables:: Handling local variable lists in files. @@ -765,6 +766,68 @@ Setting Variables @end example @end defun +@node Watching Variables +@section Running a function when a variable is changed. +@cindex variable watchpoints + +It is sometimes useful to take some action when a variable changes its +value. The watchpoint facility provides the means to do so. Some +possible uses for this feature include keeping display in sync with +variable settings, and invoking the debugger to track down unexpected +changes to variables @pxref{Variable Debugging}. + +Each variable has a list of watch functions stored in its +@code{watchers} symbol property, @xref{Symbol Properties}. However, +for efficiency reasons, the list is only consulted if symbol is marked +as watched. Therefore, the watch function list should only be +manipulated by the following functions, which take care of the +symbol's watched status in addition to the property value. + +@defun add-variable-watcher symbol watch-function +This function arranges for @var{watch-function} to be called whenever +@var{symbol} (or any of its aliases @pxref{Variable Aliases}) are +modified. + +It will be called with 4 arguments: (@var{symbol} @var{newval} +@var{operation} @var{where}). + +@var{symbol} is the variable being changed. +@var{newval} is the value it will be changed to. +@var{operation} is a symbol representing the kind of change, one of: +`set', `let', `unlet', `makunbound', and `defvaralias'. +@var{where} is a buffer if the buffer-local value of the variable +being changed, nil otherwise. +@end defun + +@defun remove-variable-watch symbol watch-function +This function removes @var{watch-function} from @var{symbol}'s list of +watchers. +@end defun + +@defun get-variable-watchers symbol +This function returns the list of active watcher functions. +@end defun + +@subsection Limitations + +There are a couple of ways in which a variable could be modifed (or at +least appear to be modified) without triggering a watchpoint. + +Since the watchpoint are attached to symbols, modification to the +objects contained within variables (e.g., by a list modification +function @pxref{Modifying Lists}) is not caught by this mechanism. + +Additionally, C code can modify the value of variables directly, +bypassing the watchpoint mechanism. + +A minor limitation of this feature, again because it targets symbols, +is that only variables of dynamic scope may be watched. This poses +little difficulty, since modifications to lexical variables can be +discovered easily by inspecting the code within the scope of the +variable (unlike dynamic variables which can be modified by any code +at all, @pxref{Variable Scoping}). + + @node Variable Scoping @section Scoping Rules for Variable Bindings @cindex scoping rule diff --git a/etc/NEWS b/etc/NEWS index e29dfe2..fcbbb44 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -627,6 +627,11 @@ consistency with the new functions. For compatibility, 'sxhash' remains as an alias to 'sxhash-equal'. +++ +** New function `add-variable-watcher' can be used to call a function +when a symbol's value is changed. This is used to implement the new +debugger command `debug-on-variable-change'. + ++++ ** Time conversion functions that accept a time zone rule argument now allow it to be OFFSET or a list (OFFSET ABBR), where the integer OFFSET is a count of seconds east of Universal Time, and the string diff --git a/src/data.c b/src/data.c index ff35315..ef6b48b 100644 --- a/src/data.c +++ b/src/data.c @@ -1428,6 +1428,15 @@ harmonize_variable_watchers (Lisp_Object alias, Lisp_Object base_variable) DEFUN ("add-variable-watcher", Fadd_variable_watcher, Sadd_variable_watcher, 2, 2, 0, doc: /* Cause WATCH-FUNCTION to be called when SYMBOL is set. + +It will be called with 4 arguments: (SYMBOL NEWVAL OPERATION WHERE). +SYMBOL is the variable being changed. +NEWVAL is the value it will be changed to. +OPERATION is a symbol representing the kind of change, one of: `set', +`let', `unlet', `makunbound', and `defvaralias'. +WHERE is a buffer if the buffer-local value of the variable being +changed, nil otherwise. + All writes to aliases of SYMBOL will call WATCH-FUNCTION too. */) (Lisp_Object symbol, Lisp_Object watch_function) { -- 2.9.3