X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=tests%2Fthreads.impure.lisp;h=5d1a380bd48efc7594a7c922ba0dabdfcfa0c2a0;hb=54e97796e29cb89892dd30c8cb8c5e9d0a870f94;hp=8002d5b1007c19cf46c60006b9ec5b6761b5dea3;hpb=2a860441fcd4181c0a511094397fdc6b6511b280;p=sbcl.git diff --git a/tests/threads.impure.lisp b/tests/threads.impure.lisp index 8002d5b..5d1a380 100644 --- a/tests/threads.impure.lisp +++ b/tests/threads.impure.lisp @@ -114,11 +114,10 @@ (with-mutex (l) (with-recursive-lock (l))))) -(let ((l (make-spinlock :name "spinlock")) - (p *current-thread*)) +(let ((l (make-spinlock :name "spinlock"))) (assert (eql (spinlock-value l) 0) nil "1") (with-spinlock (l) - (assert (eql (spinlock-value l) p) nil "2")) + (assert (eql (spinlock-value l) 1) nil "2")) (assert (eql (spinlock-value l) 0) nil "3")) ;; test that SLEEP actually sleeps for at least the given time, even @@ -476,21 +475,89 @@ (lambda () (sb-ext:run-program "sleep" '("1") :search t :wait nil))) -(with-test (:name (:thread-start :dynamic-values-and-gc)) - (let ((gc-thread (sb-thread:make-thread (lambda () - (loop (sleep (random 0.2)) - (sb-ext:gc :full t)))))) - (wait-for-threads - (loop for i below 3000 - when (zerop (mod i 30)) - do (princ ".") - collect - (let ((*x* (lambda ()))) - (declare (special *x*)) - (sb-thread:make-thread (lambda () (functionp *x*)))))) - (sb-thread:terminate-thread gc-thread) - (terpri))) - +;;;; Binding stack safety + +(defparameter *x* nil) +(defparameter *n-gcs-requested* 0) +(defparameter *n-gcs-done* 0) + +(let ((counter 0)) + (defun make-something-big () + (let ((x (make-string 32000))) + (incf counter) + (let ((counter counter)) + (sb-ext:finalize x (lambda () (format t " ~S" counter) + (force-output))))))) + +(defmacro wait-for-gc () + `(progn + (incf *n-gcs-requested*) + (loop while (< *n-gcs-done* *n-gcs-requested*)))) + +(defun send-gc () + (loop until (< *n-gcs-done* *n-gcs-requested*)) + (format t "G" *n-gcs-requested* *n-gcs-done*) + (force-output) + (sb-ext:gc) + (incf *n-gcs-done*)) + +(defun exercise-binding () + (loop + (let ((*x* (make-something-big))) + (let ((*x* 42)) + ;; at this point the binding stack looks like this: + ;; NO-TLS-VALUE-MARKER, *x*, SOMETHING, *x* + t)) + (wait-for-gc) + ;; sig_stop_for_gc_handler binds FREE_INTERRUPT_CONTEXT_INDEX. By + ;; now SOMETHING is gc'ed and the binding stack looks like this: 0, + ;; 0, SOMETHING, 0 (because the symbol slots are zeroed on + ;; unbinding but values are not). + (let ((*x* nil)) + ;; bump bsp as if a BIND had just started + (incf sb-vm::*binding-stack-pointer* 2) + (wait-for-gc) + (decf sb-vm::*binding-stack-pointer* 2)))) + +(with-test (:name (:binding-stack-gc-safety)) + (let (threads) + (unwind-protect + (progn + (push (sb-thread:make-thread #'exercise-binding) threads) + (push (sb-thread:make-thread (lambda () + (loop + (send-gc)))) + threads) + (sleep 4)) + (mapc #'sb-thread:terminate-thread threads)))) + +(format t "~&binding test done~%") + +;; Try to corrupt the NEXT-VECTOR. Operations on a hash table with a +;; cyclic NEXT-VECTOR can loop endlessly in a WITHOUT-GCING form +;; causing the next gc hang SBCL. +(with-test (:name (:hash-table-thread-safety)) + (let* ((hash (make-hash-table)) + (threads (list (sb-thread:make-thread + (lambda () + (loop + ;;(princ "1") (force-output) + (setf (gethash (random 100) hash) 'h)))) + (sb-thread:make-thread + (lambda () + (loop + ;;(princ "2") (force-output) + (remhash (random 100) hash)))) + (sb-thread:make-thread + (lambda () + (loop + (sleep (random 1.0)) + (sb-ext:gc :full t))))))) + (unwind-protect + (sleep 5) + (mapc #'sb-thread:terminate-thread threads)))) + +(format t "~&hash table test done~%") #| ;; a cll post from eric marsden | (defun crash () | (setq *debugger-hook*