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