1 #+(or sb-safepoint interpreter
) (invoke-restart 'run-tests
::skip-file
)
3 (defvar *tmp
* 0.0) ; don't remove - used by the setq below
5 (declaim (fixnum *count
*))
11 (defglobal *maxdepth
* 0)
12 ;; Be gentler on 32-bit platforms
13 (defglobal *n-finalized-things
* (or #+(and 64-bit
(not sb-safepoint
)) 20000 10000))
14 (defglobal *weak-pointers
* nil
)
19 (push (make-weak-pointer x
) *weak-pointers
*)
20 (finalize x
(lambda ()
22 (max sb-kernel
:*free-interrupt-context-index
*
24 ;; cons 320K in the finalizer for #+64-bit,
25 ;; or 80K for #-64-bit
26 (setf *tmp
* (make-list *n-finalized-things
*))
27 (sb-ext:atomic-incf
*count
*)))
32 (sb-int:dx-let
((b (make-array 20))) (eval b
))
33 (sb-sys:scrub-control-stack
))
35 (defun run-consy-thing ()
37 (let ((junk (mapcar #'makejunk
38 (make-list (/ *n-finalized-things
* 10)))))
39 (setf junk
(foo junk
))
44 ; no threads - hope for the best with respect to conservative root retention
45 #-sb-thread
(run-consy-thing)
49 (sb-thread:join-thread
(sb-thread:make-thread
#'run-consy-thing
))
50 (gc :full t
)) ; one more time to clean everything up
52 ;;; Verify that the thread was started.
54 (with-test (:name
:finalizer-thread-started
)
55 (assert (typep sb-impl
::*finalizer-thread
* 'sb-thread
::thread
))
56 ;; We're going to assert on an approximate count of finalizers that ran,
57 ;; which is a bit sketchy.
58 ;; So call RUN-PENDING-FINALIZERS which actually does the work of helping out
59 ;; the finalizer thread.
60 ;; This also shows that it works to run finalization actions in two threads -
61 ;; the finalizer thread and this. Hence the need for ATOMIC-INCF on *count*.
62 (sb-impl::run-pending-finalizers
)
64 ;; Make sure the thread is done.
65 ;; This JOIN-THREADs it, so we know it's not executing.
66 (sb-impl::finalizer-thread-stop
))
68 ;;; This was failing with something like:
69 ;;; The assertion (<= *MAXDEPTH* 1) failed with *MAXDEPTH* = 232.
70 ;;; The test parameters for 64-bit are quite severe, but should not exhaust the heap.
71 (with-test (:name
:finalizers-dont-nest-garbage-collections
)
72 (assert (<= *maxdepth
* 1)))
74 (with-test (:name
:finalizers-ran
)
75 ;; Finalizers won't have run for keys needing to be rehashed.
76 (unless (null sb-impl
::*finalizer-rehashlist
*)
77 (format t
"~&::: INFO: rehashing finalizer store~%")
78 (sb-impl::finalizers-rehash
)
80 (sb-impl::run-pending-finalizers
))
81 ;; expect that 97% of the finalizers ran
82 (assert (>= *count
* (* *n-finalized-things
* 97/100)))
83 (unless (= *count
* *n-finalized-things
*)
84 ;; show how the junk was reachable
85 (search-roots *weak-pointers
* :print
:verbose
)))
87 ;;; For finalizers that didn't run (if any), we had better find
88 ;;; that the object still exists in *weak-pointers*.
89 ;;; Conversely, for each intact weak pointer, there had better be
90 ;;; a finalizer for that object.
91 ;;; #+weak-vector-readbarrier could be made to pass, but scarcely seems
92 ;;; worth the effort since finalizers work if and only if weak-pointers do.
93 (with-test (:name
:finalizer-state
94 :skipped-on
:weak-vector-readbarrier
)
96 (delete-if (lambda (x) (null (weak-pointer-value x
)))
98 (let ((solist sb-impl
::**finalizer-store
**))
99 (sb-lockless:so-maplist
101 (let ((k (sb-sys:without-gcing
(sb-impl::finalizer-object node
))))
102 (when (and (symbolp k
) (not (symbol-package k
)))
103 (assert (find k
*weak-pointers
* :key
#'weak-pointer-value
)))))
105 (sb-sys:without-gcing
106 (dolist (wp *weak-pointers
*)
107 (let ((addr (sb-kernel:%make-lisp-obj
108 (logandc2 (sb-kernel:get-lisp-obj-address
109 (weak-pointer-value wp
))
110 sb-vm
:lowtag-mask
))))
111 (assert (sb-lockless:so-find solist addr
)))))))
113 ;;; A super-smart GC and/or compiler might prove that the object passed to
114 ;;; FINALIZE is instantly garbage. Like maybe (FINALIZE (CONS 1 2) 'somefun)
115 ;;; with the object otherwise unreachable. And so the system might reasonably
116 ;;; call #'SOMEFUN right away. Hence it had better be a function so that the
117 ;;; error isn't just shoved over to the finalizer thread.
118 ;;; Also, as a special case caught by the general case, I'd rather not see NILs
119 ;;; in the finalizer table, because NIL could never be defined as a function.
120 (with-test (:name
:finalizer-funarg
)
121 ;; The :no-function-conversion option in fndb was removed, for two reasons:
122 ;; - unlike with SET-MACRO-CHARACTER there is no "inquiry" function that you
123 ;; could use to determine what symbol was given as the funarg.
124 ;; Whereas I prefer lazy resolution in readtables because GET-MACRO-CHARACTER
125 ;; should return 'FUN if that's what you had set, and not #'FUN.
126 ;; - I can't particularly see anyone making the claim that a weird use such as
127 ;; (FINALIZE (CONS 1 2) 'STRING=))) should not emit e a warning about #'STRING=
128 ;; being funcalled with zero args when it should receive two.
129 (assert (nth-value 1 (compile nil
'(lambda () (finalize (cons 1 2) 'string
=)))))
130 ;; I make this mistake sometimes in GC testing - forgetting to wrap
131 ;; a FORMAT in a LAMBDA. So this had better fail early and often.
132 (assert-error (finalize (cons 'a
'b
) (format t
"The object died~%")))
133 ;; This too, even if you think this is a little different, because
134 ;; you _could_ define this function. But it's not different.
135 ;; The attempted call to #'no-function-for-you may arbitrarily occur
136 ;; (in theory) as soon as the system is able to detect garbage.
137 (assert-error (finalize (cons 1 2) 'no-function-for-you
)))