summaryrefslogtreecommitdiff
path: root/lisp/filenotify.el
diff options
context:
space:
mode:
authorMattias EngdegÄrd <mattiase@acm.org>2019-04-20 10:19:52 +0200
committerMattias EngdegÄrd <mattiase@acm.org>2019-04-22 17:54:32 +0200
commitc243aabfa8d280adf75024c8e6c0e68a7932f6cf (patch)
tree72bb8683c4ce909d18be2d180a174e86c1927df5 /lisp/filenotify.el
parent4e2ea400cbd78fa791fb897938a6dcb099401a25 (diff)
downloademacs-c243aabfa8d280adf75024c8e6c0e68a7932f6cf.tar.gz
Make file-notify-rm-watch robust against reentry
Allow file-notify callbacks to call `file-notify-rm-watch', harmlessly, after receiving a `stopped' event without triggering recursion. * lisp/filenotify.el (file-notify--watch): Note that `callback' can be nil. (file-notify--rm-descriptor): Set the `callback' field to nil before sending `stopped'. (file-notify-rm-watch): Don't do anything if the `callback' field is nil.
Diffstat (limited to 'lisp/filenotify.el')
-rw-r--r--lisp/filenotify.el57
1 files changed, 31 insertions, 26 deletions
diff --git a/lisp/filenotify.el b/lisp/filenotify.el
index 3f9bb960a9b..62dd1cd9117 100644
--- a/lisp/filenotify.el
+++ b/lisp/filenotify.el
@@ -49,7 +49,7 @@ could use another implementation.")
directory
;; Watched relative filename, nil if watching the directory.
filename
- ;; Function to propagate events to.
+ ;; Function to propagate events to, or nil if watch is being removed.
callback)
(defun file-notify--watch-absolute-filename (watch)
@@ -72,12 +72,15 @@ struct.")
DESCRIPTOR should be an object returned by `file-notify-add-watch'.
If it is registered in `file-notify-descriptors', a stopped event is sent."
(when-let* ((watch (gethash descriptor file-notify-descriptors)))
- ;; Send `stopped' event.
- (unwind-protect
- (funcall
- (file-notify--watch-callback watch)
- `(,descriptor stopped ,(file-notify--watch-absolute-filename watch)))
- (remhash descriptor file-notify-descriptors))))
+ (let ((callback (file-notify--watch-callback watch)))
+ ;; Make sure this is the last time the callback is invoked.
+ (setf (file-notify--watch-callback watch) nil)
+ ;; Send `stopped' event.
+ (unwind-protect
+ (funcall
+ callback
+ `(,descriptor stopped ,(file-notify--watch-absolute-filename watch)))
+ (remhash descriptor file-notify-descriptors)))))
;; This function is used by `inotify', `kqueue', `gfilenotify' and
;; `w32notify' events.
@@ -381,25 +384,27 @@ FILE is the name of the file whose event is being reported."
"Remove an existing watch specified by its DESCRIPTOR.
DESCRIPTOR should be an object returned by `file-notify-add-watch'."
(when-let* ((watch (gethash descriptor file-notify-descriptors)))
- (let ((handler (find-file-name-handler
- (file-notify--watch-directory watch)
- 'file-notify-rm-watch)))
- (condition-case nil
- (if handler
- ;; A file name handler could exist even if there is no
- ;; local file notification support.
- (funcall handler 'file-notify-rm-watch descriptor)
-
- (funcall
- (cond
- ((eq file-notify--library 'inotify) 'inotify-rm-watch)
- ((eq file-notify--library 'kqueue) 'kqueue-rm-watch)
- ((eq file-notify--library 'gfilenotify) 'gfile-rm-watch)
- ((eq file-notify--library 'w32notify) 'w32notify-rm-watch))
- descriptor))
- (file-notify-error nil)))
- ;; Modify `file-notify-descriptors'.
- (file-notify--rm-descriptor descriptor)))
+ ;; If we are called from a `stopped' event, do nothing.
+ (when (file-notify--watch-callback watch)
+ (let ((handler (find-file-name-handler
+ (file-notify--watch-directory watch)
+ 'file-notify-rm-watch)))
+ (condition-case nil
+ (if handler
+ ;; A file name handler could exist even if there is no
+ ;; local file notification support.
+ (funcall handler 'file-notify-rm-watch descriptor)
+
+ (funcall
+ (cond
+ ((eq file-notify--library 'inotify) 'inotify-rm-watch)
+ ((eq file-notify--library 'kqueue) 'kqueue-rm-watch)
+ ((eq file-notify--library 'gfilenotify) 'gfile-rm-watch)
+ ((eq file-notify--library 'w32notify) 'w32notify-rm-watch))
+ descriptor))
+ (file-notify-error nil)))
+ ;; Modify `file-notify-descriptors' and send a `stopped' event.
+ (file-notify--rm-descriptor descriptor))))
(defun file-notify-valid-p (descriptor)
"Check a watch specified by its DESCRIPTOR.