Hello
Why aren't interrupts (ctl-c in particular) running the current exception handler, but instead enter the debugger unconditionally?
$ cat testinterrupt.scm (with-exception-catcher (lambda (e) (display "Catched an exception: ") (write e) (newline) (##repl)) (lambda () (read)))
$ gsi
(load "testinterrupt.scm")
*** INTERRUPTED IN ##wait-for-io! 1> fooo Catched an exception: #<unbound-global-exception #2> 1> foo *** ERROR IN (console)@3.1 -- Unbound variable: foo 2>
Note that inside the debugger, my exception handler is still active, as shown after entering |fooo|. So it's not that ##wait-for-io or some other function would install another handler, but that the current-exception-handler is simply ignored.
Same thing in compiled code, except that there's no handler catching exceptions when inside mine:
$ gsc -warnings testinterrupt $ gcc -O3 -fomit-frame-pointer -mpreferred-stack-boundary=2 -Wdisabled-optimization testinterrupt.c testinterrupt_.c -I/usr/local/Gambit-C/include -L/usr/local/Gambit-C/lib -lgambc -lm -lutil -ldl -o testinterrupt
$ ./testinterrupt *** INTERRUPTED IN ##wait-for-io!
foo
Catched an exception: #<unbound-global-exception #2>
foo
*** ERROR IN (console)@2.1 -- Unbound variable: foo $
The real problem with this is: how can I create a standalone Gambit program that exits when it gets SIGINT ?
Thanks Christian.
Afficher les réponses par date
CTRL-C does not generate an exception. It simply calls the current user-interrupt-handler. What you want is this:
(current-user-interrupt-handler (lambda () (display "goodbye!\n") (exit)))
(with-exception-catcher (lambda (e) (display "Catched an exception: ") (write e) (newline) (##repl)) (lambda () (read)))
Note that the REPL dynamically binds its own user-interrupt-handler for the dynamic extent of the call to ##repl (in other words, once you get a REPL you are debugging and a CTRL-C is either ignored when reading the expression to evaluate or is interpreted as a desire to interrupt the evaluation and go back to the REPL).
Marc
On 3-Jan-06, at 9:15 AM, Christian wrote:
Hello
Why aren't interrupts (ctl-c in particular) running the current exception handler, but instead enter the debugger unconditionally?
$ cat testinterrupt.scm (with-exception-catcher (lambda (e) (display "Catched an exception: ") (write e) (newline) (##repl)) (lambda () (read)))
$ gsi
(load "testinterrupt.scm")
*** INTERRUPTED IN ##wait-for-io! 1> fooo Catched an exception: #<unbound-global-exception #2> 1> foo *** ERROR IN (console)@3.1 -- Unbound variable: foo 2>
Note that inside the debugger, my exception handler is still active, as shown after entering |fooo|. So it's not that ##wait-for-io or some other function would install another handler, but that the current-exception-handler is simply ignored.
Same thing in compiled code, except that there's no handler catching exceptions when inside mine:
$ gsc -warnings testinterrupt $ gcc -O3 -fomit-frame-pointer -mpreferred-stack-boundary=2 - Wdisabled-optimization testinterrupt.c testinterrupt_.c -I/usr/ local/Gambit-C/include -L/usr/local/Gambit-C/lib -lgambc -lm -lutil -ldl -o testinterrupt
$ ./testinterrupt *** INTERRUPTED IN ##wait-for-io!
foo
Catched an exception: #<unbound-global-exception #2>
foo
*** ERROR IN (console)@2.1 -- Unbound variable: foo $
The real problem with this is: how can I create a standalone Gambit program that exits when it gets SIGINT ?
Thanks Christian.
Gambit-list mailing list Gambit-list@iro.umontreal.ca http://mailman.iro.umontreal.ca/mailman/listinfo/gambit-list
At 10:18 Uhr -0500 03.01.2006, Marc Feeley wrote:
CTRL-C does not generate an exception. It simply calls the current user-interrupt-handler.
Ok, thanks, that makes perfect sense.
Two small followup questions about things I might need in the future:
- can other signals than SIGINT be catched, too? I guess that you haven't added that since it's platform specific. I might write a small C layer for my programs on unix, but then my question is: how do I register an interrupt callback in gambit's runtime (I guess I'll have to save the signal number and values into some global and then let gambit run a callback synchronously at a safe point)?
- maybe it's rather theoretical, but there is probably a time frame between the start of a program and the time when it sets user-interrupt-handler where sending SIGINT still makes the program "hang" in the debugger. Could gambit delay installing of a SIGINT signal handler so that the program behaves in the default way until the user actually installs a handler?(*) That should also be better if gambit is to be embedded in a C program which wants to catch signals itself.
(*) that leads to another question I've been wondering about: parameterize doesn't accept procedures which aren't parameters (it checks their type). This makes the above suggestion impossible to be implement transparently of course, since it would require running code other than just for setting the dynamic value (**). What's the reason for this restriction?
((**) without this, the user would have to run some (user-interrupt-initialize!) hook first -- at least, that might be better for thread safety?)
Thanks Christian.
On 4-Jan-06, at 12:36 AM, Christian wrote:
At 10:18 Uhr -0500 03.01.2006, Marc Feeley wrote:
CTRL-C does not generate an exception. It simply calls the current user-interrupt-handler.
Ok, thanks, that makes perfect sense.
Two small followup questions about things I might need in the future:
- can other signals than SIGINT be catched, too? I guess that you
haven't added that since it's platform specific. I might write a small C layer for my programs on unix, but then my question is: how do I register an interrupt callback in gambit's runtime (I guess I'll have to save the signal number and values into some global and then let gambit run a callback synchronously at a safe point)?
It is possible using undocumented procedures. Here's what you want:
(c-declare #<<c-declare-end
#include <signal.h>
void handler (int sig) { if (sig == SIGUSR1) ___EXT(___raise_interrupt) (___INTR_6); else ___EXT(___raise_interrupt) (___INTR_7); }
void install_SIGUSR_handlers () { signal (SIGUSR1, handler); signal (SIGUSR2, handler); }
c-declare-end )
(define install-SIGUSR-handlers (c-lambda () void "install_SIGUSR_handlers"))
(define (install-handlers) (##interrupt-vector-set! 6 (lambda () (println 'got-SIGUSR1))) (##interrupt-vector-set! 7 (lambda () (println 'got-SIGUSR2))) (install-SIGUSR-handlers))
(install-handlers)
(define my-pid (##os-getpid))
(display "executing kill -USR1\n")
(shell-command (string-append "kill -USR1 " (number->string my-pid)))
(display "executing kill -USR2\n")
(shell-command (string-append "kill -USR2 " (number->string my-pid)))
(display "done\n")
; Output: ; ; executing kill -USR1 ; got-SIGUSR1 ; executing kill -USR2 ; got-SIGUSR2 ; done
- maybe it's rather theoretical, but there is probably a time frame
between the start of a program and the time when it sets user- interrupt-handler where sending SIGINT still makes the program "hang" in the debugger. Could gambit delay installing of a SIGINT signal handler so that the program behaves in the default way until the user actually installs a handler?(*) That should also be better if gambit is to be embedded in a C program which wants to catch signals itself.
Good point. Currently Gambit, under Unix, starts off with SIGINT terminating the program (that's the default Unix SIGINT handler), then the runtime system installs a handler that ignores SIGINT, then it installs a handler that starts a REPL.
I'm planning to change this so that the default user-interrupt- handler behaves like exceptions, i.e. the default will be to terminate the program after displaying "*** INTERRUPTED IN ...". With the runtime option "-:d" the system will instead start a REPL. With the runtime option "-:d0" the program will terminate silently. However, when inside a REPL (such as the one normally started in interactive mode), a SIGINT will start a nested REPL.
(*) that leads to another question I've been wondering about: parameterize doesn't accept procedures which aren't parameters (it checks their type). This makes the above suggestion impossible to be implement transparently of course, since it would require running code other than just for setting the dynamic value (**).
I don't understand what you mean.
What's the reason for this restriction?
Parameters are special procedures that contain a key. This key is used to lookup the binding of the parameter. The machinery is quite complex (see _thread.scm).
((**) without this, the user would have to run some (user-interrupt- initialize!) hook first -- at least, that might be better for thread safety?)
Thanks Christian. _______________________________________________ Gambit-list mailing list Gambit-list@iro.umontreal.ca http://mailman.iro.umontreal.ca/mailman/listinfo/gambit-list