I am looking for a way to handle asynchronous resources finalisation
in such a way that both continuations and continuable exceptions are
allowed; if I exclude garbage collector-related finalisation
mechanisms (guardians, ...) I do not see how to do it in an efficient/
convenient way.
Putting the finalisation form in the OUT-GUARD of a DYNAMIC-WIND
does not work when continuations are used; the following code fails
because when the continuation is invoked, the port is already closed:
(import (rnrs))
(define pathname "/tmp/abcdefg.txt")
(when (file-exists? pathname)
(delete-file pathname))
(let ((kk #f)
(i 0))
(let ((port (open-file-output-port pathname)))
(dynamic-wind
(lambda () #f)
(lambda ()
(call/cc (lambda (k)
(set! kk k)))
(put-u8 port 1)
(flush-output-port port))
(lambda ()
(close-port port))))
(when (< i 2)
(set! i (+ 1 i))
(kk)))
Putting the finalisation form in the exception handler does not work
when continuable exceptions are used; the following code fails because
when the handler returns from the continuable exception, the port is
already closed:
(import (rnrs))
(define pathname "/tmp/abcdefg.txt")
(when (file-exists? pathname)
(delete-file pathname))
(with-exception-handler
(lambda (E) #t)
(lambda ()
(let* ((port (open-file-output-port pathname))
(%close (lambda () (close-port port))))
(with-exception-handler
(lambda (E)
(when (message-condition? E)
(display (condition-message E))
(newline))
(%close)
(raise-continuable E))
(lambda ()
(raise-continuable 123)
(put-u8 port 1)
(flush-output-port port)
(%close))))))
A way is to acquire and release the resource in the IN-GUARD and OUT-
GUARD forms of a DYNAMIC-WIND, which is, in general, undesirable:
(import (rnrs))
(define pathname "/tmp/abcdefg.txt")
(when (file-exists? pathname)
(delete-file pathname))
(let ((kk #f)
(i 0))
(let ((port (open-file-output-port pathname)))
(dynamic-wind
(lambda ()
(when (file-exists? pathname)
(set! port
(open-file-output-port pathname
(file-options no-create)))))
(lambda ()
(call/cc (lambda (k)
(set! kk k)))
(display "write\n")
(put-u8 port 65)
(flush-output-port port))
(lambda ()
(close-port port))))
(when (< i 2)
(set! i (+ 1 i))
(kk)))
In a way or the other, if I want to limit the "knowledge" about the
async resource to "inside" the form which allocates it, there seems to
be no convenient way to let the execution flow escape such form and
come back later. Is there a mechanism I cannot see?
TIA
--
Marco Maggi
Continuations hold references, which allows holding a reference to
only a continuation and thereby keeping its references alive even when
the continuation is not active. When a continuation becomes not-
referenced, so do the objects referenced only from it, which is the
proper time to finalize them. I don't see how any other way can
support resuming continuations and having objects still be
unfinalized, when any possible opportunity for finalizing along your
execution paths might be guessing wrong about whether you're actually
done with an object.
If you don't use GC finalization and do finalization at some point of
your execution path, you could use a flag to tell if it should
finalize or not, but that's not really any different than instead
making the flag variable be the object variable and finalizing the
object when you'd toggle the flag. Also, with a flag, even though
you've toggled the flag, the execution might not get to the point
where it does the finalization.
So I think this is an argument for not excluding GC-related
finalization mechanisms.
--
: Derick
----------------------------------------------------------------