1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%W weakptr.tex GAP documentation Steve Linton
%%
%H @(#)$Id: weakptr.tex,v 4.11.2.1 2006/03/07 14:46:25 sal Exp $
%%
%Y Copyright 1997, The GAP Project
%%
%% This file describes the use of weak pointers
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Chapter{Weak Pointers}
This chapter describes the use of the kernel feature of *weak pointers*. This
feature is intended for use only in {\GAP} internals, and is *not
recommended* for use in {\GAP} packages, user code, or at the higher levels
of the library.
The GASMAN garbage collector is the part of the kernel that manages memory in
the users workspace. It will normally only reclaim the storage used by an
object when the object cannot be reached as a subobject of any GAP variable,
or from any reference in the kernel. We say that any link to object <a> from
object <b> ``keeps object <a> alive'', as long as <b> is alive. It is
occasionally convenient, however to have a link to an object which *does not
keep it alive*, and this is a weak pointer. The most common use is in
caches, and similar structures, where it is only necessary to remember how to
solve problem x as long as some other link to x exists.
The following section "Weak Pointer Objects" describes the semantics of the
objects that contain weak pointers. Following sections describe the functions
available to manipulate them.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Weak Pointer Objects}
A *weak pointer object* is similar to a mutable plain list, except that it
does not keep its subobjects alive during a garbage collection. From the
{\GAP} viewpoint this means that its entries may become unbound, apparently
spontaneously, at any time. Considerable care is therefore needed in
programming with such an object.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{WeakPointerObj}\nolabel
\>WeakPointerObj( <list> )
`WeakPointerObj' returns a weak pointer object which contains the same
subobjects as <list>, that is it returns a *shallow* weak copy of <list>.
\beginexample
gap> w := WeakPointerObj( [ 1, , [2,3], fail, rec( a := 1) ] );
WeakPointerObj( [ 1, , [ 2, 3 ], fail, rec( a := 1 ) ] )
gap> GASMAN("collect");
gap> w;
WeakPointerObj( [ 1, , , fail ] )
\endexample
Note that `w' has failed to keep its list and record subobjects alive during
the garbage collection. Certain subobjects, such as small integers and
elements of small finite fields, are not stored in the workspace, and so are
not subject to garbage collection, while certain other objects, such as the
Boolean values, are always reachable from global variables or the kernel and
so are never garbage collected.
Subobjects reachable without going through a weak pointer object do not
evaporate, as in:
\beginexample
gap> l := [1,2,3];;
gap> w[1] := l;;
gap> w;
WeakPointerObj( [ [ 1, 2, 3 ], , , fail ] )
gap> GASMAN("collect");
gap> w;
WeakPointerObj( [ [ 1, 2, 3 ], , , fail ] )
\endexample
Note also that the global variables `last', `last2' and `last3' will keep
things alive -- this can be confusing when debugging.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Low Level Access Functions for Weak Pointer Objects}
\index{ElmWPObj}
\>SetElmWPObj(<wp>,<pos>,<val>)
\>UnbindElmWPObj(<wp>,<pos>)
\>ElmWPObj(<wp>, <pos>)
\>IsBOundElmWPObj(<wp>,<pos>)
\>LengthWPObj(<wp>)
The functions `SetElmWPObj(<wp>,<pos>,<val>)' and
`UnbindElmWPObj(<wp>,<pos>)' set and unbind entries in a weak pointer object.
The function `ElmWPObj(<wp>, <pos>)' returns the element at position <pos> of
the weak pointer object <wp>, if there is one, and `fail' otherwise. A return
value of `fail' can thus arise either because (a) the value `fail' is stored
at position <pos>, or (b) no value is stored at position <pos>. Since `fail'
cannot vanish in a garbage collection, these two cases can safely be
distinguished by a *subsequent* call to `IsBoundElmWPObj(<wp>,<pos>)', which
returns `true' if there is currently a value bound at position <pos> of <wp>
and `false' otherwise.
Note that it is *not* safe to write: `if IsBoundElmWpObj(w,i) then x:=
ElmWPObj(w,i); fi;' and treat `x' as reliably containing a value taken from
`w', as a badly timed garbage collection could leave `x' containing `fail'.
Instead use `x := ElmWPObj(w,i); if x \<> fail or IsBoundElmWPObj(w,i) then .
. .'.
\beginexample
gap> w := WeakPointerObj( [ 1, , [2,3], fail, rec() ] );
WeakPointerObj( [ 1, , [ 2, 3 ], fail, rec( ) ] )
gap> SetElmWPObj(w,5,[]);
gap> w;
WeakPointerObj( [ 1, , [ 2, 3 ], fail, [ ] ] )
gap> UnbindElmWPObj(w,1);
gap> w;
WeakPointerObj( [ , , [ 2, 3 ], fail, [ ] ] )
gap> ElmWPObj(w,3);
[ 2, 3 ]
gap> ElmWPObj(w,1);
fail
gap> 2;;3;;4;;GASMAN("collect"); # clear last etc.
gap> ElmWPObj(w,3);
fail
gap> w;
WeakPointerObj( [ , , , fail ] )
gap> ElmWPObj(w,4);
fail
gap> IsBoundElmWPObj(w,3);
false
gap> IsBoundElmWPObj(w,4);
true
\endexample
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Accessing Weak Pointer Objects as Lists}
Weak pointer objects are members of `ListsFamily' and the categories `IsList'
and `IsMutable'. Methods based on the low-level functions in the previous
section, are installed for the list access operations, enabling them to be
used as lists. However, it is *not recommended* that these be used in
programming. They are supplied mainly as a convenience for interactive
working, and may not be safe, since functions and methods for lists may
assume that after `IsBound(w[i])' returns true, access to `w[i]' is safe.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Copying Weak Pointer Objects}
A `ShallowCopy' method is installed, which makes a new weak pointer object
containing the same objects as the original.
It is possible to apply `StructuralCopy' to a weak pointer object, obtaining
a new weak pointer object containing copies of the objects in the original.
This *may not be safe* if a badly timed garbage collection occurs during
copying.
Applying `Immutable' to a weak pointer object produces an immutable plain
list containing immutable copies of the objects contained in the weak pointer
object. An immutable weak pointer object is a contradiction in terms.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{The GASMAN Interface for Weak Pointer Objects}
The key support for weak pointers is in `gasman.c' and `gasman.h'. This
document assumes familiarity with the rest of the operation of GASMAN. A
kernel type (tnum) of bags which are intended to act as weak pointers to
their subobjects must meet three conditions. Firstly, the marking function
installed for that tnum must use `MarkBagWeakly' for those subbags, rather
than `MARK_BAG'. Secondly, before any access to such a subbag, it must be
checked with `IS_WEAK_DEAD_BAG'. If that returns true, then the subbag has
evaporated in a recent garbage collection and must not be accessed. Typically
the reference to it should be removed. Thirdly, a *sweeping function* must be
installed for that tnum which copies the bag, removing all references to dead
weakly held subbags.
The files `weakptr.c' and `weakptr.h' use this interface to support weak
pointer objects. Other objects with weak behaviour could be implemented in a
similar way.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%E
|