diff options
author | Andy Wingo <wingo@pobox.com> | 2016-11-19 14:54:44 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2016-11-19 14:54:44 +0100 |
commit | 1e925119969ea58396c79ab8e6c6c0130471eb22 (patch) | |
tree | 1ee388d2e4b06f9ff6da00c99baf5a462faa3d12 /test-suite/tests/asyncs.test | |
parent | 08584310ee5fc254854ef98bb2c5f4da3063f9c9 (diff) | |
download | guile-1e925119969ea58396c79ab8e6c6c0130471eb22.tar.gz |
Add asyncs test
* test-suite/tests/asyncs.test: New file.
Diffstat (limited to 'test-suite/tests/asyncs.test')
-rw-r--r-- | test-suite/tests/asyncs.test | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/test-suite/tests/asyncs.test b/test-suite/tests/asyncs.test new file mode 100644 index 000000000..437927a81 --- /dev/null +++ b/test-suite/tests/asyncs.test @@ -0,0 +1,138 @@ +;;;; asyncs.test -*- mode: scheme; coding: utf-8; -*- +;;;; +;;;; Copyright (C) 2016 Free Software Foundation, Inc. +;;;; +;;;; This library is free software; you can redistribute it and/or +;;;; modify it under the terms of the GNU Lesser General Public +;;;; License as published by the Free Software Foundation; either +;;;; version 3 of the License, or (at your option) any later version. +;;;; +;;;; This library is distributed in the hope that it will be useful, +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;;; Lesser General Public License for more details. +;;;; +;;;; You should have received a copy of the GNU Lesser General Public +;;;; License along with this library; if not, write to the Free Software +;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +(define-module (test-asyncs) + #:use-module (ice-9 control) + #:use-module (ice-9 q) + #:use-module (ice-9 atomic) + #:use-module (ice-9 threads) + #:use-module (test-suite lib)) + + +(with-test-prefix "interrupts" + (pass-if-equal "self-interruptable v1" 42 + (let/ec break + (let lp ((n 0)) + (when (= n 10) + (system-async-mark (lambda () (break 42)))) + (lp (1+ n))))) + + (pass-if-equal "self-interruptable v2" 42 + (let/ec break + (begin + (system-async-mark (lambda () (break 42))) + (let lp () (lp)))))) + +(define (with-sigprof-interrupts hz interrupt proc) + (let ((prev-handler #f) + (period-usecs (inexact->exact (round (/ 1e6 hz))))) + (define (profile-signal-handler _) (interrupt)) + (dynamic-wind + (lambda () + (set! prev-handler (car (sigaction SIGPROF profile-signal-handler))) + (setitimer ITIMER_PROF 0 period-usecs 0 period-usecs)) + proc + (lambda () + (setitimer ITIMER_PROF 0 0 0 0) + (sigaction SIGPROF prev-handler))))) + +(when (defined? 'setitimer) + (pass-if "preemption via sigprof" + ;; Use an atomic box as a compiler barrier. + (let* ((box (make-atomic-box 0)) + (preempt-tag (make-prompt-tag)) + (runqueue (make-q))) + (define (run-cothreads) + (unless (q-empty? runqueue) + (let ((k (deq! runqueue))) + (call-with-prompt preempt-tag + k + (lambda (k) (enq! runqueue k)))) + (run-cothreads))) + (enq! runqueue (lambda () + (let lp () + (let ((x (atomic-box-ref box))) + (unless (= x 100) + (when (even? x) + (atomic-box-set! box (1+ x))) + (lp)))))) + (enq! runqueue (lambda () + (let lp () + (let ((x (atomic-box-ref box))) + (unless (= x 100) + (when (odd? x) + (atomic-box-set! box (1+ x))) + (lp)))))) + (with-sigprof-interrupts + 1000 ; Hz + (lambda () + ;; Could throw an exception if the prompt is + ;; not active (i.e. interrupt happens + ;; outside running a cothread). Ignore in + ;; that case. + (false-if-exception (abort-to-prompt preempt-tag))) + run-cothreads) + (equal? (atomic-box-ref box) 100)))) + +(when (provided? 'threads) + (pass-if "preemption via external thread" + ;; Use an atomic box as a compiler barrier. + (let* ((box (make-atomic-box 0)) + (preempt-tag (make-prompt-tag)) + (runqueue (make-q))) + (define (run-cothreads) + (unless (q-empty? runqueue) + (let ((k (deq! runqueue))) + (call-with-prompt preempt-tag + k + (lambda (k) (enq! runqueue k)))) + (run-cothreads))) + (enq! runqueue (lambda () + (let lp () + (let ((x (atomic-box-ref box))) + (unless (= x 100) + (when (even? x) + (atomic-box-set! box (1+ x))) + (lp)))))) + (enq! runqueue (lambda () + (let lp () + (let ((x (atomic-box-ref box))) + (unless (= x 100) + (when (odd? x) + (atomic-box-set! box (1+ x))) + (lp)))))) + (let* ((main-thread (current-thread)) + (preempt-thread (call-with-new-thread + (lambda () + (let lp () + (unless (= (atomic-box-ref box) 100) + (usleep 1000) + (system-async-mark + (lambda () + ;; Could throw an exception if the + ;; prompt is not active + ;; (i.e. interrupt happens outside + ;; running a cothread). Ignore in + ;; that case. + (false-if-exception + (abort-to-prompt preempt-tag))) + main-thread) + (lp))))))) + (run-cothreads) + (join-thread preempt-thread) + (equal? (atomic-box-ref box) 100))))) |