chicken-hackers
[Top][All Lists]
Advanced

[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


reply via email to

[Prev in Thread] Current Thread [Next in Thread]