branch: elpa/slime
commit 68a36ebfa7b31eb1fc7e6800857cbdf4ba188b32
Author: Stas Boukarev <stass...@gmail.com>
Commit: Stas Boukarev <stass...@gmail.com>

    gray: don't grab a lock while touching CLOS objects.
    
    Avoiding possible deadlocks when writing from multiple threads.
---
 swank/gray.lisp | 34 ++++++++++++++++++++--------------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/swank/gray.lisp b/swank/gray.lisp
index 3f5f09fc88..76a1005726 100644
--- a/swank/gray.lisp
+++ b/swank/gray.lisp
@@ -55,7 +55,7 @@
          :initarg :data 
          :accessor data)))
 
-(defmacro with-slime-output-stream (stream &body body)
+(defmacro with-stream-data (data &body body)
   `(with-accessors ((lock stream-data-lock)
                     (output-fn stream-data-output-fn)
                     (buffer stream-data-buffer)
@@ -63,11 +63,15 @@
                     (column stream-data-column)
                     (flush-thread stream-data-flush-thread)
                     (flush-scheduled stream-data-flush-scheduled))
-       (data ,stream)
+       ,data
      (call-with-lock-held lock (lambda () ,@body))))
 
-(defun maybe-schedule-flush (stream)
-  (with-slime-output-stream stream
+(defmacro with-slime-output-stream (stream &body body)
+  `(let ((data (data ,stream)))
+     (with-stream-data data ,@body)))
+
+(defun maybe-schedule-flush (data)
+  (with-stream-data data
     (when flush-thread
       (or flush-scheduled
           (progn
@@ -83,8 +87,8 @@
     (when (char= #\newline char)
       (setf column 0))
     (if (= fill-pointer (length buffer))
-        (%stream-finish-output stream)
-        (maybe-schedule-flush stream)))
+        (%stream-finish-output data)
+        (maybe-schedule-flush data)))
   char)
 
 (defmethod stream-write-string ((stream slime-output-stream) string
@@ -96,12 +100,12 @@
            (count (- end start))
            (free (- len fill-pointer)))
       (when (>= count free)
-        (%stream-finish-output stream))
+        (%stream-finish-output data))
       (cond ((< count len)
              (replace buffer string :start1 fill-pointer
                       :start2 start :end2 end)
              (incf fill-pointer count)
-             (maybe-schedule-flush stream))
+             (maybe-schedule-flush data))
             (t
              (funcall output-fn (subseq string start end))))
       (let ((last-newline (position #\newline string :from-end t
@@ -117,8 +121,8 @@
 (defun reset-stream-line-column (stream)
   (with-slime-output-stream stream (setf column 0)))
 
-(defun %stream-finish-output (stream)
-  (with-slime-output-stream stream
+(defun %stream-finish-output (data)
+  (with-stream-data data
     (unless (zerop fill-pointer)
       (funcall output-fn (subseq buffer 0 fill-pointer))
       (setf fill-pointer 0))
@@ -129,8 +133,9 @@
   (stream-finish-output stream))
 
 (defmethod stream-finish-output ((stream slime-output-stream))
-  (unless (maybe-schedule-flush stream)
-    (%stream-finish-output stream)))
+  (with-slime-output-stream stream
+    (unless (maybe-schedule-flush data)
+      (%stream-finish-output data))))
 
 (defmethod stream-fresh-line ((stream slime-output-stream))
   (with-slime-output-stream stream
@@ -213,7 +218,8 @@
 (defimplementation make-auto-flush-thread (stream)
   (if (typep stream 'slime-output-stream)
       (setf (stream-data-flush-thread (data stream))
-            (spawn (lambda () (auto-flush-loop stream 0.005 t 
#'%stream-finish-output))
+            (spawn (lambda () (auto-flush-loop stream 0.005 t (lambda (stream) 
+                                                                
(%stream-finish-output (data stream)))))
                    :name "auto-flush-thread"))
       (spawn (lambda () (auto-flush-loop stream *auto-flush-interval*))
              :name "auto-flush-thread")))
@@ -221,7 +227,7 @@
 (defimplementation really-finish-output (stream)
   (let ((stream (swank::real-output-stream stream)))
     (if (typep stream 'slime-output-stream)
-        (%stream-finish-output stream)
+        (%stream-finish-output (data stream))
         (finish-output stream))))
 
 (defimplementation make-output-stream (write-string)

Reply via email to