[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
unwind-protect and inhibit-quit
From: |
Felix Dietrich |
Subject: |
unwind-protect and inhibit-quit |
Date: |
Thu, 15 Jul 2021 17:14:56 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/27.1 (gnu/linux) |
Hello,
I have questions regarding “unwind-protect” and the two examples
provided in the elisp reference manual [1].
;; 1. Example
(let ((buffer (get-buffer-create " *temp*")))
(with-current-buffer buffer
(unwind-protect
body-form
(kill-buffer buffer))))
;; 2. Example
(let ((win nil))
(unwind-protect
(progn
(setq process (ftp-setup-buffer host file))
(if (setq win (ftp-login process host user password))
(message "Logged in")
(error "Ftp login failed")))
(or win (and process (delete-process process)))))
In the last paragraph [2], the description of the second example mentions a
race condition between the assignment of the “ftp-setup-buffer”
functionʼs return value to the variable “process” and the user sending a
quit signal (C-g). Does the first example suffer from the same issue in
itʼs assignment to the “buffer” variable?
That paragraph also mentions that “there is no easy way to fix this
bug”. Is that statement still true or can this issue be resolved by
setting “inhibit-quit” in current Emacs versions:
;; 2. Example (added inhibit-quit)
(let ((win nil))
(unwind-protect
(progn
(let ((inhibit-quit t))
(setq process (ftp-setup-buffer host file)))
(if (setq win (ftp-login process host user password))
(message "Logged in")
(error "Ftp login failed")))
(or win (and process (delete-process process)))))
The first example has the “unwind-protect” form nested inside
“with-current-buffer”; this leaves a window where the buffer is both
created and assigned to the variable “buffer” but not protected from
being left alive in case of a quit (or, in more elaborated uses, an
error). Shouldn’t it, therefore, be the other way around:
“unwind-protect” wrapping “with-current-buffer”? In the following
snippet I also have added “inhibit-quit”, assuming that it works like I
expect.
;; 1. Example (moved unwind-protect up; added inhibit-quit)
(let (buffer)
(unwind-protect
(progn
(let ((inhibit-quit t))
(setq buffer (get-buffer-create " *temp*")))
(with-current-buffer buffer
body-form))
(and buffer (kill-buffer buffer))))
There also seems to be an issue in the first example with modifying and
killing a potentially already existing buffer " *temp*", which could be
avoided, I believe, by using “generate-new-buffer”:
;; 1. Example (moved unwind-protect up; added inhibit-quit;
;; use generate-new-buffer)
(let (buffer)
(unwind-protect
(progn
(let ((inhibit-quit t))
(setq buffer (generate-new-buffer " *temp*")))
(with-current-buffer buffer
body-form))
(and buffer (kill-buffer buffer))))
Does “generate-new-buffer” make the same guarantee as
“get-buffer-create” that it will never return nil? At least
“generate-new-buffer” is implemented with “get-buffer-create”.
Footnotes:
[1] <https://www.gnu.org/software/emacs/manual/html_node/elisp/Cleanups.html>
(info "(elisp) Cleanups")
[2] “This example has a small bug: if the user types C-g to quit, and the
quit happens immediately after the function ftp-setup-buffer
returns but before the variable process is set, the process will
not be killed. There is no easy way to fix this bug, but at least
it is very unlikely.”
--
Felix Dietrich