aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albinus2015-11-17 15:46:29 +0000
committerMichael Albinus2015-11-17 15:46:29 +0000
commitbad2b4dbc6dee26bde4b2da73cf9c295f0a31f97 (patch)
tree5253623c0b26b21ed7898a0db70826b5be64ae5c
parentb5804c3a08cca4082bb2bcff1ab70c94ba0c7b96 (diff)
downloademacs-bad2b4dbc6dee26bde4b2da73cf9c295f0a31f97.tar.gz
emacs-bad2b4dbc6dee26bde4b2da73cf9c295f0a31f97.zip
Code cleanup of kqueue.c
* src/kqueue.c (kqueue_directory_listing): Skip "." and "..". (kqueue_compare_dir_list): Do not loop when calling directory_files_internal. Remove checks for "." and "..", this is done in kqueue_directory_listing now. (Fkqueue_add_watch): Check for proper emacs_open flags.
-rw-r--r--src/kqueue.c109
1 files changed, 57 insertions, 52 deletions
diff --git a/src/kqueue.c b/src/kqueue.c
index dfd91397370..5caef67b92a 100644
--- a/src/kqueue.c
+++ b/src/kqueue.c
@@ -35,13 +35,19 @@ 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. 38/* Generate a list from the directory_files_internal output.
39 Items are (INODE FILE-NAME LAST-MOD LAST-STATUS-MOD SIZE). */ 39 Items are (INODE FILE-NAME LAST-MOD LAST-STATUS-MOD SIZE). */
40Lisp_Object 40Lisp_Object
41kqueue_directory_listing (Lisp_Object directory_files) 41kqueue_directory_listing (Lisp_Object directory_files)
42{ 42{
43 Lisp_Object dl, result = Qnil; 43 Lisp_Object dl, result = Qnil;
44
44 for (dl = directory_files; ! NILP (dl); dl = XCDR (dl)) { 45 for (dl = directory_files; ! NILP (dl); dl = XCDR (dl)) {
46 /* We ignore "." and "..". */
47 if ((strcmp (".", SSDATA (XCAR (XCAR (dl)))) == 0) ||
48 (strcmp ("..", SSDATA (XCAR (XCAR (dl)))) == 0))
49 continue;
50
45 result = Fcons 51 result = Fcons
46 (list5 (/* inode. */ 52 (list5 (/* inode. */
47 Fnth (make_number (11), XCAR (dl)), 53 Fnth (make_number (11), XCAR (dl)),
@@ -61,7 +67,8 @@ kqueue_directory_listing (Lisp_Object directory_files)
61/* Generate a file notification event. */ 67/* Generate a file notification event. */
62static void 68static void
63kqueue_generate_event 69kqueue_generate_event
64(Lisp_Object ident, Lisp_Object actions, Lisp_Object file, Lisp_Object file1, Lisp_Object callback) 70(Lisp_Object ident, Lisp_Object actions, Lisp_Object file, Lisp_Object file1,
71 Lisp_Object callback)
65{ 72{
66 struct input_event event; 73 struct input_event event;
67 EVENT_INIT (event); 74 EVENT_INIT (event);
@@ -78,14 +85,15 @@ kqueue_generate_event
78} 85}
79 86
80/* This compares two directory listings in case of a `write' event for 87/* This compares two directory listings in case of a `write' event for
81 a directory. The old directory listing is stored in watch_object, 88 a directory. Generate resulting file notification events. The old
82 it will be replaced by a new directory listing at the end of this 89 directory listing is retrieved from watch_object, it will be
90 replaced by the new directory listing at the end of this
83 function. */ 91 function. */
84static void 92static void
85kqueue_compare_dir_list 93kqueue_compare_dir_list
86(Lisp_Object watch_object) 94(Lisp_Object watch_object)
87{ 95{
88 Lisp_Object dir, callback, actions; 96 Lisp_Object dir, callback;
89 Lisp_Object old_directory_files, old_dl, new_directory_files, new_dl, dl; 97 Lisp_Object old_directory_files, old_dl, new_directory_files, new_dl, dl;
90 98
91 dir = XCAR (XCDR (watch_object)); 99 dir = XCAR (XCDR (watch_object));
@@ -94,37 +102,28 @@ kqueue_compare_dir_list
94 old_directory_files = Fnth (make_number (4), watch_object); 102 old_directory_files = Fnth (make_number (4), watch_object);
95 old_dl = kqueue_directory_listing (old_directory_files); 103 old_dl = kqueue_directory_listing (old_directory_files);
96 104
97 /* Sometimes, the directory write event is triggered when the change 105 /* When the directory is not accessible anymore, it has been deleted. */
98 is not visible yet in the directory itself. So we must wait a
99 little bit. */
100 if (NILP (Ffile_directory_p (dir))) { 106 if (NILP (Ffile_directory_p (dir))) {
101 kqueue_generate_event 107 kqueue_generate_event
102 (XCAR (watch_object), Fcons (Qdelete, Qnil), dir, Qnil, callback); 108 (XCAR (watch_object), Fcons (Qdelete, Qnil), dir, Qnil, callback);
103 return; 109 return;
104 } 110 }
105 do { 111 new_directory_files =
106 new_directory_files = 112 directory_files_internal (dir, Qnil, Qnil, Qnil, 1, Qnil);
107 directory_files_internal (dir, Qnil, Qnil, Qnil, 1, Qnil);
108 } while (! NILP (Fequal (old_directory_files, new_directory_files)));
109 new_dl = kqueue_directory_listing (new_directory_files); 113 new_dl = kqueue_directory_listing (new_directory_files);
110 114
111 /* Parse through the old list. */ 115 /* Parse through the old list. */
112 dl = old_dl; 116 dl = old_dl;
113 while (1) { 117 while (1) {
114 Lisp_Object old_entry, new_entry; 118 Lisp_Object old_entry, new_entry, dl1;
115 if (NILP (dl)) 119 if (NILP (dl))
116 break; 120 break;
117 121
118 /* We ignore "." and "..". */
119 old_entry = XCAR (dl);
120 if ((strcmp (".", SSDATA (XCAR (XCDR (old_entry)))) == 0) ||
121 (strcmp ("..", SSDATA (XCAR (XCDR (old_entry)))) == 0))
122 goto the_end;
123
124 /* Search for an entry with the same inode. */ 122 /* Search for an entry with the same inode. */
123 old_entry = XCAR (dl);
125 new_entry = Fassoc (XCAR (old_entry), new_dl); 124 new_entry = Fassoc (XCAR (old_entry), new_dl);
126 if (! NILP (Fequal (old_entry, new_entry))) { 125 if (! NILP (Fequal (old_entry, new_entry))) {
127 /* Both entries are identical. Nothing happens. */ 126 /* Both entries are identical. Nothing to do. */
128 new_dl = Fdelq (new_entry, new_dl); 127 new_dl = Fdelq (new_entry, new_dl);
129 goto the_end; 128 goto the_end;
130 } 129 }
@@ -158,9 +157,8 @@ kqueue_compare_dir_list
158 goto the_end; 157 goto the_end;
159 } 158 }
160 159
161 /* Search, whether there is a file with the same name (with 160 /* Search, whether there is a file with the same name but another
162 another inode). */ 161 inode. */
163 Lisp_Object dl1;
164 for (dl1 = new_dl; ! NILP (dl1); dl1 = XCDR (dl1)) { 162 for (dl1 = new_dl; ! NILP (dl1); dl1 = XCDR (dl1)) {
165 new_entry = XCAR (dl1); 163 new_entry = XCAR (dl1);
166 if (strcmp (SSDATA (XCAR (XCDR (old_entry))), 164 if (strcmp (SSDATA (XCAR (XCDR (old_entry))),
@@ -173,7 +171,7 @@ kqueue_compare_dir_list
173 } 171 }
174 } 172 }
175 173
176 /* A file has been deleted. */ 174 /* The file has been deleted. */
177 kqueue_generate_event 175 kqueue_generate_event
178 (XCAR (watch_object), Fcons (Qdelete, Qnil), 176 (XCAR (watch_object), Fcons (Qdelete, Qnil),
179 XCAR (XCDR (old_entry)), Qnil, callback); 177 XCAR (XCDR (old_entry)), Qnil, callback);
@@ -183,23 +181,15 @@ kqueue_compare_dir_list
183 old_dl = Fdelq (old_entry, old_dl); 181 old_dl = Fdelq (old_entry, old_dl);
184 } 182 }
185 183
186 /* Parse through the shortened new list. */ 184 /* Parse through the resulting new list. */
187 dl = new_dl; 185 dl = new_dl;
188 while (1) { 186 while (1) {
189 Lisp_Object new_entry; 187 Lisp_Object new_entry;
190 if (NILP (dl)) 188 if (NILP (dl))
191 break; 189 break;
192 190
193 /* We ignore "." and "..". */
194 new_entry = XCAR (dl);
195 if ((strcmp (".", SSDATA (XCAR (XCDR (new_entry)))) == 0) ||
196 (strcmp ("..", SSDATA (XCAR (XCDR (new_entry)))) == 0)) {
197 dl = XCDR (dl);
198 new_dl = Fdelq (new_entry, new_dl);
199 continue;
200 }
201
202 /* A new file has appeared. */ 191 /* A new file has appeared. */
192 new_entry = XCAR (dl);
203 kqueue_generate_event 193 kqueue_generate_event
204 (XCAR (watch_object), Fcons (Qcreate, Qnil), 194 (XCAR (watch_object), Fcons (Qcreate, Qnil),
205 XCAR (XCDR (new_entry)), Qnil, callback); 195 XCAR (XCDR (new_entry)), Qnil, callback);
@@ -222,21 +212,21 @@ kqueue_compare_dir_list
222 if (! NILP (new_dl)) 212 if (! NILP (new_dl))
223 report_file_error ("New list not empty", new_dl); 213 report_file_error ("New list not empty", new_dl);
224 214
225 /* Replace directory listing with the new one. */ 215 /* Replace old directory listing with the new one. */
226 XSETCDR (Fnthcdr (make_number (3), watch_object), 216 XSETCDR (Fnthcdr (make_number (3), watch_object),
227 Fcons (new_directory_files, Qnil)); 217 Fcons (new_directory_files, Qnil));
228 return; 218 return;
229} 219}
230 220
231/* This is the callback function for arriving input on kqueuefd. It 221/* This is the callback function for arriving input on kqueuefd. It
232 shall create a Lisp event, and put it into Emacs input queue. */ 222 shall create a Lisp event, and put it into the Emacs input queue. */
233static void 223static void
234kqueue_callback (int fd, void *data) 224kqueue_callback (int fd, void *data)
235{ 225{
236 for (;;) { 226 for (;;) {
237 struct kevent kev; 227 struct kevent kev;
238 static const struct timespec nullts = { 0, 0 }; 228 static const struct timespec nullts = { 0, 0 };
239 Lisp_Object monitor_object, watch_object, file, callback, dirp, actions; 229 Lisp_Object descriptor, watch_object, file, callback, actions;
240 230
241 /* Read one event. */ 231 /* Read one event. */
242 int ret = kevent (kqueuefd, NULL, 0, &kev, 1, &nullts); 232 int ret = kevent (kqueuefd, NULL, 0, &kev, 1, &nullts);
@@ -245,14 +235,13 @@ kqueue_callback (int fd, void *data)
245 return; 235 return;
246 } 236 }
247 237
248 /* Determine file name and callback function. */ 238 /* Determine descriptor, file name and callback function. */
249 monitor_object = make_number (kev.ident); 239 descriptor = make_number (kev.ident);
250 watch_object = assq_no_quit (monitor_object, watch_list); 240 watch_object = assq_no_quit (descriptor, watch_list);
251 241
252 if (CONSP (watch_object)) { 242 if (CONSP (watch_object)) {
253 file = XCAR (XCDR (watch_object)); 243 file = XCAR (XCDR (watch_object));
254 callback = Fnth (make_number (3), watch_object); 244 callback = Fnth (make_number (3), watch_object);
255 dirp = Fnth (make_number (4), watch_object);
256 } 245 }
257 else 246 else
258 continue; 247 continue;
@@ -262,7 +251,8 @@ kqueue_callback (int fd, void *data)
262 if (kev.fflags & NOTE_DELETE) 251 if (kev.fflags & NOTE_DELETE)
263 actions = Fcons (Qdelete, actions); 252 actions = Fcons (Qdelete, actions);
264 if (kev.fflags & NOTE_WRITE) { 253 if (kev.fflags & NOTE_WRITE) {
265 if (NILP (dirp)) 254 /* Check, whether this is a directory event. */
255 if (NILP (Fnth (make_number (4), watch_object)))
266 actions = Fcons (Qwrite, actions); 256 actions = Fcons (Qwrite, actions);
267 else 257 else
268 kqueue_compare_dir_list (watch_object); 258 kqueue_compare_dir_list (watch_object);
@@ -273,16 +263,19 @@ kqueue_callback (int fd, void *data)
273 actions = Fcons (Qattrib, actions); 263 actions = Fcons (Qattrib, actions);
274 if (kev.fflags & NOTE_LINK) 264 if (kev.fflags & NOTE_LINK)
275 actions = Fcons (Qlink, actions); 265 actions = Fcons (Qlink, actions);
266 /* It would be useful to know the target of the rename operation.
267 At this point, it is not possible. Happens only when the upper
268 directory is monitored. */
276 if (kev.fflags & NOTE_RENAME) 269 if (kev.fflags & NOTE_RENAME)
277 actions = Fcons (Qrename, actions); 270 actions = Fcons (Qrename, actions);
278 271
279 /* Construct an event. */ 272 /* Create the event. */
280 if (! NILP (actions)) 273 if (! NILP (actions))
281 kqueue_generate_event (monitor_object, actions, file, Qnil, callback); 274 kqueue_generate_event (descriptor, actions, file, Qnil, callback);
282 275
283 /* Cancel monitor if file or directory is deleted. */ 276 /* Cancel monitor if file or directory is deleted or renamed. */
284 if (kev.fflags & (NOTE_DELETE | NOTE_RENAME)) 277 if (kev.fflags & (NOTE_DELETE | NOTE_RENAME))
285 Fkqueue_rm_watch (monitor_object); 278 Fkqueue_rm_watch (descriptor);
286 } 279 }
287 return; 280 return;
288} 281}
@@ -316,13 +309,14 @@ DESCRIPTOR is the same object as the one returned by this function.
316ACTIONS is a list of events. 309ACTIONS is a list of events.
317 310
318FILE is the name of the file whose event is being reported. FILE1 311FILE is the name of the file whose event is being reported. FILE1
319will be reported only in case of the `rename' event. */) 312will be reported only in case of the `rename' event. This is possible
313only when the upper directory of the renamed file is watched. */)
320 (Lisp_Object file, Lisp_Object flags, Lisp_Object callback) 314 (Lisp_Object file, Lisp_Object flags, Lisp_Object callback)
321{ 315{
322 Lisp_Object watch_object, dir_list; 316 Lisp_Object watch_object, dir_list;
323 int fd; 317 int fd, oflags;
324 u_short fflags = 0; 318 u_short fflags = 0;
325 struct kevent ev; 319 struct kevent kev;
326 320
327 /* Check parameters. */ 321 /* Check parameters. */
328 CHECK_STRING (file); 322 CHECK_STRING (file);
@@ -350,7 +344,18 @@ will be reported only in case of the `rename' event. */)
350 344
351 /* Open file. */ 345 /* Open file. */
352 file = ENCODE_FILE (file); 346 file = ENCODE_FILE (file);
353 fd = emacs_open (SSDATA (file), O_RDONLY, 0); 347 oflags = O_NONBLOCK;
348#if O_EVTONLY
349 oflags |= O_EVTONLY;
350#else
351 oflags |= O_RDONLY;
352#endif
353#if O_SYMLINK
354 oflags |= O_SYMLINK;
355#else
356 oflags |= O_NOFOLLOW;
357#endif
358 fd = emacs_open (SSDATA (file), oflags, 0);
354 if (fd == -1) 359 if (fd == -1)
355 report_file_error ("File cannot be opened", file); 360 report_file_error ("File cannot be opened", file);
356 361
@@ -363,10 +368,10 @@ will be reported only in case of the `rename' event. */)
363 if (! NILP (Fmember (Qrename, flags))) fflags |= NOTE_RENAME; 368 if (! NILP (Fmember (Qrename, flags))) fflags |= NOTE_RENAME;
364 369
365 /* Register event. */ 370 /* Register event. */
366 EV_SET (&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, 371 EV_SET (&kev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
367 fflags, 0, NULL); 372 fflags, 0, NULL);
368 373
369 if (kevent (kqueuefd, &ev, 1, NULL, 0, NULL) < 0) { 374 if (kevent (kqueuefd, &kev, 1, NULL, 0, NULL) < 0) {
370 emacs_close (fd); 375 emacs_close (fd);
371 report_file_error ("Cannot watch file", file); 376 report_file_error ("Cannot watch file", file);
372 } 377 }