[slime-devel] Re: Use of with-lock inside without-interrupts
Martin Simmons
martin at lispworks.com
Wed Aug 6 11:33:51 UTC 2008
>>>>> On Tue, 05 Aug 2008 22:51:05 +0200, Helmut Eller said:
>
> * Martin Simmons [2008-08-05 21:26+0200] writes:
>
> > I see some new changes in swank-lispworks.lisp where mp:with-lock is used
> > inside mp:without-interrupts. What is the purpose of that?
>
> My reasoning with this code was:
>
> (loop
> (mp:process-wait "receive-if"
> (lambda () (some test (mailbox.queue mbox))))
> (mp:without-interrupts
> (mp:with-lock (lock "receive-if/try" 0.1)
> (let* ((q (mailbox.queue mbox))
> (tail (member-if test q)))
> (when tail
> (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail)))
> (return (car tail)))))))
>
> there would be no guarantee that the part inside WITH-LOCK isn't
> interrupted, e.g. by PROCESS-INTERRUPT to run the SLIME debugger. But
> the debugger, sooner or later, calls RECEIVE-IF in the same thread;
> recursively so to say. It could happen that the debugger removes the
> the element that the suspended call was about to remove, i.e. both
> calls would, after the debugger resumes, return the same element.
>
> Disabling interrupts inside the WITH-LOCK didn't seem right either,
> because then the interrupt handler would be delayed, but still be run in
> the dynamic extend of the lock and so blocking any sender.
>
> That's pretty unfortunate mix of threading and interrupts. The current
> variant with the timeout appeared to me as the least broken. But I
> would love to learn how to do this properly.
Hmmm, I see the problem now.
I think you could implement it without blocking all interrupts by maintaining
your own interrupt queue, something like this:
(defvar *pending-slime-interrupts* nil)
(defvar *in-without-slime-interrupts* nil)
(defmacro without-slime-interrupts (&body body)
`(let ((*pending-slime-interrupts* nil)
(*in-without-slime-interrupts* t))
(unwind-protect
(progn , at body)
(when *pending-slime-interrupts*
(let ((*in-without-slime-interrupts* nil))
(mapc 'funcall *pending-slime-interrupts*))))))
(defun invoke-or-queue-interrupt (function)
(if *in-without-slime-interrupts*
(push function *pending-slime-interrupts*)
(funcall function)))
Then the SLIME interrupt function should call INVOKE-OR-QUEUE-INTERRUPT, which
will delay the interrupt if inside the WITHOUT-SLIME-INTERRUPTS form.
--
Martin Simmons
LispWorks Ltd
http://www.lispworks.com/
More information about the slime-devel
mailing list