[gambit-list] Interrupted in wait-for-io

Christian christian at pflanze.mine.nu
Wed Jan 4 15:30:09 EST 2006


At 10:28 Uhr -0500 04.01.2006, Marc Feeley wrote:
>It is possible using undocumented procedures.  Here's what you want:

Thank you.

>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 ...".

The default for unix programs is that SIGINT makes them terminate 
*and deliver that fact to the parent* (through wait(2) the parent can 
know if the child terminated because of a signal and which one it 
was). If you trap SIGINT, then afaik the only way to make the parent 
know we are terminating because of a signal is to remove our signal 
handler and then killing ourselves again. This poses the question as 
to why a signal handler has been installed in the first place.
   I think that printing a message and exiting with an error code is a 
nonstandard and thus suboptimal solution, and that not installing 
signal handlers at all unless really necessary would be, in 
principle, a better solution. (I'm mainly coming from perl, which 
works that way.) I don't want to suggest to give this a high priority 
though and also have never really programmed on non-unix systems.

>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 makes sense to me.

>>(*) 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.

Here's a normal parameter p1, and a self-written parameter like 
function p2 which has the side effect of something like initializing 
signal setup if not done already:

(define p1 (make-parameter #f))

(define pseudo-signal-handler-hook #f)
(define p2
   (let ((absent (gensym))
	(value #f))
     (lambda (#!optional (newvalue absent))
       (if (eq? newvalue absent)
	  value
	  (begin
	    (if (not pseudo-signal-handler-hook)
		(set! pseudo-signal-handler-hook
		      (lambda ()
			(display "hello world\n"))))
	    (set! value newvalue))))))

; > (p1)
; #f
; > (p1 "hello")
; > (p1)
; "hello"
; > (p2)
; #f
; > pseudo-signal-handler-hook
; #f
; > (p2 "world")
; > (p2)
; "world"
; > pseudo-signal-handler-hook
; #<procedure #2 pseudo-signal-handler-hook>
; > (#2)
; hello world

; > (begin (parameterize ((p1 "a")) (display (p1))(newline)) (display 
(p1))(newline))
; a
; #f
; > (begin (parameterize ((p2 "a")) (display (p2))(newline)) (display 
(p2))(newline))
; *** ERROR IN (console)@3.8 -- PARAMETER expected
; 1>

The problem is that my side-effecting pseudo parameter cannot be 
transparently used with parameterize. It occured to me as an 
unnecessary drawback when I first realized that parameters were 
procedures but procedures can't be parameters. I did assume 
parameterize were implemented about like this (e.g. querying the old 
value, storing in lexical context, setting new value with 
dynamic-wind):

; (let ((#:g10 (p2)))
;   (dynamic-wind
;    (lambda () (p2 "a"))
;    (lambda () (display (p2)) (newline))
;    (lambda () (p2 #:g10))))

(let ((#:var2 "a"))
   (let ((#:swap4 (lambda ()
                    (let ((#:tmp3 (p2)))
                      (p2 #:var2) (set! #:var2 #:tmp3)))))
     (dynamic-wind #:swap4
                   (lambda () (display (p2)) (newline))
                   #:swap4)))

; as generated by this macro:

(define-macro (my-parameterize bindings . body)
   (let* ((b-alist (map (lambda (l)
			(cons l
			       (gensym 'var)))
		       bindings))
	(b->var (lambda (l)
		   (cdr (assoc l b-alist))))
	(b->name car)
	(b->init cadr)
	(tmp (gensym 'tmp))
	(swap (gensym 'swap)))
      `(let ,(map (lambda (l)
		   (list (b->var l)
			(b->init l)))
		bindings)
	(let ((,swap
	       (lambda ()
		,@ (map (lambda (l)
			   `(let ((,tmp (,(b->name l))))
			      (,(b->name l) ,(b->var l))
			      (set! ,(b->var l) ,tmp)))
			bindings))))
	  (dynamic-wind
	      ,swap
	      (lambda ()
		,@ body)
	      ,swap)))))

I know this implementation of parameterize has a problem though: 
dynamic-wind is not safe when using exceptions. Why? I find this 
especially strange considering that I thought with-exception-catcher 
was implemented using continuations.

Which other reasons are there for implementing parameters 
differently? Performance or semantics? I guess the above 
implementation would be rather slow. I've taken a cursory look at the 
srfi-39 document and discussion archive, but most of it is over my 
head right now, I'll reread later.

So, it seems that the "most natural way" of how parameterize would be 
implemented is not the best and thus I shouldn't expect to be able to 
put callbacks into a supposedly lowlevel dynamic bindings mechanism.

>>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).

I'll reread it later.

>>((**) 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.



More information about the Gambit-list mailing list