]> git.eshelyaron.com Git - emacs.git/commitdiff
Further fixes for kqueue.
authorMichael Albinus <michael.albinus@gmx.de>
Wed, 18 Nov 2015 13:47:25 +0000 (13:47 +0000)
committerMichael Albinus <michael.albinus@gmx.de>
Wed, 18 Nov 2015 13:47:25 +0000 (13:47 +0000)
* lisp/filenotify.el (file-notify-callback): Raise also event if
directory name matches.
(file-notify-add-watch): Add `create' to the flags for `kqueue'.

* src/kqueue.c (kqueue_generate_event): Use watch_object as
argument instead of ident.  Remove callback argument.  Adapt
callees.  Check actions whether they are monitored flags.

* test/automated/file-notify-tests.el (file-notify--test-library):
New defun.
(file-notify-test00-availability, file-notify-test02-events)
(file-notify-test04-file-validity)
(file-notify-test05-dir-validity): Use it.
(file-notify-test02-events, file-notify-test04-file-validity): Add
`read-event' calls between different file actions, in order to
give the backends a chance to rais an event.  Needed especially
for kqueue.  In case of deleting a directory, there are two
`deleted' events.

lisp/filenotify.el
src/kqueue.c
test/automated/file-notify-tests.el

index eb869cf66a93a429bda039ff722b90cb3452c76e..5072bf414bfc83652123a297c39b38cddfaec82a 100644 (file)
@@ -258,6 +258,10 @@ EVENT is the cadr of the event in `file-notify-handle-event'
                    ;; File matches.
                    (string-equal
                     (nth 0 entry) (file-name-nondirectory file))
+                   ;; Directory matches.
+                   (string-equal
+                    (file-name-nondirectory file)
+                    (file-name-nondirectory (car registered)))
                    ;; File1 matches.
                    (and (stringp file1)
                         (string-equal
@@ -364,7 +368,7 @@ FILE is the name of the file whose event is being reported."
            ((eq file-notify--library 'inotify)
             '(create delete delete-self modify move-self move))
            ((eq file-notify--library 'kqueue)
-            '(delete write extend rename))
+            '(create delete write extend rename))
            ((eq file-notify--library 'w32notify)
             '(file-name directory-name size last-write-time)))))
        (when (memq 'attribute-change flags)
index 5caef67b92a2fea61957dbe98c66da21a15fde1b..e2c9dabcb20a04401af5d6c68e74a5d32cde8db1 100644 (file)
@@ -67,21 +67,39 @@ kqueue_directory_listing (Lisp_Object directory_files)
 /* Generate a file notification event.  */
 static void
 kqueue_generate_event
-(Lisp_Object ident, Lisp_Object actions, Lisp_Object file, Lisp_Object file1,
- Lisp_Object callback)
+(Lisp_Object watch_object, Lisp_Object actions,
+ Lisp_Object file, Lisp_Object file1)
 {
+  Lisp_Object flags, action, entry;
   struct input_event event;
-  EVENT_INIT (event);
-  event.kind = FILE_NOTIFY_EVENT;
-  event.frame_or_window = Qnil;
-  event.arg = list2 (Fcons (ident, Fcons (actions,
-                                         NILP (file1)
-                                         ? Fcons (file, Qnil)
-                                         : list2 (file, file1))),
-                    callback);
+
+  /* Check, whether all actions shall be monitored.  */
+  flags = Fnth (make_number (2), watch_object);
+  action = actions;
+  do {
+    if (NILP (action))
+      break;
+    entry = XCAR (action);
+    if (NILP (Fmember (entry, flags))) {
+      action = XCDR (action);
+      actions = Fdelq (entry, actions);
+    } else
+      action = XCDR (action);
+  } while (1);
 
   /* Store it into the input event queue.  */
-  kbd_buffer_store_event (&event);
+  if (! NILP (actions)) {
+    EVENT_INIT (event);
+    event.kind = FILE_NOTIFY_EVENT;
+    event.frame_or_window = Qnil;
+    event.arg = list2 (Fcons (XCAR (watch_object),
+                             Fcons (actions,
+                                    NILP (file1)
+                                    ? Fcons (file, Qnil)
+                                    : list2 (file, file1))),
+                      Fnth (make_number (3), watch_object));
+    kbd_buffer_store_event (&event);
+  }
 }
 
 /* This compares two directory listings in case of a `write' event for
