emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master c243aab 1/3: Make file-notify-rm-watch robust again


From: Mattias Engdegård
Subject: [Emacs-diffs] master c243aab 1/3: Make file-notify-rm-watch robust against reentry
Date: Mon, 22 Apr 2019 12:19:37 -0400 (EDT)

branch: master
commit c243aabfa8d280adf75024c8e6c0e68a7932f6cf
Author: Mattias Engdegård <address@hidden>
Commit: Mattias Engdegård <address@hidden>

    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.
---
 lisp/filenotify.el | 57 +++++++++++++++++++++++++++++-------------------------
 1 file changed, 31 insertions(+), 26 deletions(-)

diff --git a/lisp/filenotify.el b/lisp/filenotify.el
index 3f9bb96..62dd1cd 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.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]