Looking at this some more, there's two places where a reference to the
object to be finalized is returned: sb-ext:weak-pointer-value, and
subsequently by sb-ext:finalize.
I thought something like this would do the trick:
(declaim (notinline finalize-our-thread))
(defun finalize-our-thread (ptr thread)
(lambda () (throw 'done nil)))))
(defun weak-interrupt (ptr)
(finalize-our-thread ptr sb-thread:*current-thread*)
(defvar thread8 (weak-interrupt (make-weak-pointer (make-instance 'foo))))
(sb-ext:gc :full t)
(The goal here is to interrupt the sleeping thread btw, I probably
explained that poorly).
So the idea is that finalize-our-thread gets called, cleans up the
stack after itself, and returns. I'm making three assumptions here -
finalize-our-thread cleans up after itself on the stack, doesn't leave
a pointer in a register, and doesn't keep intermediate values anywhere
else but the stack or the registers. But it seems at least one of
those assumptions is wrong, as the object isn't being collected while
the thread is sleeping. Another thing is I'm on x86-32, so the
conservative collector might be at fault. Would it help if I post the
output of disassemble? (I can kind of read it but not understand
what's going on)
2010/10/29 Nikodemus Siivola <nikodemus@...>:
> On 29 October 2010 06:36, Vladimir Sedach <vsedach@...> wrote:
> Wait, are you saying that
> (lambda ()
> (catch 'done
> (finalize <obj>
> (let ((thread *current-thread*))
> (lambda ()
> thread (lambda () (throw 'done <computation>))))))
> is the exact pattern you are using in your code? That you want to
> delay a computation to be done by a thread till an object dies?
> There are couple of issues with this.
> Firstly, yes, you're going to have a very hard time making sure you
> don't have life references to <OBJ> till that LAMBDA returns.
> If you're really want to try it:
> * (DEBUG 0) is going to be your friend (high debug settings increase
> variable lifetimes).
> * You want to structure the code so that WAIT-FOREVER can be in a
> tail-position, which it isn't here -- CATCH prevents that (as would
> using BLOCK/RETURN-FROM and closing over the block.) Instead of
> BLOCK/RETURN or CATCH/THROW you want WAIT-FOREVER to actually return
> the value. (INTERRUPT-THREAD in production code is also always a bit
> icky, IMO -- especially forcing a non-local exit using it.) Something
> along the lines of
> (lambda ()
> (declare (optimize (debug 0)))
> (let ((sem (sb-thread:make-semaphore)))
> (finalize obj (lambda () (sb-thread:signal-semaphore sem)))
> (wait-and-compute sem function))))
> (defun wait-and-compute (sem function)
> (sb-thread:wait-on-semaphore sem)
> (funcall function))
> might have a chance. If it still doesn't fire, you need to insert a
> bit of frame-scrubbing between the FINALIZE and WAIT-AND-COMPUTE
> calls. I think it should not be too hard to write a VOP
> %NUKE-FRAME-REFS that takes a specific object and removes references
> to it from the frame -- but it doesn't quite fit into this
> metaphorical margin.
> Secondly, while a thread is cheap in comparison to a process, it's
> still a pretty damn big object. Doing this is a rather expensive way
> to defer computation.
> -- Nikodemus