aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albinus2015-11-15 17:45:32 +0000
committerMichael Albinus2015-11-25 15:07:11 +0100
commite95b309ae4f5fbdebdb7067daca9d091925047cf (patch)
treee2671f96cbc0e803ee927af06c3781eb03c52788
parent41d9bd0c3b19d839b72fdd20e613cb6ab3b1b1f4 (diff)
downloademacs-e95b309ae4f5fbdebdb7067daca9d091925047cf.tar.gz
emacs-e95b309ae4f5fbdebdb7067daca9d091925047cf.zip
More work on kqueue
* lisp/filenotify.el (file-notify-callback): Handle also the `rename' event from kqueue. (file-notify-add-watch): Do not register an entry twice. * src/kqueue.c (kqueue_directory_listing): New function. (kqueue_generate_event): New argument FILE1. Adapt callees. (kqueue_compare_dir_list): Rewrite in order to make it more robust.
-rw-r--r--lisp/filenotify.el21
-rw-r--r--src/kqueue.c190
2 files changed, 149 insertions, 62 deletions
diff --git a/lisp/filenotify.el b/lisp/filenotify.el
index f7c97569825..23029427760 100644
--- a/lisp/filenotify.el
+++ b/lisp/filenotify.el
@@ -189,7 +189,7 @@ EVENT is the cadr of the event in `file-notify-handle-event'
189 ((memq action 189 ((memq action
190 '(attribute-changed changed created deleted renamed)) 190 '(attribute-changed changed created deleted renamed))
191 action) 191 action)
192 ((eq action 'moved) 192 ((memq action '(moved rename))
193 (setq file1 (file-notify--event-file1-name event)) 193 (setq file1 (file-notify--event-file1-name event))
194 'renamed) 194 'renamed)
195 ((eq action 'ignored) 195 ((eq action 'ignored)
@@ -329,7 +329,7 @@ FILE is the name of the file whose event is being reported."
329 (if (file-directory-p file) 329 (if (file-directory-p file)
330 file 330 file
331 (file-name-directory file)))) 331 (file-name-directory file))))
332 desc func l-flags registered) 332 desc func l-flags registered entry)
333 333
334 (unless (file-directory-p dir) 334 (unless (file-directory-p dir)
335 (signal 'file-notify-error `("Directory does not exist" ,dir))) 335 (signal 'file-notify-error `("Directory does not exist" ,dir)))
@@ -378,18 +378,15 @@ FILE is the name of the file whose event is being reported."
378 (setq desc (funcall func dir l-flags 'file-notify-callback))) 378 (setq desc (funcall func dir l-flags 'file-notify-callback)))
379 379
380 ;; Modify `file-notify-descriptors'. 380 ;; Modify `file-notify-descriptors'.
381 (setq registered (gethash desc file-notify-descriptors)) 381 (setq file (unless (file-directory-p file) (file-name-nondirectory file))
382 (puthash 382 desc (file-notify--descriptor desc file)
383 desc 383 registered (gethash desc file-notify-descriptors)
384 `(,dir 384 entry `(,file . ,callback))
385 (,(unless (file-directory-p file) (file-name-nondirectory file)) 385 (unless (member entry (cdr registered))
386 . ,callback) 386 (puthash desc `(,dir ,entry . ,(cdr registered)) file-notify-descriptors))
387 . ,(cdr registered))
388 file-notify-descriptors)
389 387
390 ;; Return descriptor. 388 ;; Return descriptor.
391 (file-notify--descriptor 389 desc))
392 desc (unless (file-directory-p file) (file-name-nondirectory file)))))
393 390
394(defun file-notify-rm-watch (descriptor) 391(defun file-notify-rm-watch (descriptor)
395 "Remove an existing watch specified by its DESCRIPTOR. 392 "Remove an existing watch specified by its DESCRIPTOR.
diff --git a/src/kqueue.c b/src/kqueue.c
index 0425a142a98..2097b7ed492 100644
--- a/src/kqueue.c
+++ b/src/kqueue.c
@@ -35,16 +35,42 @@ static int kqueuefd = -1;
35/* This is a list, elements are (DESCRIPTOR FILE FLAGS CALLBACK [DIRLIST]) */ 35/* This is a list, elements are (DESCRIPTOR FILE FLAGS CALLBACK [DIRLIST]) */
36static Lisp_Object watch_list; 36static Lisp_Object watch_list;
37 37
38/* Generate a temporary list from the directory_files_internal output.
39 Items are (INODE FILE_NAME LAST_MOD LAST_STATUS_MOD SIZE). */
40Lisp_Object
41kqueue_directory_listing (Lisp_Object directory_files)
42{
43 Lisp_Object dl, result = Qnil;
44 for (dl = directory_files; ! NILP (dl); dl = XCDR (dl)) {
45 result = Fcons
46 (list5 (/* inode. */
47 XCAR (Fnthcdr (make_number (11), XCAR (dl))),
48 /* filename. */
49 XCAR (XCAR (dl)),
50 /* last modification time. */
51 XCAR (Fnthcdr (make_number (6), XCAR (dl))),
52 /* last status change time. */
53 XCAR (Fnthcdr (make_number (7), XCAR (dl))),
54 /* size. */
55 XCAR (Fnthcdr (make_number (8), XCAR (dl)))),
56 result);
57 }
58 return result;
59}
60
38/* Generate a file notification event. */ 61/* Generate a file notification event. */
39static void 62static void
40kqueue_generate_event 63kqueue_generate_event
41(Lisp_Object ident, Lisp_Object actions, Lisp_Object file, Lisp_Object callback) 64(Lisp_Object ident, Lisp_Object actions, Lisp_Object file, Lisp_Object file1, Lisp_Object callback)
42{ 65{
43 struct input_event event; 66 struct input_event event;
44 EVENT_INIT (event); 67 EVENT_INIT (event);
45 event.kind = FILE_NOTIFY_EVENT; 68 event.kind = FILE_NOTIFY_EVENT;
46 event.frame_or_window = Qnil; 69 event.frame_or_window = Qnil;
47 event.arg = list2 (Fcons (ident, Fcons (actions, Fcons (file, Qnil))), 70 event.arg = list2 (Fcons (ident, Fcons (actions,
71 NILP (file1)
72 ? Fcons (file, Qnil)
73 : list2 (file, file1))),
48 callback); 74 callback);
49 75
50 /* Store it into the input event queue. */ 76 /* Store it into the input event queue. */
@@ -53,73 +79,140 @@ kqueue_generate_event
53 79
54/* This compares two directory listings in case of a `write' event for 80/* This compares two directory listings in case of a `write' event for
55 a directory. The old directory listing is stored in watch_object, 81 a directory. The old directory listing is stored in watch_object,
56 it will be replaced by a new directory listing at the end. */ 82 it will be replaced by a new directory listing at the end of this
83 function. */
57static void 84static void
58kqueue_compare_dir_list (Lisp_Object watch_object) 85kqueue_compare_dir_list
86(Lisp_Object watch_object)
59{ 87{
60 Lisp_Object dir, callback, old_dl, new_dl, dl, actions; 88 Lisp_Object dir, callback, actions;
89 Lisp_Object old_directory_files, old_dl, new_directory_files, new_dl, dl;
61 90
62 dir = XCAR (XCDR (watch_object)); 91 dir = XCAR (XCDR (watch_object));
63 callback = XCAR (XCDR (XCDR (XCDR (watch_object)))); 92 callback = XCAR (Fnthcdr (make_number (3), watch_object));
64 old_dl = XCAR (XCDR (XCDR (XCDR (XCDR (watch_object))))); 93 old_directory_files = XCAR (Fnthcdr (make_number (4), watch_object));
65 new_dl = directory_files_internal (dir, Qnil, Qnil, Qnil, 1, Qnil); 94 old_dl = kqueue_directory_listing (old_directory_files);
66 95 new_directory_files =
67 for (dl = old_dl; ! NILP (dl); dl = XCDR (dl)) { 96 directory_files_internal (dir, Qnil, Qnil, Qnil, 1, Qnil);
97 new_dl = kqueue_directory_listing (new_directory_files);
98
99 /* Parse through the old list. */
100 dl = old_dl;
101 while (1) {
68 Lisp_Object old_entry, new_entry; 102 Lisp_Object old_entry, new_entry;
69 old_entry = XCAR (dl); 103 if (NILP (dl))
70 new_entry = Fassoc (XCAR (old_entry), new_dl); 104 break;
71 105
72 /* We ignore "." and "..". */ 106 /* We ignore "." and "..". */
73 if ((strcmp (".", SSDATA (XCAR (old_entry))) == 0) || 107 old_entry = XCAR (dl);
74 (strcmp ("..", SSDATA (XCAR (old_entry))) == 0)) 108 if ((strcmp (".", SSDATA (XCAR (XCDR (old_entry)))) == 0) ||
75 continue; 109 (strcmp ("..", SSDATA (XCAR (XCDR (old_entry)))) == 0))
110 goto the_end;
76 111
77 /* A file has disappeared. */ 112 /* Search for an entry with the same inode. */
78 if (NILP (new_entry)) 113 new_entry = Fassoc (XCAR (old_entry), new_dl);
79 kqueue_generate_event 114 if (! NILP (Fequal (old_entry, new_entry))) {
80 (XCAR (watch_object), Fcons (Qdelete, Qnil), 115 /* Both entries are identical. Nothing happens. */
81 XCAR (old_entry), callback); 116 new_dl = Fdelq (new_entry, new_dl);
82 117 goto the_end;
83 else { 118 }
84 /* A file has changed. We compare last modification time. */ 119
85 if (NILP 120 if (! NILP (new_entry)) {
86 (Fequal 121 /* Both entries have the same inode. */
87 (XCAR (XCDR (XCDR (XCDR (XCDR (XCDR (XCDR (old_entry))))))), 122 if (strcmp (SSDATA (XCAR (XCDR (old_entry))),
88 XCAR (XCDR (XCDR (XCDR (XCDR (XCDR (XCDR (new_entry)))))))))) 123 SSDATA (XCAR (XCDR (new_entry)))) == 0) {
124 /* Both entries have the same file name. */
125 if (! NILP (Fequal (XCAR (Fnthcdr (make_number (2), old_entry)),
126 XCAR (Fnthcdr (make_number (2), new_entry)))))
127 /* Modification time has been changed, the file has been written. */
128 kqueue_generate_event
129 (XCAR (watch_object), Fcons (Qwrite, Qnil),
130 XCAR (XCDR (old_entry)), Qnil, callback);
131 if (! NILP (Fequal (XCAR (Fnthcdr (make_number (3), old_entry)),
132 XCAR (Fnthcdr (make_number (3), new_entry)))))
133 /* Status change time has been changed, the file attributes
134 have changed. */
135 kqueue_generate_event
136 (XCAR (watch_object), Fcons (Qattrib, Qnil),
137 XCAR (XCDR (old_entry)), Qnil, callback);
138
139 } else {
140 /* The file has been renamed. */
89 kqueue_generate_event 141 kqueue_generate_event
90 (XCAR (watch_object), Fcons (Qwrite, Qnil), 142 (XCAR (watch_object), Fcons (Qrename, Qnil),
91 XCAR (old_entry), callback); 143 XCAR (XCDR (old_entry)), XCAR (XCDR (new_entry)), callback);
144 }
145 new_dl = Fdelq (new_entry, new_dl);
146 goto the_end;
147 }
92 148
93 /* A file attribute has changed. We compare last status change time. */ 149 /* Search, whether there is a file with the same name (with
94 if (NILP 150 another inode). */
95 (Fequal 151 Lisp_Object dl1;
96 (XCAR (XCDR (XCDR (XCDR (XCDR (XCDR (XCDR (XCDR (old_entry)))))))), 152 for (dl1 = new_dl; ! NILP (dl1); dl1 = XCDR (dl1)) {
97 XCAR (XCDR (XCDR (XCDR (XCDR (XCDR (XCDR (XCDR (new_entry))))))))))) 153 new_entry = XCAR (dl1);
154 if (strcmp (SSDATA (XCAR (XCDR (old_entry))),
155 SSDATA (XCAR (XCDR (new_entry)))) == 0) {
98 kqueue_generate_event 156 kqueue_generate_event
99 (XCAR (watch_object), Fcons (Qattrib, Qnil), 157 (XCAR (watch_object), Fcons (Qwrite, Qnil),
100 XCAR (old_entry), callback); 158 XCAR (XCDR (old_entry)), Qnil, callback);
159 new_dl = Fdelq (new_entry, new_dl);
160 goto the_end;
161 }
101 } 162 }
163
164 /* A file has been deleted. */
165 kqueue_generate_event
166 (XCAR (watch_object), Fcons (Qdelete, Qnil),
167 XCAR (XCDR (old_entry)), Qnil, callback);
168
169 the_end:
170 dl = XCDR (dl);
171 old_dl = Fdelq (old_entry, old_dl);
102 } 172 }
103 173
104 for (dl = new_dl; ! NILP (dl); dl = XCDR (dl)) { 174 /* Parse through the shortened new list. */
105 Lisp_Object old_entry, new_entry; 175 dl = new_dl;
106 new_entry = XCAR (dl); 176 while (1) {
107 old_entry = Fassoc (XCAR (new_entry), old_dl); 177 Lisp_Object new_entry;
178 if (NILP (dl))
179 break;
108 180
109 /* We ignore "." and "..". */ 181 /* We ignore "." and "..". */
110 if ((strcmp (".", SSDATA (XCAR (new_entry))) == 0) || 182 new_entry = XCAR (dl);
111 (strcmp ("..", SSDATA (XCAR (new_entry))) == 0)) 183 if ((strcmp (".", SSDATA (XCAR (XCDR (new_entry)))) == 0) ||
184 (strcmp ("..", SSDATA (XCAR (XCDR (new_entry)))) == 0)) {
185 dl = XCDR (dl);
186 new_dl = Fdelq (new_entry, new_dl);
112 continue; 187 continue;
188 }
113 189
114 /* A new file has appeared. */ 190 /* A new file has appeared. */
115 if (NILP (old_entry)) 191 kqueue_generate_event
192 (XCAR (watch_object), Fcons (Qcreate, Qnil),
193 XCAR (XCDR (new_entry)), Qnil, callback);
194
195 /* Check size of that file. */
196 Lisp_Object size = XCAR (Fnthcdr (make_number (4), new_entry));
197 if (FLOATP (size) || (XINT (size) > 0))
116 kqueue_generate_event 198 kqueue_generate_event
117 (XCAR (watch_object), Fcons (Qcreate, Qnil), 199 (XCAR (watch_object), Fcons (Qwrite, Qnil),
118 XCAR (new_entry), callback); 200 XCAR (XCDR (new_entry)), Qnil, callback);
201
202 dl = XCDR (dl);
203 new_dl = Fdelq (new_entry, new_dl);
119 } 204 }
120 205
206 /* At this point, both old_dl and new_dl shall be empty. Let's make
207 a check for this (might be removed once the code is stable). */
208 if (! NILP (old_dl))
209 report_file_error ("Old list not empty", old_dl);
210 if (! NILP (new_dl))
211 report_file_error ("New list not empty", new_dl);
212
121 /* Replace directory listing with the new one. */ 213 /* Replace directory listing with the new one. */
122 XSETCDR (XCDR (XCDR (XCDR (watch_object))), Fcons (new_dl, Qnil)); 214 XSETCDR (XCDR (XCDR (XCDR (watch_object))),
215 Fcons (new_directory_files, Qnil));
123 return; 216 return;
124} 217}
125 218
@@ -173,7 +266,7 @@ kqueue_callback (int fd, void *data)
173 266
174 /* Construct an event. */ 267 /* Construct an event. */
175 if (! NILP (actions)) 268 if (! NILP (actions))
176 kqueue_generate_event (monitor_object, actions, file, callback); 269 kqueue_generate_event (monitor_object, actions, file, Qnil, callback);
177 270
178 /* Cancel monitor if file or directory is deleted. */ 271 /* Cancel monitor if file or directory is deleted. */
179 if (kev.fflags & (NOTE_DELETE | NOTE_RENAME)) 272 if (kev.fflags & (NOTE_DELETE | NOTE_RENAME))
@@ -352,9 +445,6 @@ syms_of_kqueue (void)
352 445
353#endif /* HAVE_KQUEUE */ 446#endif /* HAVE_KQUEUE */
354 447
355/* TODO
356 * Add FILE1 in case of `rename'. */
357
358/* PROBLEMS 448/* PROBLEMS
359 * https://bugs.launchpad.net/ubuntu/+source/libkqueue/+bug/1514837 449 * https://bugs.launchpad.net/ubuntu/+source/libkqueue/+bug/1514837
360 prevents tests on Ubuntu. */ 450 prevents tests on Ubuntu. */