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 ,@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.