unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: "Mattias Engdegård" <mattiase@acm.org>
To: Michael Albinus <michael.albinus@gmx.de>
Cc: Emacs developers <emacs-devel@gnu.org>
Subject: Re: master e9e807e: Don't remove notify descriptor that is already gone
Date: Sat, 20 Apr 2019 12:20:15 +0200	[thread overview]
Message-ID: <B142C60C-2800-42F0-BD39-A53E9B83589D@acm.org> (raw)
In-Reply-To: <87wojqhwlk.fsf@gmx.de>

[-- Attachment #1: Type: text/plain, Size: 2939 bytes --]

19 apr. 2019 kl. 16.56 skrev Michael Albinus <michael.albinus@gmx.de>:
> 
>> (Not only is `auto-revert-notify-watch-descriptor-hash-list' a
>> mouthful, it is a bit misleading. It maps descriptors to lists of
>> buffers. How about `auto-revert--buffers-by-watch-descriptor'?)
> 
> No objection.

Thanks, I'll do this separately.

>> Slightly more robust would be to stop reusing descriptors: either made
>> mutable, so that they can be invalidated, or made unique by using a
>> counter. However, the basic design is still somewhat dubious: it tells
>> us whether the descriptor is valid, but that just raises the question:
>> why do we even have to ask? Correct code should understand its own
>> invariants.
> 
> In theory you are right. But I fear there could be situations where such
> assumptions do ne keep. A double-check is OK.

What about using the checks in assertions to validate the assumptions, instead of making the code bug-tolerant? Assertions both inform the reader and check correctness.

After all, bug-tolerant code just leads to more bugs, to code where the just-in-case conditions cannot be distinguished from the essential ones, and where nobody understands the invariants.

>> Now that you `mentioned auto-revert-notify-rm-watch', does it strike
>> you as odd the way it does
>> 
>>    (maphash
>>     (lambda (key value)
>>       (when (equal key some-key)
>>         do-something))
>>     some-hashtable)
>> 
>> instead of using the hash table directly? Suggested patch to fix this
>> attached.
> 
> I'm still not convinced that we need REMOVE-DESCRIPTOR. We shall always
> remove the descriptor, and assure, that no superfluous events are raised.

Can I take it that you are happy with the patch attached to that message, which just does away with the maphash?

Regarding getting rid of remove-descriptor, that's fine with me -- I'm attaching a new patch which does the work in file-notify instead, which is how I interpret your wish. With that patch, e9e807e931 (addition of the remove-descriptor parameter) can be reverted.

>> By the way, why don't we give each buffer in auto-revert-mode a unique
>> descriptor, so that the table just maps descriptors to buffers,
>> instead of to lists of buffers? It would simplify the code in many
>> places, and it cannot be that common to have multiple buffers for the
>> same file that it warrants the descriptor-sharing optimisation.
> 
> Well, the descriptor is the one we get from filenotify. I don't believe
> we shall do double housekeeping. Sounds to me error-prone.

Agreed, and filenotify seems to ensure that each watch gets a distinct descriptor even for the same file. I'll prepare a patch for simplifying the table in autorevert.el, unless you can remember the reason for introducing the buffer lists in ef3544f6a6. I have read bug#13540, which is mentioned in the commit message, and am none the wiser.


[-- Attachment #2: 0001-Make-file-notify-rm-watch-robust-against-reentry.patch --]
[-- Type: application/octet-stream, Size: 4609 bytes --]

From 1105a7d356b1adfb2a39ae29f4970e997f37a2f6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Sat, 20 Apr 2019 10:19:52 +0200
Subject: [PATCH] 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 3f9bb960a9..62dd1cd911 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.
-- 
2.20.1 (Apple Git-117)


  reply	other threads:[~2019-04-20 10:20 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20190415083338.9906.18508@vcs0.savannah.gnu.org>
     [not found] ` <20190415083339.64FE620536@vcs0.savannah.gnu.org>
2019-04-16  7:04   ` master e9e807e: Don't remove notify descriptor that is already gone Michael Albinus
2019-04-16 13:31     ` Mattias Engdegård
2019-04-19 14:56       ` Michael Albinus
2019-04-20 10:20         ` Mattias Engdegård [this message]
2019-04-22  8:37           ` Michael Albinus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=B142C60C-2800-42F0-BD39-A53E9B83589D@acm.org \
    --to=mattiase@acm.org \
    --cc=emacs-devel@gnu.org \
    --cc=michael.albinus@gmx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).