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