aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2019-04-20 10:19:52 +0200
committerMattias EngdegÄrd2019-04-22 17:54:32 +0200
commitc243aabfa8d280adf75024c8e6c0e68a7932f6cf (patch)
tree72bb8683c4ce909d18be2d180a174e86c1927df5
parent4e2ea400cbd78fa791fb897938a6dcb099401a25 (diff)
downloademacs-c243aabfa8d280adf75024c8e6c0e68a7932f6cf.tar.gz
emacs-c243aabfa8d280adf75024c8e6c0e68a7932f6cf.zip
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.
-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.")
49 directory 49 directory
50 ;; Watched relative filename, nil if watching the directory. 50 ;; Watched relative filename, nil if watching the directory.
51 filename 51 filename
52 ;; Function to propagate events to. 52 ;; Function to propagate events to, or nil if watch is being removed.
53 callback) 53 callback)
54 54
55(defun file-notify--watch-absolute-filename (watch) 55(defun file-notify--watch-absolute-filename (watch)
@@ -72,12 +72,15 @@ struct.")
72DESCRIPTOR should be an object returned by `file-notify-add-watch'. 72DESCRIPTOR should be an object returned by `file-notify-add-watch'.
73If it is registered in `file-notify-descriptors', a stopped event is sent." 73If it is registered in `file-notify-descriptors', a stopped event is sent."
74 (when-let* ((watch (gethash descriptor file-notify-descriptors))) 74 (when-let* ((watch (gethash descriptor file-notify-descriptors)))
75 ;; Send `stopped' event. 75 (let ((callback (file-notify--watch-callback watch)))
76 (unwind-protect 76 ;; Make sure this is the last time the callback is invoked.
77 (funcall 77 (setf (file-notify--watch-callback watch) nil)
78 (file-notify--watch-callback watch) 78 ;; Send `stopped' event.
79 `(,descriptor stopped ,(file-notify--watch-absolute-filename watch))) 79 (unwind-protect
80 (remhash descriptor file-notify-descriptors)))) 80 (funcall
81 callback
82 `(,descriptor stopped ,(file-notify--watch-absolute-filename watch)))
83 (remhash descriptor file-notify-descriptors)))))
81 84
82;; This function is used by `inotify', `kqueue', `gfilenotify' and 85;; This function is used by `inotify', `kqueue', `gfilenotify' and
83;; `w32notify' events. 86;; `w32notify' events.
@@ -381,25 +384,27 @@ FILE is the name of the file whose event is being reported."
381 "Remove an existing watch specified by its DESCRIPTOR. 384 "Remove an existing watch specified by its DESCRIPTOR.
382DESCRIPTOR should be an object returned by `file-notify-add-watch'." 385DESCRIPTOR should be an object returned by `file-notify-add-watch'."
383 (when-let* ((watch (gethash descriptor file-notify-descriptors))) 386 (when-let* ((watch (gethash descriptor file-notify-descriptors)))
384 (let ((handler (find-file-name-handler 387 ;; If we are called from a `stopped' event, do nothing.
385 (file-notify--watch-directory watch) 388 (when (file-notify--watch-callback watch)
386 'file-notify-rm-watch))) 389 (let ((handler (find-file-name-handler
387 (condition-case nil 390 (file-notify--watch-directory watch)
388 (if handler 391 'file-notify-rm-watch)))
389 ;; A file name handler could exist even if there is no 392 (condition-case nil
390 ;; local file notification support. 393 (if handler
391 (funcall handler 'file-notify-rm-watch descriptor) 394 ;; A file name handler could exist even if there is no
392 395 ;; local file notification support.
393 (funcall 396 (funcall handler 'file-notify-rm-watch descriptor)
394 (cond 397
395 ((eq file-notify--library 'inotify) 'inotify-rm-watch) 398 (funcall
396 ((eq file-notify--library 'kqueue) 'kqueue-rm-watch) 399 (cond
397 ((eq file-notify--library 'gfilenotify) 'gfile-rm-watch) 400 ((eq file-notify--library 'inotify) 'inotify-rm-watch)
398 ((eq file-notify--library 'w32notify) 'w32notify-rm-watch)) 401 ((eq file-notify--library 'kqueue) 'kqueue-rm-watch)
399 descriptor)) 402 ((eq file-notify--library 'gfilenotify) 'gfile-rm-watch)
400 (file-notify-error nil))) 403 ((eq file-notify--library 'w32notify) 'w32notify-rm-watch))
401 ;; Modify `file-notify-descriptors'. 404 descriptor))
402 (file-notify--rm-descriptor descriptor))) 405 (file-notify-error nil)))
406 ;; Modify `file-notify-descriptors' and send a `stopped' event.
407 (file-notify--rm-descriptor descriptor))))
403 408
404(defun file-notify-valid-p (descriptor) 409(defun file-notify-valid-p (descriptor)
405 "Check a watch specified by its DESCRIPTOR. 410 "Check a watch specified by its DESCRIPTOR.