[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Chicken-hackers] [PATCH] Overhaul interrupt handling
From: |
Felix |
Subject: |
[Chicken-hackers] [PATCH] Overhaul interrupt handling |
Date: |
Thu, 27 Oct 2011 06:25:30 -0400 (EDT) |
This patch adds some cleanups and enhancements to the interrupt and
signal-handling facilities, as posted recently. Thanks to Joerg
Wittenberger and Alan Post for their valuable suggestions, which have
been incorporated in this change. I have tested it on Linux and the
core system appears to operate normally on Windows so far (the
signal-test program from the test suite is currently disabled for this
platform). Depending on system load, interrupt/signal frequency and
threading issues, it is quite possible that certain corner cases are
not handled yet.
cheers,
felix
>From ad9e59350be0a4d2476e202e495c20a37fdfa9de Mon Sep 17 00:00:00 2001
From: felix <address@hidden>
Date: Thu, 27 Oct 2011 12:08:23 +0200
Subject: [PATCH] Overhaul interrupt handling:
- EINTR handling for all read-operations from tcp, file and process streams
- signals are queued (up to a certain limit, with the usual restrictions given
by UNIX)
- added silly test-file
- csi installs SIGINT handler directly (independent of the posix unit)
- added setter for "signal-handler"
- moved some more code into "posix-common"
Squashed commit of the following:
commit fddac7bf61ea49ff44b122bd1c61a914f312d967
Merge: 931bb0a 814cd2f
Author: felix <address@hidden>
Date: Mon Oct 24 11:44:01 2011 +0200
Merge commit 'origin/blocked-signals' into blocked-signals
commit 931bb0a602fbb3030863fb39cdc6f45b8ad70de7
Author: felix <address@hidden>
Date: Mon Oct 24 11:42:58 2011 +0200
fixed incorrect option when compiling signal-test.scm
commit 8f32dfd10d68fbf9138720fabbf6fa4f4b939549
Merge: e2724e1 159611d
Author: felix <address@hidden>
Date: Mon Oct 24 11:32:42 2011 +0200
resolved conflicts
commit 814cd2f4f6fe60ca1436440fc4fb1e10750e64b3
Author: felix <address@hidden>
Date: Fri Oct 21 02:49:19 2011 +0200
EINTR handling for process-I/O and read-line/read-string from FP
commit bd4b427948af203d1e74099b4627b303b3003d32
Merge: 0069002 17b58b8
Author: felix <address@hidden>
Date: Wed Oct 12 14:46:17 2011 +0200
Merge remote-tracking branch 'origin/master' into blocked-signals
commit 00690020d3b514e607536397a48da97a01b672a9
Author: felix <address@hidden>
Date: Wed Oct 12 14:39:09 2011 +0200
reverted change to test file
commit 608dba68f9e4f2aa8d9440ca074ff274ced9c244
Merge: 82fbcd8 1ec7470
Author: felix <address@hidden>
Date: Wed Oct 12 14:38:21 2011 +0200
Merge branch 'master' into blocked-signals
commit 82fbcd862677c77f80f7af2d71b1c0b9c14de896
Author: felix <address@hidden>
Date: Wed Oct 12 09:56:20 2011 +0200
disable failing numbers/string-conv test for windows
commit 83fe6fba1b1980d21f401e3a01e12b1330208918
Author: felix <address@hidden>
Date: Wed Oct 12 09:55:00 2011 +0200
wrong option when compiling signal-tests.scm
commit e2724e1729f32e757b581f7b659949b614886dfc
Author: felix <address@hidden>
Date: Tue Oct 11 12:17:44 2011 +0200
fixes in signal-test
commit 806b4b70445b3b92185a3800205b74aee2f15665
Author: felix <address@hidden>
Date: Mon Oct 10 12:00:10 2011 +0200
added background threads to signal-test
commit 7fbaae02f525c5d0e51955c8359b2bad021f17f7
Author: felix <address@hidden>
Date: Fri Oct 7 22:48:35 2011 +0200
- moved low-level signal handling into library
- establish SIGINT handler in csi (posix not needed)
- added internal exn category #:memory-error (unused in the moment - this
was intended for SIGSEGV handling, but ... not sure)
- added setter for "signal-handler"
- added note to manual about order of handling when signal-overrun occurs
- "signal-handler" and setter moved to "posix-common.scm"
- gave label in C_reclaim a more meaningful name
- C_raise_interrupt drops interrupts if pending stack is full
- C_i_pending_interrupts ignores timer interrupts
- EINTR handling for tcp accept/connect
- signal-tests fixes
commit 2795100e4c52fa7253d2ee8f188317b36f9a718a
Author: felix <address@hidden>
Date: Fri Oct 7 13:04:56 2011 +0200
stack signals that arrive during handling; explicit EINTR handling in
stream and tcp ports (Note: what about accept/connect?)
commit 5104223a382f8147e210dd4bf5df553307f75c80
Author: felix <address@hidden>
Date: Fri Oct 7 13:02:58 2011 +0200
do windows test in test-file, not in runtests.sh; added signal tests
commit d00768d2f84071cfe16ecea2569717de7900f64e
Author: felix <address@hidden>
Date: Fri Oct 7 10:18:34 2011 +0200
learning about EINTR - how could this ever have worked?
commit 7a058a84e0a8ff74b1d1cf2f051bd6eb0674bd61
Author: felix <address@hidden>
Date: Fri Oct 7 10:18:11 2011 +0200
applied rest of Alan's patch
commit ac391091f12794e654545c424ede8ed2a99f6d3c
Merge: a5b3914 3a9e0f2
Author: felix <address@hidden>
Date: Fri Oct 7 08:20:57 2011 +0200
Merge branch 'master' into blocked-signals
commit a5b391482a6351e42068762cd7940fd44c035c1d
Author: felix <address@hidden>
Date: Sun Oct 2 13:07:59 2011 +0200
use sigaction(3) instead of signal(3) where available. Patch by Alan Post,
problem originally spotted by Joerg Wittenberger
---
Makefile.bsd | 1 +
Makefile.cygwin | 1 +
Makefile.haiku | 1 +
Makefile.linux | 1 +
Makefile.macosx | 1 +
Makefile.solaris | 1 +
chicken.h | 4 ++
csi.scm | 16 ++++++++
distribution/manifest | 1 +
library.scm | 71 ++++++++++++++++++++++++++++++-------
manual/Unit posix | 14 +++++--
posix-common.scm | 16 ++++++++-
posixunix.scm | 70 +++++++++++++------------------------
posixwin.scm | 19 ----------
runtime.c | 81 ++++++++++++++++++++++++++++++++++++------
tcp.scm | 65 ++++++++++++++++++++--------------
tests/arithmetic-test.scm | 7 ++++
tests/runtests.sh | 9 +++--
tests/signal-tests.scm | 85 +++++++++++++++++++++++++++++++++++++++++++++
19 files changed, 338 insertions(+), 126 deletions(-)
create mode 100644 tests/signal-tests.scm
diff --git a/Makefile.bsd b/Makefile.bsd
index 5eab203..98e44fd 100644
--- a/Makefile.bsd
+++ b/Makefile.bsd
@@ -83,6 +83,7 @@ chicken-config.h: chicken-defaults.h
echo "#define HAVE_LONG_LONG 1" >>$@
echo "#define HAVE_MEMMOVE 1" >>$@
echo "#define HAVE_MEMORY_H 1" >>$@
+ echo "#define HAVE_SIGACTION 1" >>$@
echo "#define HAVE_STDINT_H 1" >>$@
echo "#define HAVE_STDLIB_H 1" >>$@
echo "#define HAVE_STRERROR 1" >>$@
diff --git a/Makefile.cygwin b/Makefile.cygwin
index f56bc29..cee6e74 100644
--- a/Makefile.cygwin
+++ b/Makefile.cygwin
@@ -95,6 +95,7 @@ chicken-config.h: chicken-defaults.h
echo "#define HAVE_LONG_LONG 1" >>$@
echo "#define HAVE_MEMMOVE 1" >>$@
echo "#define HAVE_MEMORY_H 1" >>$@
+ echo "#define HAVE_SIGACTION 1" >>$@
echo "#define HAVE_STDINT_H 1" >>$@
echo "#define HAVE_STDLIB_H 1" >>$@
echo "#define HAVE_STRERROR 1" >>$@
diff --git a/Makefile.haiku b/Makefile.haiku
index 1f86bc3..54634a2 100644
--- a/Makefile.haiku
+++ b/Makefile.haiku
@@ -71,6 +71,7 @@ chicken-config.h: chicken-defaults.h
echo "#define HAVE_LONG_LONG 1" >>$@
echo "#define HAVE_MEMMOVE 1" >>$@
echo "#define HAVE_MEMORY_H 1" >>$@
+ echo "#define HAVE_SIGACTION 1" >>$@
echo "#define HAVE_STDINT_H 1" >>$@
echo "#define HAVE_STDLIB_H 1" >>$@
echo "#define HAVE_STRERROR 1" >>$@
diff --git a/Makefile.linux b/Makefile.linux
index c713b45..6e5116a 100644
--- a/Makefile.linux
+++ b/Makefile.linux
@@ -72,6 +72,7 @@ chicken-config.h: chicken-defaults.h
echo "#define HAVE_LONG_LONG 1" >>$@
echo "#define HAVE_MEMMOVE 1" >>$@
echo "#define HAVE_MEMORY_H 1" >>$@
+ echo "#define HAVE_SIGACTION 1" >>$@
echo "#define HAVE_STDINT_H 1" >>$@
echo "#define HAVE_STDLIB_H 1" >>$@
echo "#define HAVE_STRERROR 1" >>$@
diff --git a/Makefile.macosx b/Makefile.macosx
index b4a44d9..da612a4 100644
--- a/Makefile.macosx
+++ b/Makefile.macosx
@@ -96,6 +96,7 @@ chicken-config.h: chicken-defaults.h
echo "#define HAVE_LONG_LONG 1" >>$@
echo "#define HAVE_MEMMOVE 1" >>$@
echo "#define HAVE_MEMORY_H 1" >>$@
+ echo "#define HAVE_SIGACTION 1" >>$@
echo "#define HAVE_STDINT_H 1" >>$@
echo "#define HAVE_STDLIB_H 1" >>$@
echo "#define HAVE_STRERROR 1" >>$@
diff --git a/Makefile.solaris b/Makefile.solaris
index f2d4dee..84dc433 100644
--- a/Makefile.solaris
+++ b/Makefile.solaris
@@ -102,6 +102,7 @@ chicken-config.h: chicken-defaults.h
echo "#define HAVE_LONG_LONG 1" >>$@
echo "#define HAVE_MEMMOVE 1" >>$@
echo "#define HAVE_MEMORY_H 1" >>$@
+ echo "#define HAVE_SIGACTION 1" >>$@
echo "#define HAVE_STDINT_H 1" >>$@
echo "#define HAVE_STDLIB_H 1" >>$@
echo "#define HAVE_STRERROR 1" >>$@
diff --git a/chicken.h b/chicken.h
index af17015..8169f6d 100644
--- a/chicken.h
+++ b/chicken.h
@@ -863,6 +863,9 @@ DECL_C_PROC_p0 (128, 1,0,0,0,0,0,0,0)
# define C_isatty isatty
# define C_fileno fileno
# define C_select select
+# if defined(HAVE_SIGACTION)
+# define C_sigaction sigaction
+# endif
# define C_signal signal
# define C_getrusage getrusage
# define C_tolower tolower
@@ -1848,6 +1851,7 @@ C_fctexport void C_ccall
C_peek_unsigned_integer_32(C_word c, C_word closure, C_
#endif
C_fctexport C_word C_fcall C_decode_literal(C_word **ptr, C_char *str)
C_regparm;
+C_fctexport C_word C_fcall C_i_pending_interrupt(C_word dummy) C_regparm;
/* defined in eval.scm: */
C_fctexport void CHICKEN_get_error_message(char *buf,int bufsize);
diff --git a/csi.scm b/csi.scm
index fa95e2f..8846dd4 100644
--- a/csi.scm
+++ b/csi.scm
@@ -31,6 +31,8 @@
(disable-interrupts)
(compile-syntax)
(foreign-declare #<<EOF
+#include <signal.h>
+
#if defined(HAVE_DIRECT_H)
# include <direct.h>
#else
@@ -906,6 +908,20 @@ EOF
(##sys#void))))))
+;;; Handle some signals:
+
+(define-foreign-variable _sigint int "SIGINT")
+
+(define-syntax defhandler
+ (syntax-rules ()
+ ((_ sig handler)
+ (begin
+ (##core#inline "C_establish_signal_handler" sig sig)
+ (##sys#setslot ##sys#signal-vector sig handler)))))
+
+(defhandler _sigint (lambda (n) (##sys#user-interrupt-hook)))
+
+
;;; Start interpreting:
(define (member* keys set)
diff --git a/distribution/manifest b/distribution/manifest
index 2c3a43a..dd39f86 100644
--- a/distribution/manifest
+++ b/distribution/manifest
@@ -198,6 +198,7 @@ tests/reverser/tags/1.1/reverser.meta
tests/reverser/tags/1.1/reverser.setup
tests/reverser/tags/1.1/reverser.scm
tests/rev-app.scm
+tests/signal-tests.scm
tweaks.scm
utils.scm
apply-hack.x86.S
diff --git a/library.scm b/library.scm
index 8075c2f..9b65ad2 100644
--- a/library.scm
+++ b/library.scm
@@ -76,12 +76,18 @@ fast_read_line_from_file(C_word str, C_word port, C_word
size) {
C_FILEPTR fp = C_port_file(port);
if ((c = C_getc(fp)) == EOF)
- return C_SCHEME_END_OF_FILE;
+ return errno == EINTR ? C_fix(-1) : C_SCHEME_END_OF_FILE;
C_ungetc(c, fp);
for (i = 0; i < n; i++) {
c = C_getc(fp);
+
+ if(c == EOF && errno == EINTR) {
+ clearerr(fp);
+ return C_fix(-(i + 1));
+ }
+
switch (c) {
case '\r': if ((c = C_getc(fp)) != '\n') C_ungetc(c, fp);
case EOF: clearerr(fp);
@@ -101,7 +107,11 @@ fast_read_string_from_file(C_word dest, C_word port,
C_word len, C_word pos)
size_t m = fread (buf, sizeof (char), n, fp);
- if (m < n) {
+ if(m == EOF && errno == EINTR) {
+ clearerr(fp);
+ return C_fix(-1);
+ }
+ else if (m < n) {
if (feof (fp)) {
clearerr (fp);
if (0 == m)
@@ -1736,9 +1746,17 @@ EOF
(define ##sys#stream-port-class
(vector (lambda (p) ; read-char
- (##core#inline "C_read_char" p) )
+ (let loop ()
+ (let ((c (##core#inline "C_read_char" p)))
+ (if (eq? -1 c) ; EINTR
+ (##sys#dispatch-interrupt loop)
+ c))))
(lambda (p) ; peek-char
- (##core#inline "C_peek_char" p) )
+ (let loop ()
+ (let ((c (##core#inline "C_peek_char" p)))
+ (if (eq? -1 c) ; EINTR
+ (##sys#dispatch-interrupt loop)
+ c))))
(lambda (p c) ; write-char
(##core#inline "C_display_char" p c) )
(lambda (p s) ; write-string
@@ -1756,6 +1774,11 @@ EOF
(cond [(or (not len) ; error returns EOF
(eof-object? len)) ; EOF returns 0 bytes read
act]
+ ((fx< len 0) ; EINTR
+ (let ((len (fx< (fxneg len) 1)))
+ (##sys#dispatch-interrupt
+ (lambda ()
+ (loop (fx- rem len) (fx+ act len) (fx+ start
len))))))
[(fx< len rem)
(loop (fx- rem len) (fx+ act len) (fx+ start len))]
[else
@@ -1781,6 +1804,11 @@ EOF
(##sys#make-string (fx* len 2))
(##sys#string-append result buffer)
#t)) ]
+ ((fx< n 0) ; EINTR
+ (let ((n (fx- (fxneg n) 1)))
+ (##sys#dispatch-interrupt
+ (lambda ()
+ (loop len limit buffer result f)))))
[f (##sys#setislot p 4 (fx+ (##sys#slot p 4) 1))
(##sys#string-append result (##sys#substring buffer
0 n))]
[else
@@ -3909,6 +3937,7 @@ EOF
[(#:arity-error) '(exn arity)]
[(#:access-error) '(exn access)]
[(#:domain-error) '(exn domain)]
+ ((#:memory-error) '(exn memory))
[else '(exn)] )
(list '(exn . message) msg
'(exn . arguments) args
@@ -4344,10 +4373,23 @@ EOF
(define ##sys#context-switch (##core#primitive "C_context_switch"))
+(define ##sys#signal-vector (make-vector 256 #f))
+
(define (##sys#interrupt-hook reason state)
- (cond ((fx> (##sys#slot ##sys#pending-finalizers 0) 0)
- (##sys#run-pending-finalizers state) )
- (else (##sys#context-switch state) ) ) )
+ (let loop ((reason reason))
+ (cond ((and reason (##sys#slot ##sys#signal-vector reason)) =>
+ (lambda (handler)
+ (handler reason)
+ (loop (##core#inline "C_i_pending_interrupt" #f))))
+ ((fx> (##sys#slot ##sys#pending-finalizers 0) 0)
+ (##sys#run-pending-finalizers state) )
+ ((procedure? state) (state))
+ (else (##sys#context-switch state) ) ) ) )
+
+(define (##sys#dispatch-interrupt k)
+ (##sys#interrupt-hook
+ (##core#inline "C_i_pending_interrupt" #f)
+ k))
;;; Accessing "errno":
@@ -4568,19 +4610,20 @@ EOF
(vector-fill! ##sys#pending-finalizers (##core#undefined))
(##sys#setislot ##sys#pending-finalizers 0 0)
(set! working #f) ) )
- (when state (##sys#context-switch state) ) ) ) )
+ (cond ((not state))
+ ((procedure? state) (state))
+ (state (##sys#context-switch state) ) ) ) ))
(define (##sys#force-finalizers)
(let loop ()
(let ([n (##sys#gc)])
- (if (fx> (##sys#slot ##sys#pending-finalizers 0) 0)
- (begin
- (##sys#run-pending-finalizers #f)
- (loop) )
- n) ) ) )
+ (cond ((fx> (##sys#slot ##sys#pending-finalizers 0) 0)
+ (##sys#run-pending-finalizers #f)
+ (loop) )
+ (else n) ) ) ))
(define (gc . arg)
- (let ([a (and (pair? arg) (car arg))])
+ (let ((a (and (pair? arg) (car arg))))
(if a
(##sys#force-finalizers)
(apply ##sys#gc arg) ) ) )
diff --git a/manual/Unit posix b/manual/Unit posix
index 0f6d0a2..a81b834 100644
--- a/manual/Unit posix
+++ b/manual/Unit posix
@@ -848,6 +848,12 @@ after {{SECONDS}} are elapsed. You can use the
==== set-signal-handler!
+==== signal-handler
+
+<procedure>(signal-handler SIGNUM)</procedure>
+
+Returns the signal handler for the code {{SIGNUM}} or {{#f}}.
+
<procedure>(set-signal-handler! SIGNUM PROC)</procedure>
Establishes the procedure of one argument {{PROC}} as the handler
@@ -855,13 +861,13 @@ for the signal with the code {{SIGNUM}}. {{PROC}} is
called
with the signal number as its sole argument. If the argument {{PROC}} is {{#f}}
then any signal handler will be removed, and the corresponding signal set to
{{SIG_IGN}}.
-Note that is is unspecified in which thread of execution the signal handler
will be invoked.
+Notes
-==== signal-handler
+* it is unspecified in which thread of execution the signal handler will be
invoked.
-<procedure>(signal-handler SIGNUM)</procedure>
+* when signals arrive in quick succession (specifically, before the handler
for a signal has been started), then signals will be queued (up to a certain
limit); the order in which the queued signals will be handled is not specified
-Returns the signal handler for the code {{SIGNUM}} or {{#f}}.
+* {{(set! (signal-handler SIG) PROC)}} can be used as an alternative to
{{(set-signal-handler! SIG PROC)}}
==== set-signal-mask!
diff --git a/posix-common.scm b/posix-common.scm
index 89e87d3..20b5a7a 100644
--- a/posix-common.scm
+++ b/posix-common.scm
@@ -488,6 +488,21 @@ EOF
(##sys#error 'time->string "cannot convert time vector to
string" tm) ) ) ) ) ) )
+;;; Signals
+
+(define (set-signal-handler! sig proc)
+ (##sys#check-exact sig 'set-signal-handler!)
+ (##core#inline "C_establish_signal_handler" sig (and proc sig))
+ (vector-set! ##sys#signal-vector sig proc) )
+
+(define signal-handler
+ (getter-with-setter
+ (lambda (sig)
+ (##sys#check-exact sig 'signal-handler)
+ (##sys#slot ##sys#signal-vector sig) )
+ set-signal-handler!))
+
+
;;; Processes
(define current-process-id (foreign-lambda int "C_getpid"))
@@ -501,4 +516,3 @@ EOF
(if (fx= epid -1)
(posix-error #:process-error 'process-wait "waiting for child
process failed" pid)
(values epid enorm ecode) ) ) ) ) ) )
-
diff --git a/posixunix.scm b/posixunix.scm
index ec3df0f..f1af092 100644
--- a/posixunix.scm
+++ b/posixunix.scm
@@ -950,26 +950,6 @@ EOF
signal/tstp signal/pipe signal/xcpu signal/xfsz signal/usr1 signal/usr2
signal/winch))
-(let ([oldhook ##sys#interrupt-hook]
- [sigvector (make-vector 256 #f)] )
- (set! signal-handler
- (lambda (sig)
- (##sys#check-exact sig 'signal-handler)
- (##sys#slot sigvector sig) ) )
- (set! set-signal-handler!
- (lambda (sig proc)
- (##sys#check-exact sig 'set-signal-handler!)
- (##core#inline "C_establish_signal_handler" sig (and proc sig))
- (vector-set! sigvector sig proc) ) )
- (set! ##sys#interrupt-hook
- (lambda (reason state)
- (let ([h (##sys#slot sigvector reason)])
- (if h
- (begin
- (h reason)
- (##sys#context-switch state) )
- (oldhook reason state) ) ) ) ) )
-
(define set-signal-mask!
(lambda (sigs)
(##sys#check-list sigs 'set-signal-mask!)
@@ -1005,12 +985,6 @@ EOF
(when (fx< (##core#inline "C_sigprocmask_unblock" 0) 0)
(posix-error #:process-error 'signal-unmask! "cannot unblock signal") )
)
-;;; Set SIGINT handler:
-
-(set-signal-handler!
- signal/int
- (lambda (n) (##sys#user-interrupt-hook)) )
-
;;; Getting system-, group- and user-information:
@@ -1338,13 +1312,15 @@ EOF
(when (fx>= bufpos buflen)
(let loop ()
(let ([cnt (##core#inline "C_read" fd buf bufsiz)])
- (cond [(fx= cnt -1)
- (if (fx= _errno _ewouldblock)
- (begin
- (##sys#thread-block-for-i/o!
##sys#current-thread fd #:input)
- (##sys#thread-yield!)
- (loop) )
- (posix-error #:file-error loc "cannot read" fd
nam) )]
+ (cond ((fx= cnt -1)
+ (select errno
+ ((_ewouldblock)
+ (##sys#thread-block-for-i/o!
##sys#current-thread fd #:input)
+ (##sys#thread-yield!)
+ (loop) )
+ ((_eintr)
+ (##sys#dispatch-interrupt loop))
+ (else (posix-error #:file-error loc "cannot read"
fd nam) )))
[(and more? (fx= cnt 0))
; When "more" keep trying, otherwise
read once more
; to guard against race conditions
@@ -1445,18 +1421,21 @@ EOF
(define ##sys#custom-output-port
(lambda (loc nam fd #!optional (nonblocking? #f) (bufi 0) (on-close void))
(when nonblocking? (##sys#file-nonblocking! fd) )
- (letrec (
- [poke
+ (letrec ([poke
(lambda (str len)
- (let ([cnt (##core#inline "C_write" fd str len)])
- (cond [(fx= -1 cnt)
- (if (fx= _errno _ewouldblock)
- (begin
- (##sys#thread-yield!)
- (poke str len) )
- (posix-error loc #:file-error "cannot write" fd
nam) ) ]
- [(fx< cnt len)
- (poke (##sys#substring str cnt len) (fx- len cnt)) ] )
) )]
+ (let loop ()
+ (let ([cnt (##core#inline "C_write" fd str len)])
+ (cond ((fx= -1 cnt)
+ (select _errno
+ ((_ewouldblock)
+ (##sys#thread-yield!)
+ (poke str len) )
+ ((_eintr)
+ (##sys#dispatch-interrupt loop))
+ (else
+ (posix-error loc #:file-error "cannot write" fd
nam) ) ) )
+ ((fx< cnt len)
+ (poke (##sys#substring str cnt len) (fx- len cnt)) )
) ) ))]
[store
(let ([bufsiz (if (fixnum? bufi) bufi (##sys#size bufi))])
(if (fx= 0 bufsiz)
@@ -1480,8 +1459,7 @@ EOF
(set! bufpos (fx+ bufpos len))] ) )
(when (fx< 0 bufpos)
(poke buf bufpos) ) ) ) ) ) )])
- (letrec (
- [this-port
+ (letrec ([this-port
(make-output-port
(lambda (str) ; write-string
(store str) )
diff --git a/posixwin.scm b/posixwin.scm
index 2dd5a30..bc61b7e 100644
--- a/posixwin.scm
+++ b/posixwin.scm
@@ -1262,25 +1262,6 @@ EOF
signal/term signal/int signal/fpe signal/ill
signal/segv signal/abrt signal/break))
-(let ([oldhook ##sys#interrupt-hook]
- [sigvector (make-vector 256 #f)] )
- (set! signal-handler
- (lambda (sig)
- (##sys#check-exact sig 'signal-handler)
- (##sys#slot sigvector sig) ) )
- (set! set-signal-handler!
- (lambda (sig proc)
- (##sys#check-exact sig 'set-signal-handler!)
- (##core#inline "C_establish_signal_handler" sig (and proc sig))
- (vector-set! sigvector sig proc) ) )
- (set! ##sys#interrupt-hook
- (lambda (reason state)
- (let ([h (##sys#slot sigvector reason)])
- (if h
- (begin
- (h reason)
- (##sys#context-switch state) )
- (oldhook reason state) ) ) ) ) )
;;; More errno codes:
diff --git a/runtime.c b/runtime.c
index a6b2d35..3b00673 100644
--- a/runtime.c
+++ b/runtime.c
@@ -32,6 +32,7 @@
#include <assert.h>
#include <limits.h>
#include <math.h>
+#include <signal.h>
#ifdef HAVE_SYSEXITS_H
# include <sysexits.h>
@@ -159,6 +160,8 @@ extern void _C_do_apply_hack(void *proc, C_word *args, int
count) C_noret;
#define FILE_INFO_SIZE 7
+#define MAX_PENDING_INTERRUPTS 100
+
#ifdef C_DOUBLE_IS_32_BITS
# define FLONUM_PRINT_PRECISION 7
#else
@@ -441,6 +444,9 @@ static C_TLS FINALIZER_NODE
static C_TLS void *current_module_handle;
static C_TLS int flonum_print_precision = FLONUM_PRINT_PRECISION;
static C_TLS HDUMP_BUCKET **hdump_table;
+static C_TLS int
+ pending_interrupts[ MAX_PENDING_INTERRUPTS ],
+ pending_interrupts_count;
/* Prototypes: */
@@ -690,6 +696,7 @@ int CHICKEN_initialize(int heap, int stack, int symbols,
void *toplevel)
C_clear_trace_buffer();
chicken_is_running = chicken_ran_once = 0;
interrupt_reason = 0;
+ pending_interrupts_count = 0;
last_interrupt_latency = 0;
C_interrupts_enabled = 1;
C_initial_timer_interrupt_period = INITIAL_TIMER_INTERRUPT_PERIOD;
@@ -713,7 +720,7 @@ int CHICKEN_initialize(int heap, int stack, int symbols,
void *toplevel)
static C_PTABLE_ENTRY *create_initial_ptable()
{
- /* hardcoded table size - this must match the number of C_pte calls! */
+ /* IMPORTANT: hardcoded table size - this must match the number of C_pte
calls! */
C_PTABLE_ENTRY *pt = (C_PTABLE_ENTRY *)C_malloc(sizeof(C_PTABLE_ENTRY) * 60);
int i = 0;
@@ -745,6 +752,7 @@ static C_PTABLE_ENTRY *create_initial_ptable()
C_pte(C_divide);
C_pte(C_nequalp);
C_pte(C_greaterp);
+ /* IMPORTANT: have you read the comments at the start and the end of this
function? */
C_pte(C_lessp);
C_pte(C_greater_or_equal_p);
C_pte(C_less_or_equal_p);
@@ -779,7 +787,7 @@ static C_PTABLE_ENTRY *create_initial_ptable()
C_pte(C_filter_heap_objects);
C_pte(C_get_argument);
- /* did you remember the hardcoded pte table size? */
+ /* IMPORTANT: did you remember the hardcoded pte table size? */
pt[ i ].id = NULL;
return pt;
}
@@ -977,7 +985,9 @@ void initialize_symbol_table(void)
void global_signal_handler(int signum)
{
C_raise_interrupt(signal_mapping_table[ signum ]);
- signal(signum, global_signal_handler);
+#ifndef HAVE_SIGACTION
+ C_signal(signum, global_signal_handler);
+#endif
}
@@ -2645,7 +2655,7 @@ C_regparm void C_fcall C_reclaim(void *trampoline, void
*proc)
if(gc_mode == GC_REALLOC) {
C_rereclaim2(percentage(heap_size, C_heap_growth), 0);
gc_mode = GC_MAJOR;
- goto never_mind_edsgar;
+ goto i_like_spaghetti;
}
heap_scan_top = (C_byte *)C_align((C_uword)tospace_top);
@@ -2831,7 +2841,7 @@ C_regparm void C_fcall C_reclaim(void *trampoline, void
*proc)
tospace_limit = tmp;
}
- never_mind_edsgar:
+ i_like_spaghetti:
++gc_count_2;
if(C_enable_gcweak) {
@@ -3939,7 +3949,12 @@ C_regparm C_word C_fcall C_read_char(C_word port)
{
int c = C_getc(C_port_file(port));
- return c == EOF ? C_SCHEME_END_OF_FILE : C_make_character(c);
+ if(c == EOF) {
+ if(errno == EINTR) return C_fix(-1);
+ else return C_SCHEME_END_OF_FILE;
+ }
+
+ return C_make_character(c);
}
@@ -3948,8 +3963,13 @@ C_regparm C_word C_fcall C_peek_char(C_word port)
C_FILEPTR fp = C_port_file(port);
int c = C_getc(fp);
+ if(c == EOF) {
+ if(errno == EINTR) return C_fix(-1);
+ else return C_SCHEME_END_OF_FILE;
+ }
+
C_ungetc(c, fp);
- return c == EOF ? C_SCHEME_END_OF_FILE : C_make_character(c);
+ return C_make_character(c);
}
@@ -4197,16 +4217,25 @@ C_regparm void C_fcall
C_paranoid_check_for_interrupt(void)
C_regparm void C_fcall C_raise_interrupt(int reason)
{
if(C_interrupts_enabled) {
- saved_stack_limit = C_stack_limit;
+ if(interrupt_reason) {
+ if(reason != C_TIMER_INTERRUPT_NUMBER) {
+ if(pending_interrupts_count < MAX_PENDING_INTERRUPTS)
+ /* drop signals if too many */
+ pending_interrupts[ pending_interrupts_count++ ] = reason;
+ }
+ }
+ else {
+ saved_stack_limit = C_stack_limit;
#if C_STACK_GROWS_DOWNWARD
- C_stack_limit = C_stack_pointer + 1000;
+ C_stack_limit = C_stack_pointer + 1000;
#else
- C_stack_limit = C_stack_pointer - 1000;
+ C_stack_limit = C_stack_pointer - 1000;
#endif
- interrupt_reason = reason;
- interrupt_time = C_cpu_milliseconds();
+ interrupt_reason = reason;
+ interrupt_time = C_cpu_milliseconds();
+ }
}
}
@@ -4230,11 +4259,23 @@ C_regparm C_word C_fcall C_disable_interrupts(void)
C_regparm C_word C_fcall C_establish_signal_handler(C_word signum, C_word
reason)
{
int sig = C_unfix(signum);
+#if defined(HAVE_SIGACTION)
+ struct sigaction new;
+
+ new.sa_flags = 0;
+ sigemptyset(&new.sa_mask);
+#endif
if(reason == C_SCHEME_FALSE) C_signal(sig, SIG_IGN);
else {
signal_mapping_table[ sig ] = C_unfix(reason);
+#if defined(HAVE_SIGACTION)
+ sigaddset(&new.sa_mask, sig);
+ new.sa_handler = global_signal_handler;
+ C_sigaction(sig, &new, NULL);
+#else
C_signal(sig, global_signal_handler);
+#endif
}
return C_SCHEME_UNDEFINED;
@@ -9168,3 +9209,19 @@ C_i_file_exists_p(C_word name, C_word file, C_word dir)
}
+C_regparm C_word C_fcall
+C_i_pending_interrupt(C_word dummy)
+{
+ int i;
+
+ if(interrupt_reason && interrupt_reason != C_TIMER_INTERRUPT_NUMBER) {
+ i = interrupt_reason;
+ interrupt_reason = 0;
+ return C_fix(i);
+ }
+
+ if(pending_interrupts_count > 0)
+ return C_fix(pending_interrupts[ --pending_interrupts_count ]);
+
+ return C_SCHEME_FALSE;
+}
diff --git a/tcp.scm b/tcp.scm
index 4dfe579..4731c01 100644
--- a/tcp.scm
+++ b/tcp.scm
@@ -99,6 +99,7 @@ EOF
(define-foreign-variable _ipproto_tcp int "IPPROTO_TCP")
(define-foreign-variable _invalid_socket int "INVALID_SOCKET")
(define-foreign-variable _ewouldblock int "EWOULDBLOCK")
+(define-foreign-variable _eintr int "EINTR")
(define-foreign-variable _einprogress int "EINPROGRESS")
(define ##net#socket (foreign-lambda int "socket" int int int))
@@ -359,6 +360,8 @@ EOF
#:network-timeout-error
"read operation timed out" tmr fd) )
(loop) )
+ ((eq? errno _eintr)
+ (##sys#dispatch-interrupt loop))
(else
(##sys#update-errno)
(##sys#signal-hook
@@ -474,6 +477,9 @@ EOF
#:network-timeout-error
"write operation timed out" tmw fd) )
(loop len offset) )
+ ((eq? errno _eintr)
+ (##sys#dispatch-interrupt
+ (cut loop len offset)))
(else
(##sys#update-errno)
(##sys#signal-hook
@@ -524,12 +530,16 @@ EOF
(let loop ()
(if (eq? 1 (##net#select fd))
(let ((fd (##net#accept fd #f #f)))
- (when (eq? -1 fd)
- (##sys#update-errno)
- (##sys#signal-hook
- #:network-error 'tcp-accept (##sys#string-append "could not
accept from listener - " strerror)
- tcpl) )
- (##net#io-ports fd) )
+ (cond ((not (eq? -1 fd)) (##net#io-ports fd))
+ ((eq? errno _eintr)
+ (##sys#dispatch-interrupt loop))
+ (else
+ (##sys#update-errno)
+ (##sys#signal-hook
+ #:network-error
+ 'tcp-accept
+ (##sys#string-append "could not accept from listener - "
strerror)
+ tcpl))))
(begin
(when tma
(##sys#thread-block-for-timeout!
@@ -559,7 +569,7 @@ EOF
"int err, optlen;"
"optlen = sizeof(err);"
"if (typecorrect_getsockopt(socket, SOL_SOCKET, SO_ERROR, &err, (socklen_t
*)&optlen) == -1)"
- "C_return(-1);"
+ " C_return(-1);"
"C_return(err);"))
(define general-strerror (foreign-lambda c-string "strerror" int))
@@ -590,25 +600,28 @@ EOF
(unless (##net#make-nonblocking s)
(##sys#update-errno)
(##sys#signal-hook #:network-error 'tcp-connect (##sys#string-append
"fcntl() failed - " strerror)) )
- (when (eq? -1 (##net#connect s addr _sockaddr_in_size))
- (if (eq? errno _einprogress)
- (let loop ()
- (let ((f (##net#select-write s)))
- (when (eq? f -1) (fail))
- (unless (eq? f 1)
- (when tmc
- (##sys#thread-block-for-timeout!
- ##sys#current-thread
- (+ (current-milliseconds) tmc) ) )
- (##sys#thread-block-for-i/o! ##sys#current-thread s #:all)
- (yield)
- (when (##sys#slot ##sys#current-thread 13)
- (##sys#signal-hook
- #:network-timeout-error
- 'tcp-connect
- "connect operation timed out" tmc s) )
- (loop) ) ) )
- (fail) ) )
+ (let loop ()
+ (when (eq? -1 (##net#connect s addr _sockaddr_in_size))
+ (cond ((eq? errno _einprogress)
+ (let loop2 ()
+ (let ((f (##net#select-write s)))
+ (when (eq? f -1) (fail))
+ (unless (eq? f 1)
+ (when tmc
+ (##sys#thread-block-for-timeout!
+ ##sys#current-thread
+ (+ (current-milliseconds) tmc) ) )
+ (##sys#thread-block-for-i/o! ##sys#current-thread s
#:all)
+ (yield)
+ (when (##sys#slot ##sys#current-thread 13)
+ (##sys#signal-hook
+ #:network-timeout-error
+ 'tcp-connect
+ "connect operation timed out" tmc s) )
+ (loop2) ) ) ))
+ ((eq? errno _eintr)
+ (##sys#dispatch-interrupt loop))
+ (else (fail) ) )))
(let ((err (get-socket-error s)))
(cond ((fx= err -1)
(##net#close s)
diff --git a/tests/runtests.sh b/tests/runtests.sh
index 9c3f7cf..d54c9bc 100644
--- a/tests/runtests.sh
+++ b/tests/runtests.sh
@@ -153,10 +153,7 @@ $compile lolevel-tests.scm
./a.out
echo "======================================== arithmetic tests ..."
-if test -z "$MSYSTEM"; then
- # the windows runtime library prints flonums differently
- $interpret -D check -s arithmetic-test.scm
-fi
+$interpret -D check -s arithmetic-test.scm
echo "======================================== pretty-printer tests ..."
$interpret -s pp-test.scm
@@ -316,6 +313,10 @@ fi
$interpret -R posix -e '(delete-directory "tmpdir" #t)'
+echo "======================================== signal tests ..."
+$compile signal-tests.scm
+./a.out
+
echo "======================================== lolevel tests ..."
$interpret -s lolevel-tests.scm
$compile lolevel-tests.scm
diff --git a/tests/signal-tests.scm b/tests/signal-tests.scm
new file mode 100644
index 0000000..6f00440
--- /dev/null
+++ b/tests/signal-tests.scm
@@ -0,0 +1,85 @@
+;;;; signal-tests.scm
+
+
+#+windows
+(begin
+ (print "this test can not be run on Windows")
+ (exit))
+
+
+;;XXX not tested yet
+
+
+(use posix srfi-18 extras tcp)
+
+
+(define received1 0)
+(define received2 0)
+
+(define (tick c)
+ (write-char c)
+ (flush-output))
+
+(define (handler sig)
+ (select sig
+ ((signal/usr1)
+ (tick #\1)
+ (set! received1 (add1 received1)))
+ ((signal/usr2)
+ (tick #\2)
+ (set! received2 (add1 received2)))))
+
+(define (fini _)
+ (printf "~%child terminating, received: ~a USR1, ~a USR2~%"
+ received1 received2)
+ (exit))
+
+(define (child)
+ (print "child started")
+ (thread-start!
+ (lambda ()
+ (let-values (((i o) (tcp-accept (tcp-listen 9999))))
+ (tick #\!)
+ (assert (string=? "ok." (read-line i)))
+ (print "client connected.")
+ (close-input-port i)
+ (close-output-port o))))
+ (thread-start!
+ (lambda ()
+ (do () (#f)
+ (thread-sleep! 0.5)
+ (tick #\_))))
+ (set-signal-handler! signal/usr1 handler)
+ (set-signal-handler! signal/usr2 handler)
+ (set-signal-handler! signal/term fini)
+ (do () (#f)
+ (thread-sleep! 1)
+ (tick #\.)))
+
+(let ((pid (process-fork child))
+ (sent1 0)
+ (sent2 0))
+ (sleep 1)
+ (print "sending signals to " pid)
+ (do ((i 1000 (sub1 i)))
+ ((zero? i))
+ (thread-sleep! (/ (random 10) 1000))
+ (do ((j (random 4) (sub1 j)))
+ ((zero? j))
+ (case (random 2)
+ ((0)
+ (tick #\A)
+ (set! sent1 (add1 sent1))
+ (process-signal pid signal/usr1))
+ ((1)
+ (tick #\B)
+ (set! sent2 (add1 sent2))
+ (process-signal pid signal/usr2)))))
+ (printf "~%signals sent: ~a USR1, ~a USR2~%" sent1 sent2)
+ (print "connecting ...")
+ (let-values (((i o) (tcp-connect "localhost" 9999)))
+ (display "ok.\n" o)
+ (close-input-port i)
+ (close-output-port o)
+ (sleep 1))
+ (process-signal pid))
--
1.7.6.msysgit.0
- [Chicken-hackers] [PATCH] Overhaul interrupt handling,
Felix <=