@@ -93,19 +111,16 @@ static void
 kqueue_compare_dir_list
 (Lisp_Object watch_object)
 {
-  Lisp_Object dir, callback;
-  Lisp_Object old_directory_files, old_dl, new_directory_files, new_dl, dl;
+  Lisp_Object dir, old_directory_files, old_dl, new_directory_files, new_dl, dl;
 
   dir = XCAR (XCDR (watch_object));
-  callback = Fnth (make_number (3), watch_object);
 
   old_directory_files = Fnth (make_number (4), watch_object);
   old_dl = kqueue_directory_listing (old_directory_files);
 
   /* When the directory is not accessible anymore, it has been deleted.  */
   if (NILP (Ffile_directory_p (dir))) {
-    kqueue_generate_event
-      (XCAR (watch_object), Fcons (Qdelete, Qnil), dir, Qnil, callback);
+    kqueue_generate_event (watch_object, Fcons (Qdelete, Qnil), dir, Qnil);
     return;
   }
   new_directory_files =
@@ -137,21 +152,20 @@ kqueue_compare_dir_list
        if (NILP (Fequal (Fnth (make_number (2), old_entry),
                          Fnth (make_number (2), new_entry))))
          kqueue_generate_event
-           (XCAR (watch_object), Fcons (Qwrite, Qnil),
-            XCAR (XCDR (old_entry)), Qnil, callback);
+           (watch_object, Fcons (Qwrite, Qnil), XCAR (XCDR (old_entry)), Qnil);
        /* Status change time has been changed, the file attributes
           have changed.  */
          if (NILP (Fequal (Fnth (make_number (3), old_entry),
                            Fnth (make_number (3), new_entry))))
          kqueue_generate_event
-           (XCAR (watch_object), Fcons (Qattrib, Qnil),
-            XCAR (XCDR (old_entry)), Qnil, callback);
+           (watch_object, Fcons (Qattrib, Qnil),
+            XCAR (XCDR (old_entry)), Qnil);
 
       } else {
        /* The file has been renamed.  */
        kqueue_generate_event
-         (XCAR (watch_object), Fcons (Qrename, Qnil),
-          XCAR (XCDR (old_entry)), XCAR (XCDR (new_entry)), callback);
+         (watch_object, Fcons (Qrename, Qnil),
+          XCAR (XCDR (old_entry)), XCAR (XCDR (new_entry)));
       }
       new_dl = Fdelq (new_entry, new_dl);
       goto the_end;
@@ -164,8 +178,7 @@ kqueue_compare_dir_list
       if (strcmp (SSDATA (XCAR (XCDR (old_entry))),
                  SSDATA (XCAR (XCDR (new_entry)))) == 0) {
        kqueue_generate_event
-         (XCAR (watch_object), Fcons (Qwrite, Qnil),
-          XCAR (XCDR (old_entry)), Qnil, callback);
+         (watch_object, Fcons (Qwrite, Qnil), XCAR (XCDR (old_entry)), Qnil);
        new_dl = Fdelq (new_entry, new_dl);
        goto the_end;
       }
@@ -173,8 +186,7 @@ kqueue_compare_dir_list
 
     /* The file has been deleted.  */
     kqueue_generate_event
-      (XCAR (watch_object), Fcons (Qdelete, Qnil),
-       XCAR (XCDR (old_entry)), Qnil, callback);
+      (watch_object, Fcons (Qdelete, Qnil), XCAR (XCDR (old_entry)), Qnil);
 
   the_end:
     dl = XCDR (dl);
@@ -191,15 +203,13 @@ kqueue_compare_dir_list
     /* A new file has appeared.  */
     new_entry = XCAR (dl);
     kqueue_generate_event
-      (XCAR (watch_object), Fcons (Qcreate, Qnil),
-       XCAR (XCDR (new_entry)), Qnil, callback);
+      (watch_object, Fcons (Qcreate, Qnil), XCAR (XCDR (new_entry)), Qnil);
 
     /* Check size of that file.  */
     Lisp_Object size = Fnth (make_number (4), new_entry);
     if (FLOATP (size) || (XINT (size) > 0))
       kqueue_generate_event
-       (XCAR (watch_object), Fcons (Qwrite, Qnil),
-        XCAR (XCDR (new_entry)), Qnil, callback);
+       (watch_object, Fcons (Qwrite, Qnil), XCAR (XCDR (new_entry)), Qnil);
 
     dl = XCDR (dl);
     new_dl = Fdelq (new_entry, new_dl);
@@ -226,7 +236,7 @@ kqueue_callback (int fd, void *data)
   for (;;) {
     struct kevent kev;
     static const struct timespec nullts = { 0, 0 };
-    Lisp_Object descriptor, watch_object, file, callback, actions;
+    Lisp_Object descriptor, watch_object, file, actions;
 
     /* Read one event.  */
     int ret = kevent (kqueuefd, NULL, 0, &kev, 1, &nullts);
@@ -235,14 +245,11 @@ kqueue_callback (int fd, void *data)
       return;
     }
 
