Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use builtin SBCL thread API in test runner, or bordeaux-threads for #-sbcl #23

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ace.test.asd
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
:version "1.0"
:author "Lisp Community"
:license "MIT"
:depends-on (bordeaux-threads closer-mop trivial-garbage ace.core)
;; FIXME: does it still need closer-mop?
:depends-on (#-sbcl bordeaux-threads closer-mop trivial-garbage ace.core)
:in-order-to ((test-op (test-op :ace.test/tests)))
:serial t
:components
Expand Down
17 changes: 13 additions & 4 deletions main.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,25 @@

(in-package :ace.test.main)

;;; Compatibility shims
#+sbcl
(progn
(eval-when (:compile-toplevel :load-toplevel :execute)
(import '(sb-thread:make-thread)))
(defun all-threads () (sb-thread:list-all-threads)))
#-sbcl
(eval-when (:compile-toplevel :load-toplevel :execute)
(import '(bordeaux-threads:make-thread bordeaux-threads:all-threads)))

(defun start-timeout-watcher ()
"Runs a watcher for TIMEOUT minus 5 sec. and prints stack traces if not dead."
(let ((timeout (ace.test.runner:timeout)))
(let ((timeout (ace.test.runner:default-timeout)))
(when (and timeout (> timeout 5))
(flet ((timeout-watcher ()
(sleep (- timeout 5))
(format *error-output* "INFO: The test is about to timeout.~%")
(thread:print-backtraces)))
(thread:make-thread #'timeout-watcher :name "Timeout-Watcher")))))
(make-thread #'timeout-watcher :name "Timeout-Watcher")))))

#+google3
(flag:define ace.test.runner::*parallel* t
Expand Down Expand Up @@ -66,6 +76,5 @@ If ABORT is true, the process exits recklessly without cleaning up."
(sb-thread:%dispose-thread-structs)
;; - thread structures (not threads) awaiting reuse in the recycle list
(sb-alien:alien-funcall empty-thread-recyclebin))
(format *error-output* "INFO: Exiting with ~D thread~:p remaining.~%"
(length (thread:all-threads)))
(format *error-output* "INFO: Exiting with ~D thread~:p remaining.~%" (length (all-threads)))
(exit :timeout 10))
35 changes: 25 additions & 10 deletions runner.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@

(defpackage #:ace.test.runner
(:use #:common-lisp #:ace.core)
(:import-from #:ace.core.thread
#:join-thread
#:make-thread
#:with-timeout
#:make-mutex
#:with-mutex)
(:import-from #:ace.core.tty
#:ttyp
#:*print-ansi*)
Expand All @@ -35,6 +29,7 @@
#:missed
#:*on-missed-expectation*
#:alternate-truth-form)
(:import-from #+sbcl #:sb-ext #-sbcl #:bordeaux-threads #:timeout)
(:export
;; Execution of tests.
#:*checks-count*
Expand All @@ -47,11 +42,28 @@
#:run-and-report-tests
#:deregister-tests
#:*debug-unit-tests*
#:timeout
;; TIMEOUT is a symbol naming a condition, and it was confusing to also have it name a function,
;; so the function is now named DEFAULT-TIMEOUT
#:default-timeout
#:order))

(in-package #:ace.test.runner)

;;; Compatibility shims
#+sbcl
(progn
(eval-when (:compile-toplevel :load-toplevel :execute)
(import '(sb-thread:make-thread sb-thread:join-thread sb-thread:with-mutex)))
(defmacro with-timeout ((time) &body body) `(sb-ext:with-timeout ,time ,@body))
(defun make-mutex (name) (sb-thread:make-mutex :name name)))
#-sbcl
(progn
(eval-when (:compile-toplevel :load-toplevel :execute)
(import '(bordeaux-threads:make-thread bordeaux-threads:join-thread)))
(defun make-mutex (name) (bordeaux-threads:make-lock name))
(defmacro with-mutex ((lock) &body body) `(bordeaux-threads:with-lock-held (,lock) ,@body))
(defmacro with-timeout (&whole form) `(bordeaux-threads:with-timeout ,@(cdr form))))

;;; Test execution.

(declaim (list *unit-tests*))
Expand Down Expand Up @@ -326,7 +338,7 @@ Returns true if there was no error."
(test-run-start-time run)
(handler-bind ((missed #'on-warning)
(error #'on-error)
(bordeaux-threads:timeout #'on-error))
(timeout #'on-error))
(loop do
(with-simple-restart (retry "Retry ~S" test)
(return
Expand All @@ -336,7 +348,7 @@ Returns true if there was no error."
(funcall (symbol-function test)))))))
(update-test-run run)))))

(defun timeout ()
(defun default-timeout ()
"Return a value for the default test timeout in seconds."
;; The test timeout is provided by blaze test in the TEST_TIMEOUT variable.
;; See: http://bazel.build/docs/test-encyclopedia.html
Expand Down Expand Up @@ -450,7 +462,7 @@ If PARALLEL is NIL, the PARALLEL tests will be empty."))
(let* ((run (make-test-run
:test test
:parallel (and parallel (not (get test 'order)))
:timeout (get test 'timeout (timeout))
:timeout (get test 'timeout (default-timeout))
:output-stream (make-string-output-stream)))
(package (symbol-package test))
(name (format nil "~@[~A::~]~A"
Expand Down Expand Up @@ -563,6 +575,9 @@ If PARALLEL is NIL, the PARALLEL tests will be empty."))
(prog1
(report-tests (%run-tests :debug nil :verbose verbose :out out) :out out)
;; Cleanup Lisp-gc managed c-objects so asan doesn't complain
;; This GC call assumes that cleanups are synchronous with completion of GC,
;; but we've seen ASAN complains anyway as it requires lots of other help.
;; So probably just remove this after further testing.
(trivial-garbage:gc :full t)))

(defun deregister-tests (&optional (select :all))
Expand Down
12 changes: 7 additions & 5 deletions test.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@
#:run-tests
#:order
#:timeout)
;; Use bordeaux-threads to minimize dependencies
;; TODO(czak): Move to mocks.lisp.
(:import-from #:bordeaux-threads
#:make-recursive-lock
#:with-recursive-lock-held)
(:export
;; Testing utilities.
#:signals
Expand Down Expand Up @@ -162,6 +157,13 @@ Example:
;;;
;;; Convenience for testing bad/unsafe legacy code that depends on global state.

(defun make-recursive-lock (name)
#+sbcl (sb-thread:make-mutex :name name)
#-sbcl (bordeaux-threads:make-recursive-lock name))
(defmacro with-recursive-lock-held ((lock) &body body)
#+sbcl `(sb-thread:with-recursive-lock (,lock) ,@body)
#-sbcl `(bordeaux-threads:with-recursive-lock-held (,lock) ,@body))

(defvar *unsafe-code-test-mutex* (make-recursive-lock "UNSAFE-CODE-TEST-MUTEX")
"Used to serialize tests that mutate global space.")

Expand Down
Loading