0.9.3.28: bdowning's fd-stream patch, slightly modified
authorGabor Melis <mega@hotpop.com>
Thu, 4 Aug 2005 13:05:30 +0000 (13:05 +0000)
committerGabor Melis <mega@hotpop.com>
Thu, 4 Aug 2005 13:05:30 +0000 (13:05 +0000)
  * *AVAILABLE-BUFFERS* is now shared between threads to avoid
    leaking 8192 bytes per stream created in one thread but
    written to in another
  * killed two warnings introduced in purify.c

NEWS
src/code/fd-stream.lisp
src/code/target-thread.lisp
version.lisp-expr

diff --git a/NEWS b/NEWS
index 4a3b2b9..b42c442 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -20,8 +20,10 @@ changes in sbcl-0.9.4 relative to sbcl-0.9.3:
     *DEBUGGER-HOOK* => *DEBUGGER-HOOK* is not run when the debugger
     is disabled.
   * threads
-    ** bug fix: release-foreground doesn't choke on session lock if
+    ** bug fix: RELEASE-FOREGROUND doesn't choke on session lock if
        there is only one thread in the session
+    ** bug fix: memory leak for streams created in one thread and
+       written to in another
 
 changes in sbcl-0.9.3 relative to sbcl-0.9.2:
   * New feature: Experimental support for bivalent streams: streams
index 122809f..1d98e0e 100644 (file)
   "List of available buffers. Each buffer is an sap pointing to
   bytes-per-buffer of memory.")
 
+#!+sb-thread
+(defvar *available-buffers-mutex* (sb!thread:make-mutex
+                                   :name "lock for *AVAILABLE-BUFFERS*")
+  #!+sb-doc
+  "Mutex for access to *AVAILABLE-BUFFERS*.")
+
+(defmacro with-available-buffers-lock ((&optional) &body body)
+  ;; WITHOUT-INTERRUPTS because streams are low-level enough to be
+  ;; async signal safe, and in particular a C-c that brings up the
+  ;; debugger while holding the mutex would lose badly
+  `(without-interrupts
+    (sb!thread:with-mutex (*available-buffers-mutex*)
+      ,@body)))
+
 (defconstant bytes-per-buffer (* 4 1024)
   #!+sb-doc
   "Number of bytes per buffer.")
 ;;; Return the next available buffer, creating one if necessary.
 #!-sb-fluid (declaim (inline next-available-buffer))
 (defun next-available-buffer ()
-  (if *available-buffers*
-      (pop *available-buffers*)
-      (allocate-system-memory bytes-per-buffer)))
+  (with-available-buffers-lock ()
+    (if *available-buffers*
+        (pop *available-buffers*)
+        (allocate-system-memory bytes-per-buffer))))
 \f
 ;;;; the FD-STREAM structure
 
                  (simple-stream-perror "couldn't write to ~S" stream errno)))
             ((eql count length) ; Hot damn, it worked.
              (when reuse-sap
-               (push base *available-buffers*)))
+               (with-available-buffers-lock ()
+                 (push base *available-buffers*))))
             ((not (null count)) ; sorta worked..
              (push (list base
                          (the index (+ start count))
 
     ;; drop buffers when direction changes
     (when (and (fd-stream-obuf-sap fd-stream) (not output-p))
-      (push (fd-stream-obuf-sap fd-stream) *available-buffers*)
-      (setf (fd-stream-obuf-sap fd-stream) nil))
+      (with-available-buffers-lock ()
+       (push (fd-stream-obuf-sap fd-stream) *available-buffers*)
+       (setf (fd-stream-obuf-sap fd-stream) nil)))
     (when (and (fd-stream-ibuf-sap fd-stream) (not input-p))
-      (push (fd-stream-ibuf-sap fd-stream) *available-buffers*)
-      (setf (fd-stream-ibuf-sap fd-stream) nil))
+      (with-available-buffers-lock ()
+       (push (fd-stream-ibuf-sap fd-stream) *available-buffers*)
+       (setf (fd-stream-ibuf-sap fd-stream) nil)))
     (when input-p
       (setf (fd-stream-ibuf-sap fd-stream) (next-available-buffer))
       (setf (fd-stream-ibuf-length fd-stream) bytes-per-buffer)
        (cancel-finalization fd-stream))
      (sb!unix:unix-close (fd-stream-fd fd-stream))
      (when (fd-stream-obuf-sap fd-stream)
-       (push (fd-stream-obuf-sap fd-stream) *available-buffers*)
-       (setf (fd-stream-obuf-sap fd-stream) nil))
+       (with-available-buffers-lock ()
+         (push (fd-stream-obuf-sap fd-stream) *available-buffers*)
+         (setf (fd-stream-obuf-sap fd-stream) nil)))
      (when (fd-stream-ibuf-sap fd-stream)
-       (push (fd-stream-ibuf-sap fd-stream) *available-buffers*)
-       (setf (fd-stream-ibuf-sap fd-stream) nil))
+       (with-available-buffers-lock ()
+         (push (fd-stream-ibuf-sap fd-stream) *available-buffers*)
+         (setf (fd-stream-ibuf-sap fd-stream) nil)))
      (sb!impl::set-closed-flame fd-stream))
     (:clear-input
      (setf (fd-stream-unread fd-stream) nil)
index b859ea7..918422f 100644 (file)
@@ -486,8 +486,7 @@ returns the thread exits."
                     (sb!kernel::*restart-clusters* nil)
                     (sb!kernel::*handler-clusters* nil)
                     (sb!kernel::*condition-restarts* nil)
-                    (sb!impl::*descriptor-handlers* nil) ; serve-event
-                    (sb!impl::*available-buffers* nil)) ;for fd-stream
+                    (sb!impl::*descriptor-handlers* nil)) ; serve-event
                 ;; can't use handling-end-of-the-world, because that flushes
                 ;; output streams, and we don't necessarily have any (or we
                 ;; could be sharing them)
index 641138d..febc033 100644 (file)
@@ -17,4 +17,4 @@
 ;;; checkins which aren't released. (And occasionally for internal
 ;;; versions, especially for internal versions off the main CVS
 ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"0.9.3.27"
+"0.9.3.28"