Opened 7 years ago

Closed 7 years ago

#1127 closed defect (invalid)

dynamic wind in its own thread

Reported by: kristianlm Owned by:
Priority: major Milestone: someday
Component: unknown Version: 4.9.x
Keywords: Cc:
Estimated difficulty:

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

Change History (3)

comment:1 Changed 7 years ago by kristianlm

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

comment:2 Changed 7 years ago by Christian Kellermann

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?

comment:3 Changed 7 years ago by kristianlm

Resolution: invalid
Status: newclosed

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!

Note: See TracTickets for help on using tickets.