Summary

dynamic wind in its own thread

Metadata

Description

I'm running this code in 4.9.0rc1:

(define (trick)

 (dynamic-wind (lambda () (print "before"))
               (lambda () (error 'foo))
               (lambda () (print "after"))))
; calls before and after, no surprises

(trick)

; calls before only - why?

(thread-start! (lambda () (trick)))

; calls before and after, no surprises

(thread-start!

(lambda () (handle-exceptions e (raise e) (trick))))
;; It outputs

before

Error: foo

Call history:

<syntax>	  (trick)
<eval>	  (trick)
<eval>	  [[trick]|] (dynamic-wind (lambda () (print "before")) (lambda () (error (quote foo))) (lambda () (print "after"...
<eval>	  [[trick]|] (print "before")
<eval>	  [[trick]|] (error (quote foo))	<--

after #<thread: thread22> before

Warning (#<thread: thread22>): in thread: foo

Call history:

<eval>	  (trick)
<eval>	  [[trick]|] (dynamic-wind (lambda () (print "before")) (lambda () (error (quote foo))) (lambda () (print "after"...
<eval>	  [[trick]|] (print "before")
<eval>	  [[trick]|] (error (quote foo))	<--
; I expect to see "after" printed on the second run too

Changes and comments

[2014-05-22 17:15:16 UTC] kristianlm wrote:

Meanwhile, here's a workaround:

 (use srfi-18 test)
 ;; define original@thread-start! once
 (define original#thread-start!
   (handle-exceptions e thread-start!
                      original#thread-start!))
 
 (define (##dbg#thread-thunk thread)
   (##sys#slot thread 1))
 
 (define (thread-start! thread)
 
   ;; original thunk
   (define original-thunk
     (if (thread? thread)
         (##dbg#thread-thunk thread)
         thread))
 
   ;; simply wrap original thunk inside a handle-exceptions with
   ;; re-raises any errors seem to do the trick
   (define (thunk)
     (handle-exceptions e (raise e)
                        (original-thunk)))
 
   (original#thread-start!
    (if (thread? thread)
        (make-thread thunk (thread-name thread))
        (make-thread thunk))))
 
 
 (test-group
  "dynamic-wind.workaround"
 
  (define ran? #f)
  (define (trick)
    (dynamic-wind (lambda () (void))
                  (lambda () (error 'x))
                  (lambda () (set! ran? #t))))
 
  ;; throw away warnings
  (parameterize ((current-error-port (open-output-string)))
    (test-error
     (thread-join!
      (thread-start!
       (lambda () (trick))))))
 
  (test #t ran?))
 

This test-group passes, but fails if you don't redefine thread-start!.

[2014-05-22 22:18:12 UTC] ckeen wrote:

The manual states: (http://api.call-cc.org/doc/srfi-18)

 When an error is triggered inside the execution context of a thread,
 the default exception-handler will simply terminate the thread 
 and store the error condition for later use). Pending dynamic-wind
 thunks will not be invoked. Use a custom exception handler for the
 thread in that case.

To me that's exactly what happens here? Or am I missing something more subtle?

[2014-05-27 16:01:38 UTC] kristianlm changed status from new to closed

[2014-05-27 16:01:38 UTC] kristianlm set resolution to invalid

[2014-05-27 16:01:38 UTC] kristianlm wrote:

Of course, I was reading the part on "dynamic-wind" thoroughly without finding anything about this. But this makes very much sense. We will wrap our thread-thunks in our own exception-handlers (which I've actually tested works).

So the behavior is indeed like expected when you actually read the whole srfi-18 manual.

Thanks CKeen!