Suppose this simple loop in a child thread that executes step
every second, while you can interact with via a REPL (inspect state
or change step
):
(import (srfi 18) (chicken repl))
(define mutex (make-mutex))
(define (with-mutex-locked mutex thunk) (dynamic-wind
(lambda () (mutex-lock! mutex))
(lambda () (thunk))
(lambda () (mutex-unlock! mutex))))
(set! state 0)
(define (step) (set! state (+ state 1)))
(define (loop)
(with-mutex-locked mutex step)
(sleep 1)
(loop))
(thread-start! loop)
(repl (lambda (x) (with-mutex-locked mutex (lambda () (eval x)))))
(exit)
However, when changing step
to something erroneous the thread crashes and prints a trace:
(define (step) (car `()))
Warning (#<thread: thread26>): in thread: (car) bad argument type: ()
Call history:
<eval> [loop] (loop)
<eval> [loop] (dynamic-wind (lambda () (mutex-lock! mutex)) (lambda () (step)) (lambda () (mutex-unlock! mutex)))
<eval> [loop] (mutex-lock! mutex)
<eval> [loop] (step)
<eval> [step] (car (quasiquote ())) <--
I'd like to recover (i.e. unlock the mutex, restart the loop) from such a crash but still have the error with its trace printed for debugging. My attempt with (handle-exceptions … (step))
didn't work out, as the exception apparently only contains message
, arguments
and location
– not the trace. But the trace must be hidden somewhere, otherwise the interpreter couldn't print it. Is there a way to access it? Or is there another way to recover after the trace got printed?
The trace buffer is a ring buffer containing just the most recent calls. It can't be used to jump back.
You might want to read this old CHICKEN Gazette issue which contains a tutorial (search for "omelette recipes") on how exception handling works and the difference between continuable and non-continuable exceptions. If you're in a hurry, the real explanation starts at "To continue or not continue -- That's the question".