37 |
37 |
38 documentation |
38 documentation |
39 " |
39 " |
40 Registries provide an easy interface to using WeakArrays. |
40 Registries provide an easy interface to using WeakArrays. |
41 A class, which wants to be informed of instance-death, can put a created object |
41 A class, which wants to be informed of instance-death, can put a created object |
42 into a registry. The registry will create a (shallow-)copy of the object, and |
42 into a registry. The registry will create an executor, which is a (shallow-)copy |
43 watch out for death of the original object. When it dies, the copy will |
43 of the object, and watch out for death of the original object. When it dies, |
44 be sent a #disposed-message. |
44 the executor will be sent a #finalize message. |
45 The trick with the shallow copy is especially nice, you can think of it as |
45 The trick with the shallow copy is especially nice, you can think of it as |
46 being the original object which died. |
46 being the original object which died. |
47 |
47 |
48 All objects, which keep external resources (such as fileDescriptors, fonts, |
48 All objects, which keep external resources (such as fileDescriptors, fonts, |
49 colormap-entries etc.) should be registered, so that the underlying resource |
49 colormap-entries etc.) should be registered, so that the underlying resource |
50 can be freed when the object goes away. |
50 can be freed when the object goes away. |
51 |
51 |
52 Of course, you too can use it to do whatever you need to do in case of the |
52 Of course, you too can use it to do whatever you need to do in case of the |
53 death of an object. |
53 death of an object. |
54 |
54 |
55 Registries use #shallowCopyForFinalization to aquire the copy of the original, |
55 Registries use #executor to aquire the copy of the original, |
56 this can be redefined in registered classes for faster copying |
56 this can be redefined in registered classes for faster copying |
57 (typically, not all internal state but only some device handles are needed for |
57 (typically, not all internal state but only some device handles are needed for |
58 finalization). I if the to-be-registered object is large, this method may also |
58 finalization). I if the to-be-registered object is large, this method may also |
59 return a stub (placeHolder) object. (i.e. there is no need for the copy to be |
59 return a stub (placeHolder) object. (i.e. there is no need for the copy to be |
60 of the same class as the original, as long as it implements disposed and frees |
60 of the same class as the original, as long as it implements #finalize and frees |
61 the relevant OS resources ...) |
61 the relevant OS resources ...) |
62 Example uses are found in Form, Color, ExternalStream and Font |
62 Example uses are found in Form, Color, ExternalStream and Font |
63 |
63 |
64 [author:] |
64 [author:] |
65 Claus Gittinger |
65 Claus Gittinger |
83 ! ! |
83 ! ! |
84 |
84 |
85 !Registry methodsFor:'dispose handling'! |
85 !Registry methodsFor:'dispose handling'! |
86 |
86 |
87 informDispose:someHandle |
87 informDispose:someHandle |
88 "send a dispose message - this is sent to the phantom, |
88 "send a dispose message - this is sent to the executor, |
89 since the original is already gone" |
89 since the original is already gone" |
90 |
90 |
91 someHandle disposed |
91 someHandle finalize |
92 |
92 |
93 "Modified: 16.1.1997 / 17:23:46 / cg" |
93 "Modified: 16.1.1997 / 17:23:46 / cg" |
94 ! |
94 ! |
95 |
95 |
96 update:something with:aParameter from:changedObject |
96 update:something with:aParameter from:changedObject |
97 "an instance has been destroyed - look which one it was" |
97 "an instance has been destroyed - look which one it was" |
98 |
98 |
99 |phantom |
99 |executor |
100 index "{ Class: SmallInteger }" |
100 index "{ Class: SmallInteger }" |
101 sz "{ Class: SmallInteger }" |
101 sz "{ Class: SmallInteger }" |
102 o myHandleArray wasBlocked| |
102 o myHandleArray wasBlocked| |
103 |
103 |
104 something == #ElementExpired ifTrue:[ |
104 something == #ElementExpired ifTrue:[ |
111 index := 1. |
111 index := 1. |
112 [index <= sz] whileTrue:[ |
112 [index <= sz] whileTrue:[ |
113 o := registeredObjects at:index. |
113 o := registeredObjects at:index. |
114 o notNil ifTrue:[ |
114 o notNil ifTrue:[ |
115 o == 0 ifTrue:[ |
115 o == 0 ifTrue:[ |
116 phantom := myHandleArray at:index. |
116 executor := myHandleArray at:index. |
117 registeredObjects at:index put:nil. |
117 registeredObjects at:index put:nil. |
118 tally := tally - 1. |
118 tally := tally - 1. |
119 phantom notNil ifTrue:[ |
119 executor notNil ifTrue:[ |
120 myHandleArray at:index put:nil. |
120 myHandleArray at:index put:nil. |
121 |
121 |
122 "/ |
122 "/ |
123 "/ allow interrupts for a while ... |
123 "/ allow interrupts for a while ... |
124 "/ |
124 "/ |
125 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
125 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
126 self informDispose:phantom. |
126 self informDispose:executor. |
127 OperatingSystem blockInterrupts. |
127 OperatingSystem blockInterrupts. |
128 |
128 |
129 "/ |
129 "/ |
130 "/ any change in an interrupt or dispose handling ? |
130 "/ any change in an interrupt or dispose handling ? |
131 "/ |
131 "/ |
176 !Registry methodsFor:'private'! |
176 !Registry methodsFor:'private'! |
177 |
177 |
178 repairTally |
178 repairTally |
179 |sz "{ Class: SmallInteger }" |
179 |sz "{ Class: SmallInteger }" |
180 cnt "{ Class: SmallInteger }" |
180 cnt "{ Class: SmallInteger }" |
181 phantom wasBlocked| |
181 executor wasBlocked| |
182 |
182 |
183 wasBlocked := OperatingSystem blockInterrupts. |
183 wasBlocked := OperatingSystem blockInterrupts. |
184 |
184 |
185 indexTable := WeakIdentityDictionary new. |
185 indexTable := WeakIdentityDictionary new. |
186 |
186 |
187 sz := registeredObjects size. |
187 sz := registeredObjects size. |
188 cnt := 0. |
188 cnt := 0. |
189 |
189 |
190 1 to:sz do:[:index | |
190 1 to:sz do:[:index | |
191 ((phantom := registeredObjects at:index) notNil |
191 ((executor := registeredObjects at:index) notNil |
192 and:[phantom ~~ 0]) ifTrue:[ |
192 and:[executor ~~ 0]) ifTrue:[ |
193 indexTable at:phantom put:index. |
193 indexTable at:executor put:index. |
194 cnt := cnt + 1. |
194 cnt := cnt + 1. |
195 ] ifFalse:[ |
195 ] ifFalse:[ |
196 handleArray at:index put:nil. |
196 handleArray at:index put:nil. |
197 registeredObjects at:index put:nil. |
197 registeredObjects at:index put:nil. |
198 ] |
198 ] |
223 newHandles := Array new:realNewSize. |
223 newHandles := Array new:realNewSize. |
224 indexTable := WeakIdentityDictionary new. |
224 indexTable := WeakIdentityDictionary new. |
225 |
225 |
226 dstIndex := 1. |
226 dstIndex := 1. |
227 1 to:sz do:[:index | |
227 1 to:sz do:[:index | |
228 (phantom := registeredObjects at:index) notNil ifTrue:[ |
228 (executor := registeredObjects at:index) notNil ifTrue:[ |
229 dstIndex > realNewSize ifTrue:[ |
229 dstIndex > realNewSize ifTrue:[ |
230 'Registry [error]: size given is too small in resize' errorPrintCR. |
230 'Registry [error]: size given is too small in resize' errorPrintCR. |
231 self repairTally. |
231 self repairTally. |
232 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
232 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
233 ^ self |
233 ^ self |
234 ]. |
234 ]. |
235 newObjects at:dstIndex put:phantom. |
235 newObjects at:dstIndex put:executor. |
236 newHandles at:dstIndex put:(handleArray at:index). |
236 newHandles at:dstIndex put:(handleArray at:index). |
237 indexTable at:phantom put:dstIndex. |
237 indexTable at:executor put:dstIndex. |
238 |
238 |
239 dstIndex := dstIndex + 1 |
239 dstIndex := dstIndex + 1 |
240 ] |
240 ] |
241 ]. |
241 ]. |
242 |
242 |
349 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
349 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
350 ^ self |
350 ^ self |
351 ]. |
351 ]. |
352 |
352 |
353 "/ mhmh - a registeredObject vanished, but its |
353 "/ mhmh - a registeredObject vanished, but its |
354 "/ phantom is still there ... |
354 "/ executor is still there ... |
355 |
355 |
356 "/ |
356 "/ |
357 "/ this may happen, if the registries dispose handling is |
357 "/ this may happen, if the registries dispose handling is |
358 "/ currently being executed by a lower priority process, |
358 "/ currently being executed by a lower priority process, |
359 "/ and the registeredObject has already been nilled, |
359 "/ and the registeredObject has already been nilled, |
360 "/ but the phantom is being notified (in the other process). |
360 "/ but the executor is being notified (in the other process). |
361 |
361 |
362 "/ 'Registry [info]: leftOver phantom: ' infoPrint. p infoPrintCR. |
362 "/ 'Registry [info]: leftOver executor: ' infoPrint. p infoPrintCR. |
363 |
363 |
364 "/ "tell the phantom" |
364 "/ "tell the executor" |
365 "/ handleArray at:index put:nil. |
365 "/ handleArray at:index put:nil. |
366 "/ tally := tally - 1. |
366 "/ tally := tally - 1. |
367 "/ self informDispose:p. |
367 "/ self informDispose:p. |
368 "/ p := nil. |
368 "/ p := nil. |
369 |
369 |
395 "Modified: / 7.1.1997 / 16:56:03 / stefan" |
395 "Modified: / 7.1.1997 / 16:56:03 / stefan" |
396 "Modified: / 22.4.1998 / 11:09:23 / cg" |
396 "Modified: / 22.4.1998 / 11:09:23 / cg" |
397 ! |
397 ! |
398 |
398 |
399 registerChange:anObject |
399 registerChange:anObject |
400 "a registered object has changed, create a new phantom" |
400 "a registered object has changed, create a new executor" |
401 |
401 |
402 |index wasBlocked copy| |
402 |index wasBlocked copy| |
403 |
403 |
404 wasBlocked := OperatingSystem blockInterrupts. |
404 wasBlocked := OperatingSystem blockInterrupts. |
405 registeredObjects isNil ifTrue:[ |
405 registeredObjects isNil ifTrue:[ |