chicken-hackers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Chicken-hackers] interrupts overhaul


From: Alan Post
Subject: Re: [Chicken-hackers] interrupts overhaul
Date: Thu, 13 Oct 2011 12:15:00 -0600

I've just tested this with a program that does fork/exec+signal
handling, and it worked without my having to change my code.

I have more testing I want to do, and I'l submit some minor
tweaks to the patch below.  Please excuse a bit of a delay,
this is a relatively complicated patch to test.

So far, it is essentially working.

-Alan

On Thu, Oct 13, 2011 at 07:35:05AM -0400, Felix wrote:
> Hello!
> 
> 
> Attached is a patch for overhauling the signal- and interrupt-
> handling. This is just for an initial review, not a proper commit. It
> is based on suggestions by Joerg and Alan, with some additional stuff
> by me. Please have a look - I'm not completely sure my assumptions are
> correct and I may have overlooked some things.
> 
> 1) The global signal handler is set up using sigaction(3), where
>    available (all but mingw).
> 
> 2) SIGINT handling has been moved to csi, to make it work without
>    loading the "posix" unit.
> 
> 3) The primitives for reading and peeking from a port check for EINTR
>    now and invoke "##sys#dispatch-interrupt", which invokes signal
>    handlers for all pending signals. Also the interrupt hook processes
>    signals until all are dispatched. The interrupt hook has been
>    changed to accept a continuation procedure instead of a thread
>    context.
> 
> 4) Signals are queued (stacked, really) in a global buffer. According
>    to Stevens, multiple occurrences of a signal in fast succession may
>    result in lost signals, since sigaction(3) is not required to queue
>    incoming signals during the execution of a signal handler that
>    blocks. Timer-interrupts may be dropped during the processing of
>    interrupts caused by signals, but I assume this is acceptable.
> 
> 5) TCP connect/accept and recv/send operations check and handle
>    EINTR.
> 
> 6) A silly test program has been added. I was not able to detect any
>    improvement in the number of caught signals with the changes in
>    this patch, as compared to the current state, but it should be more
>    reliable in any case (testing is a bit difficult - if someone can
>    come up with good testcases, please consider posting).
> 
> Things to improve:
> 
> - "fast_read_line_from_file" (library.scm) probably has to do EINTR
>   handling - I guess it has.
> - Do we have to block all currently handled signals when setting up
>   the signal handler for a certain signal? It probably should.
> 
> 
> cheers,
> felix

> 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 5524bc4..0be8fd4 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
> @@ -1852,6 +1855,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..700d0b7 100644
> --- a/library.scm
> +++ b/library.scm
> @@ -1736,9 +1736,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
> @@ -3909,6 +3917,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 +4353,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 +4590,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 8c95354..9c4088f 100644
> --- a/posix-common.scm
> +++ b/posix-common.scm
> @@ -487,3 +487,17 @@ EOF
>                  (##sys#substring str 0 (fx- (##sys#size str) 1))
>                  (##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!))
> diff --git a/posixunix.scm b/posixunix.scm
> index ee17325..c64e250 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:
>  
> diff --git a/posixwin.scm b/posixwin.scm
> index 64c544e..5409600 100644
> --- a/posixwin.scm
> +++ b/posixwin.scm
> @@ -1263,25 +1263,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 5e2f161..edb7e97 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>
> @@ -156,6 +157,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
> @@ -447,6 +450,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: */
> @@ -696,6 +702,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;
> @@ -719,7 +726,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;
>  
> @@ -751,6 +758,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);
> @@ -785,7 +793,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;
>  }
> @@ -983,7 +991,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
>  }
>  
>  
> @@ -2712,7 +2722,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);    
> @@ -2898,7 +2908,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) {
> @@ -4006,7 +4016,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);
>  }
>  
>  
> @@ -4015,8 +4030,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);
>  }
>  
>  
> @@ -4264,16 +4284,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();
> +    }
>    }
>  }
>  
> @@ -4297,11 +4326,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;
> @@ -9261,3 +9302,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/arithmetic-test.scm b/tests/arithmetic-test.scm
> index 9334b33..f131915 100644
> --- a/tests/arithmetic-test.scm
> +++ b/tests/arithmetic-test.scm
> @@ -7,6 +7,13 @@
>  ; fx-ops
>  
>  
> +;; the windows runtime library prints flonums differently
> +#+windows
> +(begin
> +  (print "this test can not be run on Windows")
> +  (exit))
> +
> +
>  (use extras)
>  
>  #+use-numbers (use numbers)
> 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))

> _______________________________________________
> Chicken-hackers mailing list
> address@hidden
> https://lists.nongnu.org/mailman/listinfo/chicken-hackers


-- 
.i ma'a lo bradi cu penmi gi'e du



reply via email to

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