[slime-devel] Crash course in SLIME RPC debugging (Re: SLDB hangs with CLISP/Cygwin)
Luke Gorrie
luke at synap.se
Sun Mar 13 22:01:33 UTC 2005
"Steven E. Harris" <seh at panix.com> writes:
> Can you help interpret what's failing here? My assumption is that
> SLIME is hanging waiting for some reply to arrive from the swank
> server, and it finds no such reply to read. What SLIME component is
> responsible for writing to *slime-events*?
The pattern is that asynchronous RPCs succeed by synchronous ones fail.
Under the hood the Emacs RPC interface is asynchronous - you tell Lisp
what to do and pass a callback function to be called with the result.
Looks basically like:
(slime-eval-async '(my-lisp-function arg1 arg2)
(lambda (result) ...do something...))
but sometimes you want to make a synchronous RPC where instead of
passing a callback you just wait and have the value returned. For this
we have a simpler interface, basically:
(slime-eval '(my-function arg1 arg2)) => result
We use a trick to build synchronous evaluation on top of asynchronous.
slime-eval is implemented similar to this:
(catch request-id
(slime-eval-async form (lambda (result) (throw request-id result)))
(loop (poll-for-response)))
i.e. it sends an asynchronous request and then enters an "infinite"
loop. The loop will actually terminate when the RPC's result is
delivered to the 'lambda' function because it will throw it up to the
'catch' which is outside the loop.
For some reason this trick doesn't seem to be working in your Emacs.
The loop is not terminating so apparently no result is being thrown.
Here is the code that makes the throw, from slime-dispatch-event, with
added commentary:
(destructure-case event
...
((:return value id)
;; Lisp has sent us the result (value) for an RPC identified by `id'
;; This `id' is the same tag in slime-eval's 'catch' on the stack.
(let ((rec (assq id (slime-rex-continuations))))
;; Here is the extra event trace we added.
;; The output from this showed that the 'assq' above did indeed
;; find the continuation function - that's the function that
;; will 'throw' when we call it with the value.
(slime-log-event (list 'DEBUG id value rec))
;; We also know from the output that `rec' is not nil so the
;; first cond-clause will be selected:
(cond (rec (setf (slime-rex-continuations )
(remove rec (slime-rex-continuations)))
(when (null (slime-rex-continuations))
(slime-set-state ""))
;; Here is where we end up: call the continuation
;; function with the value. This function is
;; supposed to 'throw' its way out of the loop.
(funcall (cdr rec) value))
(t
(error "Unexpected reply: %S %S" id value)))))
I'm tempted to accuse your Emacs of having a broken throw/catch, but
that's dangerous talk. Here's another debug info patch that's worth a
try - it will print a message when the throw and catch are used:
--- slime.el.~1.471.~ 2005-03-13 20:38:20.000000000 +0100
+++ slime.el 2005-03-13 22:54:35.000000000 +0100
@@ -2102,6 +2102,7 @@
(slime-stack-eval-tags (cons tag slime-stack-eval-tags)))
(apply
#'funcall
+ (prog1
(catch tag
(slime-rex (tag sexp)
(sexp package)
@@ -2109,12 +2110,14 @@
(unless (member tag slime-stack-eval-tags)
(error "tag = %S eval-tags = %S sexp = %S"
tag slime-stack-eval-tags sexp))
+ (message "Throwing result to ~S" tag)
(throw tag (list #'identity value)))
((:abort)
(throw tag (list #'error "Synchronous Lisp Evaluation aborted."))))
(let ((debug-on-quit t)
(inhibit-quit nil))
- (while t (accept-process-output nil 0 10000)))))))
+ (while t (accept-process-output nil 0 10000))))
+ (message "Caught %S" tag)))))
(defun slime-eval-async (sexp &optional cont package)
"Evaluate EXPR on the superior Lisp and call CONT with the result."
More information about the slime-devel
mailing list