[racket] Breaks always go to main thread?

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Wed Mar 18 11:14:49 EDT 2015

That looks like a reasonable approach to me. break-thread is what the
control-c is turning into via some shim somewhere inside racket's
runtime system, I believe.

Another approach that you might want to try is to catch the "c:c;c:c"
at the emacs level and instead of turning that into SIGINT (or
whatever signal it is) send an explicit message across to the "(sync
never-evt)" code that tells it to break the user's program's thread.
This is closer to what DrRacket does and it has the advantage that you
can still use the raw breaks to debug racket mode, should the need
arise (I find this very useful when debugging drracket -- but no one
expects a control-c to drracket to turn into breaking the program
running inside drr!)

Robby


On Wed, Mar 18, 2015 at 9:53 AM, Greg Hendershott
<greghendershott at gmail.com> wrote:
> Preface to avoid any "XY problem": I recently added errortrace support
> to racket-mode. But I noticed that C-c is bypassing this. Which is sad;
> definitely want good context for that -- not "running body".
>
> Digging in, it seems that exn:break is only ever given to the main
> thread.
>
> [This matters because the user program is running on a child thread (as
> with racket/sandbox or the eventspace-handler-thread in DrR). The
> interesting errortrace info is on/about the child thread. The main
> thread is just sitting on a sync.]
>
> I didn't realize that exn:break is unlike exn:fail (other exn's
> generally?) in this respect.
>
> As a distilled example:
>
>   #lang racket/base
>
>   (thread
>    (λ ()
>      (with-handlers ([exn:fail?
>                       (λ _ (displayln "Fail caught in sub thread. Yay!"))])
>        (/ 1 0))))
>
>   (thread
>    (λ ()
>      (with-handlers ([exn:break? ;never gets here
>                       (λ _ (displayln "Break caught in sub thread. Yay!"))])
>        (displayln "Press C-c")
>        (let loop ([n 0])
>          (displayln n)
>          (sleep 1)
>          (loop (add1 n))))))
>
>   (with-handlers ([exn:break?
>                    (λ _ (displayln "Break caught in main thread. Boo!"))])
>     (sync never-evt))
>
> Running it:
>
>     #<thread:/tmp/break.rkt:3:8>
>     #<thread:/tmp/break.rkt:8:8>
>     Press C-c
>     0
>     Fail caught in sub thread. Yay!
>     1
>     2
>       C-c C-cBreak caught in main thread. Boo!
>
> After some pondering and doc-re-reading, my only idea is to catch the
> exn:break in the main thread, and break-thread the child thread, to
> catch it there, too. For example:
>
>   (define thd
>     (thread
>      (λ ()
>        (with-handlers ([exn:break?
>                         (λ _ (displayln "Break caught in sub thread. Yay!"))])
>          (displayln "Press C-c")
>          (let loop ([n 0])
>            (displayln n)
>            (sleep 1)
>            (loop (add1 n)))))))
>
>   (with-handlers ([exn:break?
>                    (λ _
>                      (break-thread thd)
>                      (sleep))])
>     (sync never-evt))
>
> Running it:
>
>     racket -t /tmp/break.rkt
>     Press C-c
>     0
>     1
>       C-c C-cBreak caught in sub thread. Yay!
>
> So, "it works". And now racket-mode shows the full errortrace on a
> break, apparently fixing the bug.
>
> But do I understand this correctly? I'm cautious generally, but also
> specifically because I didn't see this described in the main docs --
> that exn:break is only ever given to the main thread.
>
> Any caveats, cautions, advice?
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users


Posted on the users mailing list.