Changeset 13104
- Timestamp:
- Oct 27, 2009, 9:26:15 AM (15 years ago)
- File:
-
- 1 edited
-
trunk/source/doc/src/using.xml (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/source/doc/src/using.xml
r12432 r13104 1922 1922 </refentry> 1923 1923 </sect1> 1924 1925 <sect1 id="watched-objects"><title>Watched Objects</title> 1926 <para> 1927 As of release 1.4, Clozure CL provides a way for lisp objects to 1928 be watched so that a condition will be signaled when a thread 1929 attempts to write to the watched object. For a certain class of 1930 bugs (someone is changing this value, but I don't know who), this 1931 can be extremely helpful. 1932 </para> 1933 <sect2 id="watched-watch"><title>WATCH</title> 1934 <refentry id="f_watch"> 1935 <indexterm zone="f_watch"> 1936 <primary>watch</primary> 1937 </indexterm> 1938 1939 <refnamediv> 1940 <refname>WATCH</refname> 1941 <refpurpose> 1942 Monitor a lisp object for writes. 1943 </refpurpose> 1944 <refclass>Function</refclass> 1945 </refnamediv> 1946 1947 <refsynopsisdiv> 1948 <synopsis><function>watch</function> &optional; object</synopsis> 1949 </refsynopsisdiv> 1950 1951 <refsect1> 1952 <title>Arguments and Values</title> 1953 <variablelist> 1954 <varlistentry> 1955 <term>object</term> 1956 <listitem> 1957 <para> 1958 Any memory-allocated lisp object. 1959 </para> 1960 </listitem> 1961 </varlistentry> 1962 </variablelist> 1963 </refsect1> 1964 1965 <refsect1> 1966 <title>Description</title> 1967 <para> 1968 The WATCH function arranges for the specified object to be 1969 monitored for writes. This is accomplished by copying the 1970 object to its own set of virtual memory pages, which are then 1971 write-protected. This protection is enforced by the computer's 1972 memory-management hardware; the write-protection does not slow 1973 down reads at all. 1974 </para> 1975 <para> 1976 When any write to the object is attempted, a 1977 WRITE-TO-WATCHED-OBJECT condition will be signaled. 1978 </para> 1979 <para> 1980 When called with no arguments, WATCH returns a freshly-consed 1981 list of the objects currently being watched. 1982 </para> 1983 <para> 1984 WATCH returns NIL if the object cannot be watched (typically 1985 because the object is in a static or pure memory area). 1986 </para> 1987 </refsect1> 1988 <refsect1 id="watch-dwim"><title>DWIM</title> 1989 <para> 1990 WATCH operates at a fairly low level; it is not possible to 1991 avoid the details of the internal representation of objects. 1992 Nevertheless, as a convenience, WATCHing a standard-instance, 1993 a hash-table, or a multi-dimensional or non-simple CL array 1994 will watch the underlying slot-vector, hash-table-vector, or 1995 data-vector, respectively. 1996 </para> 1997 </refsect1> 1998 <refsect1 id="watch-discuss"><title>Discussion</title> 1999 <para> 2000 WATCH can monitor any memory-allocated lisp object. 2001 </para> 2002 <para> 2003 In Clozure CL, a memory-allocated object is either a cons cell 2004 or a uvector. 2005 </para> 2006 <para> 2007 WATCH operates on cons cells, not lists. In order to watch a 2008 chain of cons cells, each cons cell must be watched 2009 individually. Because each watched cons cell takes up its own 2010 own virtual memory page (4 Kbytes), it's only feasible to watch 2011 relatively short lists. 2012 </para> 2013 <para> 2014 If a memory-allocated object isn't a cons cell, then it is a 2015 vector-like object called a uvector. A uvector is a 2016 memory-allocated lisp object whose first word is a header that 2017 describes the object's type and the number of elements that it 2018 contains. 2019 </para> 2020 <para> 2021 So, a hash table is a uvector, as is a string, a standard 2022 instance, a double-float, a CL array or vector, and so forth. 2023 </para> 2024 <para> 2025 Some CL objects, like strings and other simple vectors, map in a 2026 straightforward way onto the uvector representation. It is easy 2027 to understand what happens in such cases. The uvector index 2028 corresponds directly to the vector index: 2029 </para> 2030 <programlisting> 2031 <![CDATA[ 2032 ? (defvar *s* "xxxxx") 2033 *S* 2034 ? (watch *s*) 2035 "xxxxx" 2036 ? (setf (char *s* 3) #\o) 2037 > Error: Write to watched uvector "xxxxx" at index 3 2038 > Faulting instruction: (movl (% eax) (@ -5 (% r15) (% rcx))) 2039 > While executing: SET-CHAR, in process listener(1). 2040 > Type :POP to abort, :R for a list of available restarts. 2041 > Type :? for other options. 2042 ]]> 2043 </programlisting> 2044 <para> 2045 In the case of more complicated objects (e.g., a hash-table, a 2046 standard-instance, a package, etc.), the elements of the uvector 2047 are like slots in a structure. It's necessary to know which one 2048 of those "slots" contains the data that will be changed when the 2049 object is written to. 2050 </para> 2051 <para> 2052 As mentioned above, watch knows about arrays, hash-tables, and 2053 standard-instances, and will automatically watch the appropriate 2054 data-containing element. 2055 </para> 2056 <para> 2057 An example might make this clearer. 2058 </para> 2059 <programlisting> 2060 <![CDATA[ 2061 ? (defclass foo () 2062 (slot-a slot-b slot-c)) 2063 #<STANDARD-CLASS FOO> 2064 ? (defvar *a-foo* (make-instance 'foo)) 2065 *A-FOO* 2066 ? (watch *a-foo*) 2067 #<SLOT-VECTOR #xDB00D> 2068 ;;; Note that WATCH has watched the internal slot-vector object 2069 ? (setf (slot-value *a-foo* 'slot-a) 'foo) 2070 > Error: Write to watched uvector #<SLOT-VECTOR #xDB00D> at index 1 2071 > Faulting instruction: (movq (% rsi) (@ -5 (% r8) (% rdi))) 2072 > While executing: %MAYBE-STD-SETF-SLOT-VALUE-USING-CLASS, in process listener(1). 2073 > Type :POP to abort, :R for a list of available restarts. 2074 > Type :? for other options. 2075 ]]> 2076 </programlisting> 2077 <para> 2078 Looking at a backtrace would presumably show what object and 2079 slot name were written. 2080 </para> 2081 <para> 2082 Note that even though the write was to slot-a, the uvector index 2083 was 1 (not 0). This is because the first element of a 2084 slot-vector is a pointer to the instance that owns the slots. We 2085 can retrieve that to look at the object that was modified: 2086 </para> 2087 <programlisting> 2088 <![CDATA[ 2089 1 > (uvref (write-to-watched-object-object *break-condition*) 0) 2090 #<FOO #x30004113502D> 2091 1 > (describe *) 2092 #<FOO #x30004113502D> 2093 Class: #<STANDARD-CLASS FOO> 2094 Wrapper: #<CLASS-WRAPPER FOO #x300041135EBD> 2095 Instance slots 2096 SLOT-A: #<Unbound> 2097 SLOT-B: #<Unbound> 2098 SLOT-C: #<Unbound> 2099 1 > 2100 ]]> 2101 </programlisting> 2102 </refsect1> 2103 </refentry> 2104 </sect2> 2105 <sect2 id="watched-unwatch"><title>UNWATCH</title> 2106 <refentry id="f_unwatch"> 2107 <indexterm zone="f_unwatch"> 2108 <primary>unwatch</primary> 2109 </indexterm> 2110 2111 <refnamediv> 2112 <refname>UNWATCH</refname> 2113 <refpurpose> 2114 Stop monitoring a lisp object for writes. 2115 </refpurpose> 2116 <refclass>Function</refclass> 2117 </refnamediv> 2118 2119 <refsynopsisdiv> 2120 <synopsis><function>unwatch</function> object</synopsis> 2121 </refsynopsisdiv> 2122 2123 <refsect1><title>Description</title> 2124 <para> 2125 The UNWATCH function ensures that the specified object is in 2126 normal, non-monitored memory. If the object is not currently 2127 being watched, UNWATCH does nothing and returns NIL. Otherwise, 2128 the newly unwatched object is returned. 2129 </para> 2130 </refsect1> 2131 </refentry> 2132 </sect2> 2133 <sect2 id="watched-write-to-watched-object"> 2134 <title>WRITE-TO-WATCHED-OBJECT</title> 2135 <refentry id="c_write-to-watched-object"> 2136 <indexterm zone="c_write-to-watched-object"> 2137 <primary>write-to-watched-object</primary> 2138 </indexterm> 2139 2140 <refnamediv> 2141 <refname>WRITE-TO-WATCHED-OBJECT</refname> 2142 <refpurpose> 2143 Condition signaled when a write to a watched object is attempted. 2144 </refpurpose> 2145 <refclass>Condition</refclass> 2146 </refnamediv> 2147 2148 <refsect1><title>Discussion</title> 2149 <para> 2150 This condition is signaled when a watched object is written 2151 to. There are three slots of interest: 2152 </para> 2153 <variablelist> 2154 <varlistentry> 2155 <term>object</term> 2156 <listitem> 2157 <para> 2158 The actual object that was the destination of the write. 2159 </para> 2160 </listitem> 2161 </varlistentry> 2162 <varlistentry> 2163 <term>offset</term> 2164 <listitem> 2165 <para> 2166 The byte offset from the tagged object pointer to the 2167 address of the write. 2168 </para> 2169 </listitem> 2170 </varlistentry> 2171 <varlistentry> 2172 <term>instruction</term> 2173 <listitem> 2174 <para> 2175 The disassembled machine instruction that attempted the write. 2176 </para> 2177 </listitem> 2178 </varlistentry> 2179 </variablelist> 2180 </refsect1> 2181 2182 <refsect1><title>Restarts</title> 2183 <para> 2184 A few restarts are provided: one will skip over the faulting 2185 write instruction and proceed; another offers to unwatch the 2186 object and continue. 2187 </para> 2188 <para> 2189 There is also an emulate restart. In some common cases, the 2190 faulting write instruction can be emulated, enabling the write 2191 to be performed without having to unwatch the object (and 2192 therefore let other threads potentially write to it). If the 2193 faulting instruction isn't recognized, the emulate restart will 2194 not be offered. 2195 </para> 2196 </refsect1> 2197 </refentry> 2198 </sect2> 2199 <sect2 id="watch-notes"><title>Notes</title> 2200 <para> 2201 Although some care has been taken to minimize potential problems 2202 arising from watching and unwatching objects from multiple 2203 threads, there may well be subtle race conditions present that 2204 could cause bad behavior. 2205 </para> 2206 <para> 2207 For example, suppose that a thread attempts to write to a watched 2208 object. This causes the operating system to generate an 2209 exception. The lisp kernel figures out what the exception is, and 2210 calls back into lisp to signal the write-to-watched-object 2211 condition and perhaps handle the error. 2212 </para> 2213 <para> 2214 Now, as soon lisp code starts running again (for the callback), 2215 it's possible that some other thread could unwatch the very 2216 watched object that caused the exception, perhaps before we even 2217 have a chance to signal the condition, much less respond to it. 2218 </para> 2219 <para> 2220 Having the object unwatched out from underneath a handler may at 2221 least confuse it, if not cause deeper trouble. Use caution with 2222 unwatch. 2223 </para> 2224 </sect2> 2225 <sect2 id="watch-examples"><title>Examples</title> 2226 <para> 2227 Here are a couple more examples in addition to the above examples 2228 of watching a string and a standard-instance. 2229 </para> 2230 <sect3><title>Fancy arrays</title> 2231 <programlisting> 2232 ? (defvar *f* (make-array '(2 3) :element-type 'double-float)) 2233 *F* 2234 ? (watch *f*) 2235 #(0.0D0 0.0D0 0.0D0 0.0D0 0.0D0 0.0D0) 2236 ;;; Note that the above vector is the underlying data-vector for the array 2237 ? (setf (aref *f* 1 2) pi) 2238 > Error: Write to watched uvector #<VECTOR 6 type DOUBLE-FLOAT, simple> at index 5 2239 > Faulting instruction: (movq (% rax) (@ -5 (% r8) (% rdi))) 2240 > While executing: ASET, in process listener(1). 2241 > Type :POP to abort, :R for a list of available restarts. 2242 > Type :? for other options. 2243 1 > 2244 </programlisting> 2245 <para> 2246 In this case, uvector index in the report is the row-major index 2247 of the element that was written to. 2248 </para> 2249 </sect3> 2250 <sect3><title>Hash tables</title> 2251 <para> 2252 Hash tables are surprisingly complicated. The representation of a 2253 hash table includes an element called a hash-table-vector. The 2254 keys and values of the elements are stored pairwise in this 2255 vector. 2256 </para> 2257 <para> 2258 One problem with trying to monitor hash tables for writes is that 2259 the underlying hash-table-vector is replaced with an entirely new 2260 one when the hash table is rehashed. A previously-watched 2261 hash-table-vector will not be the used by the hash table after 2262 rehashing, and writes to the new vector will not be caught. 2263 </para> 2264 <programlisting> 2265 ? (defvar *h* (make-hash-table)) 2266 *H* 2267 ? (setf (gethash 'noise *h*) 'feep) 2268 FEEP 2269 ? (watch *h*) 2270 #<HASH-TABLE-VECTOR #xDD00D> 2271 ;;; underlying hash-table-vector 2272 ? (setf (gethash 'noise *h*) 'ding) 2273 > Error: Write to watched uvector #<HASH-TABLE-VECTOR #xDD00D> at index 35 2274 > Faulting instruction: (lock) 2275 > (cmpxchgq (% rsi) (@ (% r8) (% rdx))) 2276 > While executing: %STORE-NODE-CONDITIONAL, in process listener(1). 2277 > Type :POP to abort, :R for a list of available restarts. 2278 > Type :? for other options. 2279 ;;; see what value is being replaced... 2280 1 > (uvref (write-to-watched-object-object *break-condition*) 35) 2281 FEEP 2282 ;;; backtrace shows useful context 2283 1 > :b 2284 *(1A109F8) : 0 (%STORE-NODE-CONDITIONAL ???) NIL 2285 (1A10A50) : 1 (LOCK-FREE-PUTHASH NOISE #<HASH-TABLE :TEST EQL size 1/60 #x30004117D47D> DING) 653 2286 (1A10AC8) : 2 (CALL-CHECK-REGS PUTHASH NOISE #<HASH-TABLE :TEST EQL size 1/60 #x30004117D47D> DING) 229 2287 (1A10B00) : 3 (TOPLEVEL-EVAL (SETF (GETHASH # *H*) 'DING) NIL) 709 2288 ... 2289 </programlisting> 2290 </sect3> 2291 <sect3><title>Lists</title> 2292 <para> 2293 As previously mentioned, WATCH only watches individual cons cells. 2294 </para> 2295 <programlisting> 2296 ? (defun watch-list (list) 2297 (maplist #'watch list)) 2298 WATCH-LIST 2299 ? (defvar *l* (list 1 2 3)) 2300 *L* 2301 ? (watch-list *l*) 2302 ((1 2 3) (2 3) (3)) 2303 ? (setf (nth 2 *l*) 'foo) 2304 > Error: Write to the CAR of watched cons cell (3) 2305 > Faulting instruction: (movq (% rsi) (@ 5 (% rdi))) 2306 > While executing: %SETNTH, in process listener(1). 2307 > Type :POP to abort, :R for a list of available restarts. 2308 > Type :? for other options. 2309 </programlisting> 2310 </sect3> 2311 </sect2> 2312 </sect1> 1924 2313 </chapter>
Note:
See TracChangeset
for help on using the changeset viewer.
