[Openmcl-devel] Voodoo: Callbacks and Closures
David Steuber
david at david-steuber.com
Thu May 5 21:36:58 PDT 2005
On May 5, 2005, at 5:01 PM, Gary Byers wrote:
>> Does this mean that a CLOS object referenced by the callback is also
>> protected from getting GCed?
>
> yes; it's transitively reachable from a global variable
> (%PASCAL-FUNCTIONS%).
>
>> I also have a function for uninstalling an event handler. Once this
>> is done, the callback will no longer by referenced. What do I need
>> to do to delete the entry?
>
> This is untested, assumes that it's defined in the CCL package, and
> continues
> the confusing tradition of calling callbacks "Pascal functions".
>
> (defun %delete-pascal-function (pointer)
> (with-lock-grabbed (*callback-lock*)
> (let* ((index (dotimes (i (length %pascal-function))
> (when (eql (pfe.routine-descriptor (svref
> %pascal-functions%^ i)) pointer)
> (return i)))))
> (when index
> (let* ((entry (svref %pascal-functions%^ index)))
> (setf (svref %pascal-functions%^ index) nil)
> (when (eql (symbol-value (pfe.sym entry))
> (pfe.routine-descriptor entry))
> (set (symbol-value (pfe.sym entry)) nil))
> (free (pfe.routine-descriptor entry))
> t)))))
Thanks, Gary.
Based on the above, I made some minor modifications to your function
and did some testing:
;; this function is based on code that Gary Byers posted to
openmcl-devel
(defun delete-event-target-callback (pointer)
(with-lock-grabbed (ccl::*callback-lock*)
(let ((index (dotimes (i (length ccl::%pascal-functions%))
(when (eql (ccl::pfe.routine-descriptor (svref
ccl::%pascal-functions% i))
pointer)
(return i)))))
(when index
(let ((entry (svref ccl::%pascal-functions% index)))
(setf (svref ccl::%pascal-functions% index) nil)
(ccl::free (ccl::pfe.routine-descriptor entry))
t)))))
I had some trouble with the symbol-value stuff so I removed it. It
looks like what's left does all I need. I'm not sure why the call to
free is necessary though but I left it in. It's just the reference to
the closure I need removed. The program is expected to create a new
closure for each window or whatever other object may need to receive
carbon events that is created. I haven't tested this with window
objects yet, but here is a partial transcript from my slime repl
session where I tested the code. Note also that I have not yet tested
to see if this gets rid of the "memory leak" that I think I had/have.
CL-USER> (loop for i across ccl::%pascal-functions% do (print i))
#(#<A Mac Pointer #x102490> NIL #<Compiled-function
CCL::%FOREIGN-THREAD-CONTROL (Non-Global) #x60F58BE>
CCL::%FOREIGN-THREAD-CONTROL T NIL)
#(#<A Mac Pointer #x1024B0> NIL #<Compiled-function CCL::XCMAIN
(Non-Global) #x6134406> CCL::XCMAIN T NIL)
#(#<A Mac Pointer #x1024D0> NIL #<Compiled-function CCL::%XERR-DISP
(Non-Global) #x6168F4E> CCL::%XERR-DISP NIL NIL)
#(#<A Mac Pointer #x105D80> NIL #<COMPILED-LEXICAL-CLOSURE
CL-CARBON::FN #x640AA06> CL-CARBON::FN NIL NIL)
NIL
NIL
NIL
NIL
NIL
NIL
CL-USER> (setf bar (cl-carbon::make-event-target-callback foo))
#<A Mac Pointer #x15E6D0>
CL-USER> (loop for i across ccl::%pascal-functions% do (print i))
#(#<A Mac Pointer #x102490> NIL #<Compiled-function
CCL::%FOREIGN-THREAD-CONTROL (Non-Global) #x60F58BE>
CCL::%FOREIGN-THREAD-CONTROL T NIL)
#(#<A Mac Pointer #x1024B0> NIL #<Compiled-function CCL::XCMAIN
(Non-Global) #x6134406> CCL::XCMAIN T NIL)
#(#<A Mac Pointer #x1024D0> NIL #<Compiled-function CCL::%XERR-DISP
(Non-Global) #x6168F4E> CCL::%XERR-DISP NIL NIL)
#(#<A Mac Pointer #x105D80> NIL #<COMPILED-LEXICAL-CLOSURE
CL-CARBON::FN #x640AA06> CL-CARBON::FN NIL NIL)
#(#<A Mac Pointer #x15E6D0> NIL #<COMPILED-LEXICAL-CLOSURE
CL-CARBON::FN #x6C01B0E> CL-CARBON::FN NIL NIL)
NIL
NIL
NIL
NIL
NIL
CL-USER> (cl-carbon::delete-event-target-callback bar)
T
CL-USER> (loop for i across ccl::%pascal-functions% do (print i))
#(#<A Mac Pointer #x102490> NIL #<Compiled-function
CCL::%FOREIGN-THREAD-CONTROL (Non-Global) #x60F58BE>
CCL::%FOREIGN-THREAD-CONTROL T NIL)
#(#<A Mac Pointer #x1024B0> NIL #<Compiled-function CCL::XCMAIN
(Non-Global) #x6134406> CCL::XCMAIN T NIL)
#(#<A Mac Pointer #x1024D0> NIL #<Compiled-function CCL::%XERR-DISP
(Non-Global) #x6168F4E> CCL::%XERR-DISP NIL NIL)
#(#<A Mac Pointer #x105D80> NIL #<COMPILED-LEXICAL-CLOSURE
CL-CARBON::FN #x640AA06> CL-CARBON::FN NIL NIL)
NIL
NIL
NIL
NIL
NIL
NIL
CL-USER>
Does this look kosher to you?
More information about the Openmcl-devel
mailing list