(zilch statusbar): Fix resilience during shutdown

When the (current-error-port) is closed, other threads in the middle
of using the port are likely to error out with a "port is closed"
error. When this occurs, the Chicken Scheme runtime will either
deadlock (when this happens on the output port), or worse, _hang_.
As the barf procedure usess the current error port, it itself hits this
same issue.

We can't perfectly protect against this, as there's no mutex on the current
output/error port; but we can improve the chances of hitting it massively,
to the point where a simple program won't hit the deadlock.

Change-Id: I3ccec0073b375ca21e8b46861c2f8c146a6a6964
This commit is contained in:
puck 2025-11-20 12:56:53 +00:00
parent 02045177dd
commit 222b0eb5a3

View file

@ -53,16 +53,19 @@
(define-values (rows cols) (terminal-size err-port)) (define-values (rows cols) (terminal-size err-port))
(when (> cols 0) (set! terminal-width cols)) (when (> cols 0) (set! terminal-width cols))
(define shutdown #f)
(define (terminal-width-thread-thunk handler) (define (terminal-width-thread-thunk handler)
; Lock the output mutex whilst setting the terminal size. ; Lock the output mutex whilst setting the terminal size.
(define-values (rows cols) (terminal-size err-port)) (define-values (rows cols) (terminal-size err-port))
(mutex-lock! out-mutex) (mutex-lock! out-mutex)
(when (> cols 0) (set! terminal-width cols)) (when (> cols 0) (set! terminal-width cols))
(define is-shutdown shutdown)
(mutex-unlock! out-mutex) (mutex-unlock! out-mutex)
; Wait until the next SIGWINCH, then loop ; Wait until the next SIGWINCH, then loop
(handler #t) (handler #t)
(terminal-width-thread-thunk handler)) (unless is-shutdown (terminal-width-thread-thunk handler)))
(define terminal-width-thread (make-thread (lambda () (terminal-width-thread-thunk (make-signal-handler signal/winch))))) (define terminal-width-thread (make-thread (lambda () (terminal-width-thread-thunk (make-signal-handler signal/winch)))))
@ -83,9 +86,11 @@
(rerender-status-bar) (rerender-status-bar)
(mutex-lock! out-mutex) (mutex-lock! out-mutex)
(draw-status-bar) (draw-status-bar)
(define is-shutdown shutdown)
(mutex-unlock! out-mutex) (mutex-unlock! out-mutex)
(thread-sleep! 0.1) (unless is-shutdown
(redraw-thread-thunk)) (thread-sleep! 0.1)
(redraw-thread-thunk)))
(define redraw-thread (make-thread redraw-thread-thunk "redraw thread")) (define redraw-thread (make-thread redraw-thread-thunk "redraw thread"))
(define last-builds-activity-id #f) (define last-builds-activity-id #f)
@ -123,12 +128,19 @@
(define (close-this-port) (define (close-this-port)
(mutex-lock! out-mutex) (mutex-lock! out-mutex)
(thread-terminate! redraw-thread) (when (eq? new-err-port (current-error-port))
(thread-terminate! terminal-width-thread) (current-error-port err-port))
(when (eq? new-out-port (current-output-port))
(current-output-port out-port))
(define was-shutdown shutdown)
(set! shutdown #t)
(mutex-unlock! out-mutex) (mutex-unlock! out-mutex)
(fprintf err-port "\r\x1B[2K\n") (unless was-shutdown
(close-output-port err-port) (thread-join! redraw-thread)
(close-output-port out-port)) (mutex-lock! out-mutex)
(thread-terminate! terminal-width-thread)
(mutex-unlock! out-mutex)
(fprintf err-port "\r\x1B[2K\n")))
(define new-err-port (buffered-port out-mutex write-err-line draw-status-bar close-this-port)) (define new-err-port (buffered-port out-mutex write-err-line draw-status-bar close-this-port))
(define new-out-port (buffered-port out-mutex write-out-line draw-status-bar close-this-port)) (define new-out-port (buffered-port out-mutex write-out-line draw-status-bar close-this-port))