From 7861e493d9ba821f82471b81bed0223d8033a001 Mon Sep 17 00:00:00 2001 From: Nikodemus Siivola Date: Sun, 10 Apr 2005 12:55:54 +0000 Subject: [PATCH] 0.8.21.31: tweak finalizers, thighten spec further * sprinkle WITHOUT-GCING around, so that we won't enter GC while holding the lock on finalizer store. * specify that finalizers run in an unpredictable dynamic scope and must be fully re-entrant. Add a few examples for good measure. * add finalizer, weak pointer, and after gc hook documentation to the manual. --- NEWS | 4 ++- doc/manual/beyond-ansi.texinfo | 40 +++++++++++----------- src/code/final.lisp | 74 +++++++++++++++++++++++++++++++--------- src/code/weak.lisp | 8 ++--- version.lisp-expr | 2 +- 5 files changed, 85 insertions(+), 43 deletions(-) diff --git a/NEWS b/NEWS index 041ea38..b85bd54 100644 --- a/NEWS +++ b/NEWS @@ -6,8 +6,10 @@ changes in sbcl-0.8.22 relative to sbcl-0.8.21: interrupts enabled. * incompatible change: support for *BEFORE-GC-HOOKS* (that have been inoperational for a while now) has been completely removed. - * Null lexical environments are now printed as #, + * null lexical environments are now printed as #, significantly reducing the amount of clutter in typical backtraces. + * documentation on weak pointers, finalization, and after GC hooks + has been added to the manual. * optimization: REPLACE on declared (UNSIGNED-BYTE 8) vectors, as well as other specialized array types, is much faster. SUBSEQ and COPY-SEQ on such arrays have also been sped up. diff --git a/doc/manual/beyond-ansi.texinfo b/doc/manual/beyond-ansi.texinfo index a0bffa2..4bb8556 100644 --- a/doc/manual/beyond-ansi.texinfo +++ b/doc/manual/beyond-ansi.texinfo @@ -7,36 +7,38 @@ ANSI standard. SBCL doesn't support as many extensions as CMUCL, but it still has quite a few. @xref{Contributed Modules}. @menu -* Things Which Might Be In The Next ANSI Standard:: +* Garbage Collection:: +* Metaobject Protocol:: * Support For Unix:: * Customization Hooks for Users:: * Tools To Help Developers:: -* Resolution of Name Conflicts:: +* Resolution of Name Conflicts:: * Stale Extensions:: * Efficiency Hacks:: @end menu -@node Things Which Might Be In The Next ANSI Standard +@node Garbage Collection @comment node-name, next, previous, up -@section Things Which Might Be In The Next ANSI Standard - -SBCL provides extensive support for calling external C code, -@ref{Foreign Function Interface}. +@section Garbage Collection SBCL provides additional garbage collection functionality not specified by ANSI. Weak pointers allow references to objects to be -maintained without keeping them from being GCed (garbage -collected). And ``finalization'' hooks are available to cause code to -be executed when an object has been GCed. -@c - -SBCL supports @dfn{Gray streams}, user-overloadable CLOS classes whose -instances can be used as Lisp streams (e.g. passed as the first -argument to @code{format}). Additionally, the bundled contrib module -@dfn{sb-simple-streams} implements a subset of the Franz Allegro -simple-streams proposal. - -SBCL supports a MetaObject Protocol which is intended to be compatible +maintained without keeping them from being garbage collected, and +``finalization'' hooks are available to cause code to be executed when +an object has been garbage collected. Additionally users can specify +their own cleanup actions to be executed with garbage collection. + +@include fun-sb-ext-finalize.texinfo +@include fun-sb-ext-cancel-finalization.texinfo +@include fun-sb-ext-make-weak-pointer.texinfo +@include fun-sb-ext-weak-pointer-value.texinfo +@include var-sb-ext-star-after-gc-hooks-star.texinfo + +@node Metaobject Protocol +@comment node-name, next, previous, up +@section Metaobject Protocol + +SBCL supports a metaobject protocol which is intended to be compatible with AMOP; present exceptions to this (as distinct from current bugs) are: diff --git a/src/code/final.lisp b/src/code/final.lisp index a2adcaf..945cd5e 100644 --- a/src/code/final.lisp +++ b/src/code/final.lisp @@ -19,11 +19,49 @@ (defun finalize (object function) #!+sb-doc "Arrange for the designated FUNCTION to be called when there -are no more references to OBJECT. In a multithreaded environment -the finalizer may run in any thread." - (sb!thread:with-mutex (*finalizer-store-lock*) - (push (cons (make-weak-pointer object) function) - *finalizer-store*)) +are no more references to OBJECT, including references in +FUNCTION itself. + +In a multithreaded environment FUNCTION may be called in any +thread. In both single and multithreaded environments FUNCTION +may be called in any dynamic scope: consequences are unspecified +if FUNCTION is not fully re-entrant. + +Errors from FUNCTION are handled and cause a WARNING to be +signalled in whichever thread the FUNCTION was called in. + +Examples: + + ;;; good + (let* ((handle (get-handle)) + (object (make-object handle))) + ;; assumes RELEASE-HANDLE is re-entrant + (finalize object (lambda () (release-handle handle))) + object) + + ;;; bad, finalizer refers to object being finalized, causing + ;;; it to be retained indefinitely + (let* ((handle (get-handle)) + (object (make-object handle))) + (finalize object (lambda () (release-handle (object-handle object))))) + + ;;; bad, not re-entrant + (defvar *rec* nil) + + (defun oops () + (when *rec* + (error \"recursive OOPS\")) + (let ((*rec* t)) + (gc))) ; or just cons enough to cause one + + (progn + (finalize \"oops\" #'oops) + (oops)) ; causes GC and re-entry to #'oops due to the finalizer + ; -> ERROR, caught, WARNING signalled" + (sb!sys:without-gcing + (sb!thread:with-mutex (*finalizer-store-lock*) + (push (cons (make-weak-pointer object) function) + *finalizer-store*))) object) (defun cancel-finalization (object) @@ -32,22 +70,24 @@ the finalizer may run in any thread." ;; Check for NIL to avoid deleting finalizers that are waiting to be ;; run. (when object - (sb!thread:with-mutex (*finalizer-store-lock*) - (setf *finalizer-store* - (delete object *finalizer-store* - :key (lambda (pair) - (weak-pointer-value (car pair)))))) + (sb!sys:without-gcing + (sb!thread:with-mutex (*finalizer-store-lock*) + (setf *finalizer-store* + (delete object *finalizer-store* + :key (lambda (pair) + (weak-pointer-value (car pair))))))) object)) (defun run-pending-finalizers () (let (pending) - (sb!thread:with-mutex (*finalizer-store-lock*) - (setf *finalizer-store* - (delete-if (lambda (pair) - (when (null (weak-pointer-value (car pair))) - (push (cdr pair) pending) - t)) - *finalizer-store*))) + (sb!sys:without-gcing + (sb!thread:with-mutex (*finalizer-store-lock*) + (setf *finalizer-store* + (delete-if (lambda (pair) + (when (null (weak-pointer-value (car pair))) + (push (cdr pair) pending) + t)) + *finalizer-store*)))) ;; We want to run the finalizer bodies outside the lock in case ;; finalization of X causes finalization to be added for Y. (dolist (fun pending) diff --git a/src/code/weak.lisp b/src/code/weak.lisp index 37b83a1..7268b38 100644 --- a/src/code/weak.lisp +++ b/src/code/weak.lisp @@ -14,17 +14,15 @@ (defun make-weak-pointer (object) #!+sb-doc "Allocate and return a weak pointer which points to OBJECT." - (declare (values weak-pointer)) (make-weak-pointer object)) #!-sb-fluid (declaim (inline weak-pointer-value)) (defun weak-pointer-value (weak-pointer) #!+sb-doc "If WEAK-POINTER is valid, return the value of WEAK-POINTER and T. - If the referent of WEAK-POINTER has been garbage collected, returns - the values NIL and NIL." - (declare (type weak-pointer weak-pointer) - (values t (member t nil))) +If the referent of WEAK-POINTER has been garbage collected, +returns the values NIL and NIL." + (declare (type weak-pointer weak-pointer)) ;; We don't need to wrap this with a WITHOUT-GCING, because once we ;; have extracted the value, our reference to it will keep the weak ;; pointer from becoming broken. We just have to make sure the diff --git a/version.lisp-expr b/version.lisp-expr index a795dd1..c29142b 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -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.8.21.30" +"0.8.21.31" -- 1.7.10.4