summaryrefslogtreecommitdiff
path: root/test-suite/tests/asyncs.test
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2016-11-19 14:54:44 +0100
committerAndy Wingo <wingo@pobox.com>2016-11-19 14:54:44 +0100
commit1e925119969ea58396c79ab8e6c6c0130471eb22 (patch)
tree1ee388d2e4b06f9ff6da00c99baf5a462faa3d12 /test-suite/tests/asyncs.test
parent08584310ee5fc254854ef98bb2c5f4da3063f9c9 (diff)
downloadguile-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.test138
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)))))