Merge from trunk.
[bpt/emacs.git] / src / w32notify.c
CommitLineData
6f011d81
EZ
1/* Filesystem notifications support for GNU Emacs on the Microsoft Windows API.
2 Copyright (C) 2012 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
c5c91b84
EZ
19/* Design overview:
20
21 For each watch request, we launch a separate worker thread. The
22 worker thread runs the watch_worker function, which issues an
23 asynchronous call to ReadDirectoryChangesW, and then waits for that
24 call to complete in SleepEx. Waiting in SleepEx puts the thread in
25 an alertable state, so it wakes up when either (a) the call to
26 ReadDirectoryChangesW completes, or (b) the main thread instructs
27 the worker thread to terminate by sending it an APC, see below.
28
29 When the ReadDirectoryChangesW call completes, its completion
30 routine watch_completion is automatically called. watch_completion
31 stashes the received file events in a buffer used to communicate
32 them to the main thread (using a critical section, so that several
33 threads could use the same buffer), posts a special message,
34 WM_EMACS_FILENOTIFY, to the Emacs's message queue, and returns.
35 That causes the SleepEx function call inside watch_worker to
36 return, and watch_worker then issues another call to
37 ReadDirectoryChangesW. (Except when it does not, see below.)
38
39 The WM_EMACS_FILENOTIFY message, posted to the message queue gets
40 dispatched to the main Emacs window procedure, which queues it for
41 processing by w32_read_socket. When w32_read_socket sees this
42 message, it accesses the buffer with file notifications (using a
43 critical section), extracts the information, converts it to a
44 series of FILE_NOTIFY_EVENT events, and stuffs them into the input
45 event queue to be processed by keyboard.c input machinery
46 (read_char via a call to kbd_buffer_get_event). When the
47 FILE_NOTIFY_EVENT event is processed by kbd_buffer_get_event, it is
48 converted to a Lispy event that can be bound to a command. The
49 default binding is w32notify-handle-event, defined on subr.el.
50
51 After w32_read_socket is done processing the notifications, it
52 resets a flag signaling to all watch worker threads that the
53 notifications buffer is available for more input.
54
55 When the watch is removed by a call to w32notify-rm-watch, the main
56 thread requests that the worker thread terminates by queuing an APC
57 for the worker thread. The APC specifies the watch_end function to
58 be called. watch_end calls CancelIo on the outstanding
59 ReadDirectoryChangesW call and closes the handle on which the
60 watched directory was open. When watch_end returns, the
61 watch_completion function is called one last time with the
62 ERROR_OPERATION_ABORTED status, which causes it to clean up and set
63 a flag telling watch_worker to exit without issuing another
d6de1760
EZ
64 ReadDirectoryChangesW call. The main thread waits for some time
65 for the worker thread to exit, and if it doesn't, terminates it
66 forcibly. */
c5c91b84 67
6f011d81
EZ
68#include <stddef.h>
69#include <errno.h>
70
71/* must include CRT headers *before* config.h */
72#include <config.h>
73
74#include <windows.h>
75
76#include "lisp.h"
77#include "w32term.h" /* for enter_crit/leave_crit and WM_EMACS_FILENOTIFY */
eb3abb61 78#include "w32common.h" /* for OS version data */
6f011d81
EZ
79#include "w32.h" /* for w32_strerror */
80#include "coding.h"
81#include "keyboard.h"
82#include "frame.h" /* needed by termhooks.h */
83#include "termhooks.h" /* for FILE_NOTIFY_EVENT */
84
85struct notification {
86 BYTE *buf; /* buffer for ReadDirectoryChangesW */
87 OVERLAPPED *io_info; /* the OVERLAPPED structure for async I/O */
88 BOOL subtree; /* whether to watch subdirectories */
89 DWORD filter; /* bit mask for events to watch */
90 char *watchee; /* the file we are interested in */
91 HANDLE dir; /* handle to the watched directory */
92 HANDLE thr; /* handle to the thread that watches */
93 int terminate; /* if non-zero, request for the thread to terminate */
94};
95
96/* FIXME: this needs to be changed to support more that one request at
97 a time. */
98static struct notification dirwatch;
99
100/* Used for communicating notifications to the main thread. */
101int notification_buffer_in_use;
102BYTE file_notifications[16384];
103DWORD notifications_size;
104HANDLE notifications_desc;
105
106static Lisp_Object Qfile_name, Qdirectory_name, Qattributes, Qsize;
107static Lisp_Object Qlast_write_time, Qlast_access_time, Qcreation_time;
108static Lisp_Object Qsecurity_desc, Qsubtree, watch_list;
109
6f011d81
EZ
110/* Signal to the main thread that we have file notifications for it to
111 process. */
112static void
113send_notifications (BYTE *info, DWORD info_size, HANDLE hdir, int *terminate)
114{
115 int done = 0;
116 FRAME_PTR f = SELECTED_FRAME ();
117
6f011d81
EZ
118
119 /* A single buffer is used to communicate all notifications to the
120 main thread. Since both the main thread and several watcher
121 threads could be active at the same time, we use a critical area
122 and an "in-use" flag to synchronize them. A watcher thread can
123 only put its notifications in the buffer if it acquires the
124 critical area and finds the "in-use" flag reset. The main thread
125 resets the flag after it is done processing notifications.
126
127 FIXME: is there a better way of dealing with this? */
128 while (!done && !*terminate)
129 {
130 enter_crit ();
131 if (!notification_buffer_in_use)
132 {
133 if (info_size)
134 memcpy (file_notifications, info, info_size);
135 notifications_size = info_size;
136 notifications_desc = hdir;
182b170f
EZ
137 if (FRAME_TERMCAP_P (f)
138 || (FRAME_W32_P (f)
139 /* If PostMessage fails, the message queue is full.
140 If that happens, the last thing they will worry
141 about is file notifications. So we effectively
142 discard the notification in that case. */
143 && PostMessage (FRAME_W32_WINDOW (f),
144 WM_EMACS_FILENOTIFY, 0, 0)))
6f011d81
EZ
145 notification_buffer_in_use = 1;
146 done = 1;
6f011d81
EZ
147 }
148 leave_crit ();
149 if (!done)
150 Sleep (5);
151 }
152}
153
154/* An APC routine to cancel outstanding directory watch. Invoked by
155 the main thread via QueueUserAPC. This is needed because only the
156 thread that issued the ReadDirectoryChangesW call can call CancelIo
157 to cancel that. (CancelIoEx is only available since Vista, so we
158 cannot use it on XP.) */
159VOID CALLBACK
160watch_end (ULONG_PTR arg)
161{
162 HANDLE hdir = (HANDLE)arg;
163
164 if (hdir && hdir != INVALID_HANDLE_VALUE)
165 {
166 CancelIo (hdir);
167 CloseHandle (hdir);
168 }
169}
170
171/* A completion routine (a.k.a. APC function) for handling events read
172 by ReadDirectoryChangesW. Called by the OS when the thread which
173 issued the asynchronous ReadDirectoryChangesW call is in the
174 "alertable state", i.e. waiting inside SleepEx call. */
175VOID CALLBACK
176watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info)
177{
178 struct notification *dirwatch;
179
180 /* Who knows what happened? Perhaps the OVERLAPPED structure was
181 freed by someone already? In any case, we cannot do anything
182 with this request, so just punt and skip it. FIXME: should we
183 raise the 'terminate' flag in this case? */
184 if (!io_info)
185 return;
186
187 /* We have a pointer to our dirwatch structure conveniently stashed
188 away in the hEvent member of the OVERLAPPED struct. According to
189 MSDN documentation of ReadDirectoryChangesW: "The hEvent member
190 of the OVERLAPPED structure is not used by the system, so you can
191 use it yourself." */
192 dirwatch = (struct notification *)io_info->hEvent;
193 if (status == ERROR_OPERATION_ABORTED)
194 {
195 /* We've been called because the main thread told us to issue
196 CancelIo on the directory we watch, and watch_end did so.
197 The directory handle is already closed. We should clean up
198 and exit, signalling to the thread worker routine not to
199 issue another call to ReadDirectoryChangesW. */
200 xfree (dirwatch->buf);
201 dirwatch->buf = NULL;
202 xfree (dirwatch->io_info);
203 dirwatch->io_info = NULL;
204 xfree (dirwatch->watchee);
205 dirwatch->watchee = NULL;
7d605354 206 dirwatch->dir = NULL;
6f011d81
EZ
207 dirwatch->terminate = 1;
208 }
209 else
210 {
6f011d81
EZ
211 /* Tell the main thread we have notifications for it. */
212 send_notifications (dirwatch->buf, bytes_ret, dirwatch->dir,
213 &dirwatch->terminate);
214 }
215}
216
217/* Worker routine for the watch thread. */
218static DWORD WINAPI
219watch_worker (LPVOID arg)
220{
221 struct notification *dirwatch = (struct notification *)arg;
222
223 do {
224 BOOL status;
225 DWORD sleep_result;
226 DWORD bytes_ret = 0;
227
228 if (dirwatch->dir)
229 {
230 status = ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf, 16384,
231 dirwatch->subtree, dirwatch->filter,
232 &bytes_ret,
233 dirwatch->io_info, watch_completion);
234 if (!status)
235 {
c5c91b84 236 DebPrint (("watch_worker, abnormal exit: %lu\n", GetLastError ()));
6f011d81
EZ
237 xfree (dirwatch->buf);
238 dirwatch->buf = NULL;
239 xfree (dirwatch->io_info);
240 dirwatch->io_info = NULL;
241 CloseHandle (dirwatch->dir);
242 dirwatch->dir = NULL;
243 xfree (dirwatch->watchee);
244 dirwatch->watchee = NULL;
245 return 1;
246 }
247 }
248 /* Sleep indefinitely until awoken by the I/O completion, which
249 could be either a change notification or a cancellation of the
250 watch. */
251 sleep_result = SleepEx (INFINITE, TRUE);
6f011d81
EZ
252 } while (!dirwatch->terminate);
253
6f011d81
EZ
254 return 0;
255}
256
257/* Launch a thread to watch changes to FILE in a directory open on
258 handle HDIR. */
259static int
260start_watching (const char *file, HANDLE hdir, BOOL subdirs, DWORD flags)
261{
262 dirwatch.buf = xmalloc (16384);
263 dirwatch.io_info = xzalloc (sizeof(OVERLAPPED));
264 /* Stash a pointer to dirwatch structure for use by the completion
265 routine. According to MSDN documentation of ReadDirectoryChangesW:
266 "The hEvent member of the OVERLAPPED structure is not used by the
267 system, so you can use it yourself." */
268 dirwatch.io_info->hEvent = &dirwatch;
269 dirwatch.subtree = subdirs;
270 dirwatch.filter = flags;
271 dirwatch.watchee = xstrdup (file);
272 dirwatch.terminate = 0;
273 dirwatch.dir = hdir;
274
275 /* See w32proc.c where it calls CreateThread for the story behind
276 the 2nd and 5th argument in the call to CreateThread. */
277 dirwatch.thr = CreateThread (NULL, 64 * 1024, watch_worker,
278 (void *)&dirwatch, 0x00010000, NULL);
279
280 if (!dirwatch.thr)
281 {
282 dirwatch.terminate = 1;
283 xfree (dirwatch.buf);
284 dirwatch.buf = NULL;
285 xfree (dirwatch.io_info);
286 dirwatch.io_info = NULL;
287 xfree (dirwatch.watchee);
288 dirwatch.watchee = NULL;
7d605354 289 dirwatch.dir = NULL;
6f011d81
EZ
290 return -1;
291 }
292 return 0;
293}
294
295/* Called from the main thread to start watching FILE in PARENT_DIR,
296 subject to FLAGS. If SUBDIRS is TRUE, watch the subdirectories of
297 PARENT_DIR as well. Value is the handle on which the directory is
298 open. */
299static HANDLE *
300add_watch (const char *parent_dir, const char *file, BOOL subdirs, DWORD flags)
301{
302 HANDLE hdir;
303
304 if (!file || !*file)
305 return NULL;
306
307 hdir = CreateFile (parent_dir,
308 FILE_LIST_DIRECTORY,
309 /* FILE_SHARE_DELETE doesn't preclude other
310 processes from deleting files inside
311 parent_dir. */
312 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
313 NULL, OPEN_EXISTING,
314 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
315 NULL);
316 if (hdir == INVALID_HANDLE_VALUE)
317 return NULL;
318
319 if (start_watching (file, hdir, subdirs, flags) == 0)
320 return hdir;
321
322 CloseHandle (hdir);
323 return NULL;
324}
325
326/* Stop watching a directory specified by its handle HDIR. */
327static int
328remove_watch (HANDLE hdir)
329{
330 if (hdir == dirwatch.dir)
331 {
332 int i;
333 BOOL status;
334 DWORD exit_code, err;
335
336 /* Only the thread that issued the outstanding I/O call can call
337 CancelIo on it. (CancelIoEx is available only since Vista.)
338 So we need to queue an APC for the worker thread telling it
339 to terminate. */
340 if (!QueueUserAPC (watch_end, dirwatch.thr, (ULONG_PTR)dirwatch.dir))
341 DebPrint (("QueueUserAPC failed (%lu)!\n", GetLastError ()));
342 /* We also set the terminate flag, for when the thread is
343 waiting on the critical section that never gets acquired.
344 FIXME: is there a cleaner method? Using SleepEx there is a
345 no-no, as that will lead to recursive APC invocations and
346 stack overflow. */
347 dirwatch.terminate = 1;
348 /* Wait for the thread to exit. FIXME: is there a better method
349 that is not overly complex? */
350 for (i = 0; i < 50; i++)
351 {
352 if (!((status = GetExitCodeThread (dirwatch.thr, &exit_code))
353 && exit_code == STILL_ACTIVE))
354 break;
355 Sleep (10);
356 }
357 if ((status == FALSE && (err = GetLastError ()) == ERROR_INVALID_HANDLE)
358 || exit_code == STILL_ACTIVE)
359 {
360 if (!(status == FALSE && err == ERROR_INVALID_HANDLE))
361 TerminateThread (dirwatch.thr, 0);
362 }
363
364 /* Clean up. */
365 if (dirwatch.thr)
366 {
367 CloseHandle (dirwatch.thr);
368 dirwatch.thr = NULL;
369 }
370 return 0;
371 }
372 else if (!dirwatch.dir)
373 {
374 DebPrint (("Directory handle already closed!\n"));
375 return 0;
376 }
377 else
378 {
379 DebPrint (("Unknown directory handle!\n"));
380 return -1;
381 }
382}
383
384static DWORD
385filter_list_to_flags (Lisp_Object filter_list)
386{
387 DWORD flags = 0;
388
389 if (NILP (filter_list))
390 return flags;
391
392 if (!NILP (Fmember (Qfile_name, filter_list)))
393 flags |= FILE_NOTIFY_CHANGE_FILE_NAME;
394 if (!NILP (Fmember (Qdirectory_name, filter_list)))
395 flags |= FILE_NOTIFY_CHANGE_DIR_NAME;
396 if (!NILP (Fmember (Qattributes, filter_list)))
397 flags |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
398 if (!NILP (Fmember (Qsize, filter_list)))
399 flags |= FILE_NOTIFY_CHANGE_SIZE;
400 if (!NILP (Fmember (Qlast_write_time, filter_list)))
401 flags |= FILE_NOTIFY_CHANGE_LAST_WRITE;
402 if (!NILP (Fmember (Qlast_access_time, filter_list)))
403 flags |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
404 if (!NILP (Fmember (Qcreation_time, filter_list)))
405 flags |= FILE_NOTIFY_CHANGE_CREATION;
406 if (!NILP (Fmember (Qsecurity_desc, filter_list)))
407 flags |= FILE_NOTIFY_CHANGE_SECURITY;
408
409 return flags;
410}
411
412DEFUN ("w32notify-add-watch", Fw32notify_add_watch,
413 Sw32notify_add_watch, 3, 3, 0,
414 doc: /* Add a watch for filesystem events pertaining to FILE.
415
416This arranges for filesystem events pertaining to FILE to be reported
417to Emacs. Use `w32notify-rm-watch' to cancel the watch.
418
419Value is a descriptor for the added watch, or nil if the file
420cannot be watched.
421
422FILTER is a list of conditions for reporting an event. It can include
423the following symbols:
424
425 'file-name' -- report file creation, deletion, or renaming
426 'directory-name' -- report directory creation, deletion, or renaming
427 'attributes' -- report changes in attributes
428 'size' -- report changes in file-size
429 'last-write-time' -- report changes in last-write time
430 'last-access-time' -- report changes in last-access time
431 'creation-time' -- report changes in creation time
432 'security-desc' -- report changes in security descriptor
433
434If FILE is a directory, and FILTER includes 'subtree', then all the
435subdirectories will also be watched and changes in them reported.
436
437When any event happens that satisfies the conditions specified by
438FILTER, Emacs will call the CALLBACK function passing it a single
439argument EVENT, which is of the form
440
441 (DESCRIPTOR ACTION FILE)
442
443DESCRIPTOR is the same object as the one returned by this function.
444ACTION is the description of the event. It could be any one of the
445following:
446
447 'added' -- FILE was added
448 'removed' -- FILE was deleted
449 'modified' -- FILE's contents or its attributes were modified
450 'renamed-from' -- a file was renamed whose old name was FILE
451 'renamed-to' -- a file was renamed and its new name is FILE
452
453FILE is the name of the file whose event is being reported. */)
454 (Lisp_Object file, Lisp_Object filter, Lisp_Object callback)
455{
456 Lisp_Object encoded_file, watch_object, watch_descriptor;
457 char parent_dir[MAX_PATH], *basename;
458 size_t fn_len;
459 HANDLE hdir;
460 DWORD flags;
461 BOOL subdirs = FALSE;
462 Lisp_Object lisp_errstr;
463 char *errstr;
464
465 CHECK_LIST (filter);
466
467 /* The underlying features are available only since XP. */
468 if (os_subtype == OS_9X
469 || (w32_major_version == 5 && w32_major_version < 1))
470 {
471 errno = ENOSYS;
472 report_file_error ("Watching filesystem events is not supported",
473 Qnil);
474 }
475
7d605354
EZ
476 if (dirwatch.dir)
477 error ("File watch already active");
478
6f011d81
EZ
479 /* We needa full absolute file name of FILE, and we need to remove
480 any trailing slashes from it, so that GetFullPathName below gets
481 the basename part correctly. */
482 file = Fdirectory_file_name (Fexpand_file_name (file, Qnil));
483 encoded_file = ENCODE_FILE (file);
484
485 fn_len = GetFullPathName (SDATA (encoded_file), MAX_PATH, parent_dir,
486 &basename);
487 if (!fn_len)
488 {
489 errstr = w32_strerror (0);
490 errno = EINVAL;
491 if (!NILP (Vlocale_coding_system))
492 lisp_errstr
493 = code_convert_string_norecord (build_unibyte_string (errstr),
494 Vlocale_coding_system, 0);
495 else
496 lisp_errstr = build_string (errstr);
497 report_file_error ("GetFullPathName failed",
498 Fcons (lisp_errstr, Fcons (file, Qnil)));
499 }
500 /* We need the parent directory without the slash that follows it.
501 If BASENAME is NULL, the argument was the root directory on its
502 drive. */
503 if (basename)
504 basename[-1] = '\0';
505 else
506 subdirs = TRUE;
507
508 if (!NILP (Fmember (Qsubtree, filter)))
509 subdirs = TRUE;
510
511 flags = filter_list_to_flags (filter);
512
513 hdir = add_watch (parent_dir, basename, subdirs, flags);
514 if (!hdir)
515 {
516 DWORD err = GetLastError ();
517
518 errno = EINVAL;
519 if (err)
520 {
521 errstr = w32_strerror (err);
522 if (!NILP (Vlocale_coding_system))
523 lisp_errstr
524 = code_convert_string_norecord (build_unibyte_string (errstr),
525 Vlocale_coding_system, 0);
526 else
527 lisp_errstr = build_string (errstr);
528 report_file_error ("Cannot watch file",
529 Fcons (lisp_errstr, Fcons (file, Qnil)));
530 }
531 else
532 report_file_error ("Cannot watch file", Fcons (file, Qnil));
533 }
534 /* Store watch object in watch list. */
535 watch_descriptor = make_number (hdir);
536 watch_object = Fcons (watch_descriptor, callback);
537 watch_list = Fcons (watch_object, watch_list);
538
539 return watch_descriptor;
540}
541
542DEFUN ("w32notify-rm-watch", Fw32notify_rm_watch,
543 Sw32notify_rm_watch, 1, 1, 0,
544 doc: /* Remove an existing watch specified by its WATCH-DESCRIPTOR.
545
546WATCH-DESCRIPTOR should be an object returned by `w32notify-add-watch'. */)
547 (Lisp_Object watch_descriptor)
548{
549 Lisp_Object watch_object;
550 HANDLE hdir = (HANDLE)XINT (watch_descriptor);
551
552 if (remove_watch (hdir) == -1)
553 report_file_error ("Could not remove watch", Fcons (watch_descriptor,
554 Qnil));
555
556 /* Remove watch descriptor from watch list. */
557 watch_object = Fassoc (watch_descriptor, watch_list);
558 if (!NILP (watch_object))
559 watch_list = Fdelete (watch_object, watch_list);
560
561 return Qnil;
562}
563
564Lisp_Object
565get_watch_object (Lisp_Object desc)
566{
567 return Fassoc (desc, watch_list);
568}
569
570void
571syms_of_w32notify (void)
572{
573 DEFSYM (Qfile_name, "file-name");
574 DEFSYM (Qdirectory_name, "directory-name");
575 DEFSYM (Qattributes, "attributes");
576 DEFSYM (Qsize, "size");
577 DEFSYM (Qlast_write_time, "last-write-time");
578 DEFSYM (Qlast_access_time, "last-access-time");
579 DEFSYM (Qcreation_time, "creation-time");
580 DEFSYM (Qsecurity_desc, "security-desc");
581 DEFSYM (Qsubtree, "subtree");
582
583 defsubr (&Sw32notify_add_watch);
584 defsubr (&Sw32notify_rm_watch);
585
586 staticpro (&watch_list);
587
588 Fprovide (intern_c_string ("w32notify"), Qnil);
589}