-    /* Determine descriptor, file name and callback function.  */
+    /* Determine descriptor and file name.  */
     descriptor = make_number (kev.ident);
     watch_object = assq_no_quit (descriptor, watch_list);
-
-    if (CONSP (watch_object)) {
+    if (CONSP (watch_object))
       file = XCAR (XCDR (watch_object));
-      callback = Fnth (make_number (3), watch_object);
-    }
     else
       continue;
 
@@ -271,7 +278,7 @@ kqueue_callback (int fd, void *data)
 
     /* Create the event.  */
     if (! NILP (actions))
-      kqueue_generate_event (descriptor, actions, file, Qnil, callback);
+      kqueue_generate_event (watch_object, actions, file, Qnil);
 
     /* Cancel monitor if file or directory is deleted or renamed.  */
     if (kev.fflags & (NOTE_DELETE | NOTE_RENAME))
index 67e929a647728d2f3fbb73633131662d31846182..6946541b909309ee9f0331429b0740fa7116de81 100644 (file)
@@ -133,6 +133,18 @@ being the result.")
   ;; Return result.
   (cdr file-notify--test-remote-enabled-checked))
 
+(defun file-notify--test-library ()
+  "The used libray for the test, as string.
+In the remote case, it is the process name which runs on the
+remote host, or nil."
+  (if (null (file-remote-p temporary-file-directory))
+      (symbol-name file-notify--library)
+    (and (consp file-notify--test-remote-enabled-checked)
+        (processp (cdr file-notify--test-remote-enabled-checked))
+        (replace-regexp-in-string
+         "<[[:digit:]]+>\\'" ""
+         (process-name (cdr file-notify--test-remote-enabled-checked))))))
+
 (defmacro file-notify--deftest-remote (test docstring)
   "Define ert `TEST-remote' for remote files."
   (declare (indent 1))
@@ -150,12 +162,7 @@ being the result.")
   "Test availability of `file-notify'."
   (skip-unless (file-notify--test-local-enabled))
   ;; Report the native library which has been used.
-  (if (null (file-remote-p temporary-file-directory))
-      (message "Local library: `%s'" file-notify--library)
-    (message "Remote command: `%s'"
-             (replace-regexp-in-string
-              "<[[:digit:]]+>\\'" ""
-              (process-name (cdr file-notify--test-remote-enabled-checked)))))
+  (message "Library: `%s'" (file-notify--test-library))
   (should
    (setq file-notify--test-desc
          (file-notify-add-watch temporary-file-directory '(change) 'ignore)))
@@ -311,6 +318,7 @@ Don't wait longer than timeout seconds for the events to be delivered."
         (file-notify--test-with-events '(created changed deleted)
           (write-region
            "any text" nil file-notify--test-tmpfile nil 'no-message)
+          (read-event nil nil 0.1)
           (delete-file file-notify--test-tmpfile))
        ;; `file-notify-rm-watch' fires the `stopped' event.  Suppress it.
        (let (file-notify--test-events)
@@ -319,7 +327,7 @@ Don't wait longer than timeout seconds for the events to be delivered."
         ;; Check creation, change and deletion.  There must be a
         ;; `stopped' event when deleting the directory.  It doesn't
         ;; work for w32notify.
-        (unless (eq file-notify--library 'w32notify)
+       (unless (string-equal (file-notify--test-library) "w32notify")
          (make-directory file-notify--test-tmpfile)
          (setq file-notify--test-desc
                (file-notify-add-watch
@@ -327,11 +335,14 @@ Don't wait longer than timeout seconds for the events to be delivered."
                 '(change) 'file-notify--test-event-handler))
          (file-notify--test-with-events
              ;; There are two `deleted' events, for the file and for
-             ;; the directory.
-             '(created changed deleted deleted stopped)
+             ;; the directory.  Except for kqueue.
+             (if (string-equal (file-notify--test-library) "kqueue")
+                 '(created changed deleted stopped)
+               '(created changed deleted deleted stopped))
            (write-region
             "any text" nil (expand-file-name "foo" file-notify--test-tmpfile)
             nil 'no-message)
+           (read-event nil nil 0.1)
            (delete-directory file-notify--test-tmpfile 'recursive))
          ;; `file-notify-rm-watch' fires the `stopped' event.  Suppress it.
          (let (file-notify--test-events)
@@ -346,17 +357,21 @@ Don't wait longer than timeout seconds for the events to be delivered."
         (file-notify--test-with-events
             ;; w32notify does not distinguish between `changed' and
             ;; `attribute-changed'.
-            (if (eq file-notify--library 'w32notify)
+           (if (string-equal (file-notify--test-library) "w32notify")
                 '(created changed changed deleted)
               '(created changed deleted))
           (write-region
            "any text" nil file-notify--test-tmpfile nil 'no-message)
+          (read-event nil nil 0.1)
           (copy-file file-notify--test-tmpfile file-notify--test-tmpfile1)
           ;; The next two events shall not be visible.
+          (read-event nil nil 0.1)
           (set-file-modes file-notify--test-tmpfile 000)
-          (read-event nil nil 0.1) ; In order to distinguish the events.
+          (read-event nil nil 0.1)
           (set-file-times file-notify--test-tmpfile '(0 0))
+          (read-event nil nil 0.1)
           (delete-file file-notify--test-tmpfile)
+          (read-event nil nil 0.1)
           (delete-file file-notify--test-tmpfile1))
        ;; `file-notify-rm-watch' fires the `stopped' event.  Suppress it.
        (let (file-notify--test-events)
@@ -371,15 +386,18 @@ Don't wait longer than timeout seconds for the events to be delivered."
         (file-notify--test-with-events '(created changed renamed)
           (write-region
            "any text" nil file-notify--test-tmpfile nil 'no-message)
+          (read-event nil nil 0.1)
           (rename-file file-notify--test-tmpfile file-notify--test-tmpfile1)
           ;; After the rename, we won't get events anymore.
+          (read-event nil nil 0.1)
           (delete-file file-notify--test-tmpfile1))
        ;; `file-notify-rm-watch' fires the `stopped' event.  Suppress it.
        (let (file-notify--test-events)
          (file-notify-rm-watch file-notify--test-desc))
 
-        ;; Check attribute change.  It doesn't work for w32notify.
-        (unless (eq file-notify--library 'w32notify)
+        ;; Check attribute change.  It doesn't work for kqueue and w32notify.
+       (unless (or (string-equal (file-notify--test-library) "kqueue")
+                   (string-equal (file-notify--test-library) "w32notify"))
           (setq file-notify--test-desc
                 (file-notify-add-watch
                  file-notify--test-tmpfile
@@ -523,6 +541,7 @@ Don't wait longer than timeout seconds for the events to be delivered."
           (should (file-notify-valid-p file-notify--test-desc))
           (write-region
            "any text" nil file-notify--test-tmpfile nil 'no-message)
+         (read-event nil nil 0.1)
          (delete-file file-notify--test-tmpfile))
        ;; After deleting the file, the descriptor is still valid.
         (should (file-notify-valid-p file-notify--test-desc))
@@ -537,8 +556,7 @@ Don't wait longer than timeout seconds for the events to be delivered."
   (unwind-protect
       ;; The batch-mode operation of w32notify is fragile (there's no
       ;; input threads to send the message to).
-      ;(unless (and noninteractive (eq file-notify--library 'w32notify))
-      (unless (eq file-notify--library 'w32notify)
+      (unless (string-equal (file-notify--test-library) "w32notify")
         (let ((temporary-file-directory
               (make-temp-file "file-notify-test-parent" t)))
           (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
@@ -546,10 +564,16 @@ Don't wait longer than timeout seconds for the events to be delivered."
                 (file-notify-add-watch
                  file-notify--test-tmpfile
                  '(change) #'file-notify--test-event-handler))
-          (file-notify--test-with-events '(created changed deleted stopped)
+          (file-notify--test-with-events
+             ;; There are two `deleted' events, for the file and for
+             ;; the directory.  Except for kqueue.
+             (if (string-equal (file-notify--test-library) "kqueue")
+                 '(created changed deleted stopped)
+               '(created changed deleted deleted stopped))
             (should (file-notify-valid-p file-notify--test-desc))
             (write-region
              "any text" nil file-notify--test-tmpfile nil 'no-message)
+            (read-event nil nil 0.1)
            (delete-directory temporary-file-directory t))
           ;; After deleting the parent directory, the descriptor must
           ;; not be valid anymore.
@@ -589,7 +613,8 @@ Don't wait longer than timeout seconds for the events to be delivered."
   (unwind-protect
       ;; The batch-mode operation of w32notify is fragile (there's no
       ;; input threads to send the message to).
-      (unless (and noninteractive (eq file-notify--library 'w32notify))
+      (unless (and noninteractive
+                  (string-equal (file-notify--test-library) "w32notify"))
         (setq file-notify--test-tmpfile
              (file-name-as-directory (file-notify--test-make-temp-name)))
         (make-directory file-notify--test-tmpfile)