Attached is a patch against SLIME CVS HEAD to implement multi-threading (aka the :spawn *COMMUNICATION-STYLE*) as a default in ABCL. In addition this patch muffles various STYLE-WARNING compilation messages via DECLARE forms.
Among other things, this seems to fix the fugliness around where *STANDARD-OUTPUT* ends up and the missing CR (or LF) in the NIL *COMMUNICATION-STYLE*.
This patch has been tested against ABCL 0.16.0-dev as of [svn r12022] with Emacs 22.3 under OS X.
I didn't need to do much to the existing code except fix a typo while comparing against the current 'swank-sbcl.lisp' version, making me somewhat suspicious of why that code was not used in the first place (did someone just cut and paste the SBCL implementation without trying to get it to work? But thanks to whoever got it that far!)
--
"A screaming comes across the sky. It has happened before, but there is nothing to compare to it now."
diff -r 2225a8f2d322 -r 3c562ce589df swank-abcl.lisp --- a/swank-abcl.lisp Wed Jul 01 05:38:54 2009 +0200 +++ b/swank-abcl.lisp Wed Jul 01 11:06:42 2009 +0200 @@ -17,6 +17,7 @@ (defun sys::break (&optional (format-control "BREAK called") &rest format-arguments) (let ((*saved-backtrace* (backtrace-as-list-ignoring-swank-calls))) + (declare (ignore *saved-backtrace*)) (with-simple-restart (continue "Return from BREAK.") (invoke-debugger (sys::%make-condition 'simple-condition @@ -42,10 +43,16 @@
;(defun class-finalized-p (class) t)
-(defun slot-definition-documentation (slot) #+nil (documentation slot 't)) -(defun slot-definition-type (slot) t) -(defun class-prototype (class)) -(defun generic-function-declarations (gf)) +(defun slot-definition-documentation (slot) + (declare (ignore slot)) + #+nil (documentation slot 't)) +(defun slot-definition-type (slot) + (declare (ignore slot)) + t) +(defun class-prototype (class) + (declare (ignore class))) +(defun generic-function-declarations (gf) + (declare (ignore gf))) (defun specializer-direct-methods (spec) (mop::class-direct-methods spec))
(defun slot-definition-name (slot) @@ -61,9 +68,11 @@ (mop::%method-function method))
(defun slot-boundp-using-class (class object slotdef) + (declare (ignore class)) ; FIXME (system::slot-boundp object (slot-definition-name slotdef)))
(defun slot-value-using-class (class object slotdef) + (declare (ignore class)) ; FIXME (system::slot-value object (slot-definition-name slotdef)))
(import-to-swank-mop @@ -119,7 +128,7 @@
(defimplementation preferred-communication-style () - nil) + :spawn)
(defimplementation create-socket (host port) (ext:make-server-socket port)) @@ -483,8 +492,8 @@
;;;; Multithreading
-(defimplementation startup-multiprocessing () - #+nil(mp:start-scheduler)) +#+nil ; Already started +(defimplementation startup-multiprocessing (continuation))
(defimplementation spawn (fn &key name) (ext:make-thread (lambda () (funcall fn)) :name name)) @@ -513,7 +522,23 @@ (defimplementation thread-status (thread) (format nil "Thread is ~:[dead~;alive~]" (ext:thread-alive-p thread)))
+;; XXX should be a weak hash table +(defparameter *thread-description-map* (make-hash-table)) + +(defvar *thread-description-map-lock* + (ext:make-mutex)) + +(defimplementation thread-description (thread) + (ext:with-mutex (*thread-description-map-lock*) + (or (gethash thread *thread-description-map*) + "No description available."))) + +(defimplementation set-thread-description (thread description) + (ext:with-mutex (*thread-description-map-lock*) + (setf (gethash thread *thread-description-map*) description))) + (defimplementation make-lock (&key name) + (declare (ignore name)) (ext:make-thread-lock))
(defimplementation call-with-lock-held (lock function) @@ -525,8 +550,11 @@ (defimplementation all-threads () (copy-list (ext:mapcar-threads #'identity)))
+(defimplementation thread-alive-p (thread) + (member thread (all-threads))) + (defimplementation interrupt-thread (thread fn) - (ext:interrupt-thread thread fn)) + (ext:interrupt-thread thread fn))
(defimplementation kill-thread (thread) (ext:destroy-thread thread)) @@ -542,14 +570,13 @@ (setf (getf (gethash thread *thread-props*) 'mailbox) (make-mailbox)))))
-(defimplementation send (thread object) +(defimplementation send (thread message) (let ((mbox (mailbox thread))) (ext:with-mutex ((mailbox-mutex mbox)) (setf (mailbox-queue mbox) (nconc (mailbox-queue mbox) (list message))))))
-#+(or) -(defimplementation receive-if (thread &optional timeout) +(defimplementation receive-if (test &optional timeout) (let* ((mbox (mailbox (current-thread)))) (assert (or (not timeout) (eq timeout t))) (loop @@ -561,9 +588,7 @@ (setf (mailbox-queue mbox) (nconc (ldiff q tail) (cdr tail))) (return (car tail)))) (when (eq timeout t) (return (values nil t))) - ;;(java:jcall (java:jmethod "java.lang.Object" "wait") - ;; (mailbox-mutex mbox) 1000) - )))) + (sleep .05)))))
(defimplementation quit-lisp () (ext:exit))
Mark Evenson writes:
Attached is a patch against SLIME CVS HEAD to implement multi-threading
Is there some documentation about how to use multithreading in abcl?
I've never used slime but am looking at the doc now. What I was hoping to see but don't yet is how to debug a thread. In particular, I want to know how to - break a running thread (so it goes into the debugger) - connect an emacs buffer to the debugger ONLY in that thread If there is any current support for these things, even in some other lisp implementation, even in some emacs package other than slime, please send a link.
Don Cohen wrote:
Mark Evenson writes:
Attached is a patch against SLIME CVS HEAD to implement multi-threading
Is there some documentation about how to use multithreading in abcl?
No, unfortunately there isn't, and I've never totally convinced myself from reading the code that the internals of ABCL are going to hold up under heavy usage, which was part of my motivation to try this out.
The interfaces, such as they exist, can be seen in [LispThread.java][1], all existing in the EXTERNAL package.
A quick transcription of the source code:
(MAKE-THREAD FUNCTION &key NAME) Creates and runs a thread to evalulate FUNCTION setting the NAME.
(THREADP OBJECT) Boolean predicate whether OBJECT is a thread.
(THREAD-ALIVE-P THREAD) Boolean predicate whether THREAD is alive.
(THREAD-NAME THREAD) Return name of THREAD.
(SLEEP SECONDS) Cause the invoking thread to sleep SECONDS which can be expressed as a fraction, i.e. (sleep .1) would sleep for 100ms.
(MAPCAR-THREADS FUNCTION) Apply FUNCTION to each of the threads created via MAKE-THREAD.
(DESTROY-THREAD THREAD) Mark THREAD as destroyed.
(INTERRUPT THREAD FUNCTION &rest ARGS) Interrupt thread to apply function to args. Order of interrupts is not guaranteed. Thread should resume processing after processing all outstanding interupts
(USE-FAST-CALLS BOOLEAN) Sets an internal optimization for execution to BOOLEAN.
[1]: http://trac.common-lisp.net/armedbear/browser/trunk/abcl/src/org/armedbear/l...
Of these functions, I am only sure that MAKE-THREAD and SLEEP work.
Setting the thread's name doesn't currently work, but I'll fix that with patches when I get a chance. And add docstrings with the above content.
I've never used slime but am looking at the doc now. What I was hoping to see but don't yet is how to debug a thread. In particular, I want to know how to
- break a running thread (so it goes into the debugger)
- connect an emacs buffer to the debugger ONLY in that thread
This is beyond my knowledge. From a quick browsing of the SLIME source there is a thread browser with a DEBUG-NTH-THREAD function that looks like a promising answer to your first question.
If there is any current support for these things, even in some other lisp implementation, even in some emacs package other than slime, please send a link.
I would have said your best bet for multi-threading SLIME interaction is probably [SBCL][2] on a supported multi-threading platform (I know that Linux and OSX are supported), but I just tried the promising SLIME-LIST-THREADS emacs function, returning a condition stating that SWANK-BACKEND:ALL-THREADS isn't implemented.
You might try asking on the [SLIME mailing list][3]. Note that the SLIME community is a very "hack it yourself" oriented group, as there aren't releases per se.
[2]: http://www.sbcl.org/ [3]: nntp://news.gmane.org/gmane.lisp.slime.devel
Mark Evenson wrote: […]
The interfaces, such as they exist, can be seen in [LispThread.java][1], all existing in the EXTERNAL package.
[…]
A couple of corrections:
Actually that's the "EXTENSIONS" package: I always use the "EXT" short form of the name.
And SLEEP is actually in the COMMON-LISP package.
armedbear-devel@common-lisp.net