aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/w32inevt.c115
-rw-r--r--src/w32notify.c320
-rw-r--r--src/w32term.c116
-rw-r--r--src/w32term.h16
-rw-r--r--src/w32xfns.c28
5 files changed, 349 insertions, 246 deletions
diff --git a/src/w32inevt.c b/src/w32inevt.c
index a33f82dc7db..2269d318051 100644
--- a/src/w32inevt.c
+++ b/src/w32inevt.c
@@ -620,70 +620,89 @@ maybe_generate_resize_event (void)
620int 620int
621handle_file_notifications (struct input_event *hold_quit) 621handle_file_notifications (struct input_event *hold_quit)
622{ 622{
623 BYTE *p = file_notifications; 623 struct notifications_set *ns = NULL;
624 FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p;
625 const DWORD min_size
626 = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t);
627 struct input_event inev;
628 int nevents = 0; 624 int nevents = 0;
625 int done = 0;
629 626
630 /* We cannot process notification before Emacs is fully initialized, 627 /* We cannot process notification before Emacs is fully initialized,
631 since we need the UTF-16LE coding-system to be set up. */ 628 since we need the UTF-16LE coding-system to be set up. */
632 if (!initialized) 629 if (!initialized)
633 { 630 {
634 notification_buffer_in_use = 0;
635 return nevents; 631 return nevents;
636 } 632 }
637 633
638 enter_crit (); 634 while (!done)
639 if (notification_buffer_in_use)
640 { 635 {
641 DWORD info_size = notifications_size; 636 ns = NULL;
642 Lisp_Object cs = Qutf_16le;
643 Lisp_Object obj = w32_get_watch_object (notifications_desc);
644
645 /* notifications_size could be zero when the buffer of
646 notifications overflowed on the OS level, or when the
647 directory being watched was itself deleted. Do nothing in
648 that case. */
649 if (info_size
650 && !NILP (obj) && CONSP (obj))
651 {
652 Lisp_Object callback = XCDR (obj);
653 637
654 EVENT_INIT (inev); 638 /* Find out if there is a record available in the linked list of
639 notifications sets. If so, unlink te set from the linked list.
640 Use the critical section. */
641 enter_crit ();
642 if (notifications_set_head->next != notifications_set_head)
643 {
644 ns = notifications_set_head->next;
645 ns->prev->next = ns->next;
646 ns->next->prev = ns->prev;
647 }
648 else
649 done = 1;
650 leave_crit();
655 651
656 while (info_size >= min_size) 652 if (ns)
653 {
654 BYTE *p = ns->notifications;
655 FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p;
656 const DWORD min_size
657 = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t);
658 struct input_event inev;
659 DWORD info_size = ns->size;
660 Lisp_Object cs = Qutf_16le;
661 Lisp_Object obj = w32_get_watch_object (ns->desc);
662
663 /* notifications size could be zero when the buffer of
664 notifications overflowed on the OS level, or when the
665 directory being watched was itself deleted. Do nothing in
666 that case. */
667 if (info_size
668 && !NILP (obj) && CONSP (obj))
657 { 669 {
658 Lisp_Object utf_16_fn 670 Lisp_Object callback = XCDR (obj);
659 = make_unibyte_string ((char *)fni->FileName, 671
660 fni->FileNameLength); 672 EVENT_INIT (inev);
661 /* Note: mule-conf is preloaded, so utf-16le must 673
662 already be defined at this point. */ 674 while (info_size >= min_size)
663 Lisp_Object fname 675 {
664 = code_convert_string_norecord (utf_16_fn, cs, 0); 676 Lisp_Object utf_16_fn
665 Lisp_Object action = lispy_file_action (fni->Action); 677 = make_unibyte_string ((char *)fni->FileName,
666 678 fni->FileNameLength);
667 inev.kind = FILE_NOTIFY_EVENT; 679 /* Note: mule-conf is preloaded, so utf-16le must
668 inev.timestamp = GetTickCount (); 680 already be defined at this point. */
669 inev.modifiers = 0; 681 Lisp_Object fname
670 inev.frame_or_window = callback; 682 = code_convert_string_norecord (utf_16_fn, cs, 0);
671 inev.arg = Fcons (action, fname); 683 Lisp_Object action = lispy_file_action (fni->Action);
672 inev.arg = list3 (make_pointer_integer (notifications_desc), 684
673 action, fname); 685 inev.kind = FILE_NOTIFY_EVENT;
674 kbd_buffer_store_event_hold (&inev, hold_quit); 686 inev.timestamp = GetTickCount ();
675 nevents++; 687 inev.modifiers = 0;
676 688 inev.frame_or_window = callback;
677 if (!fni->NextEntryOffset) 689 inev.arg = Fcons (action, fname);
678 break; 690 inev.arg = list3 (make_pointer_integer (ns->desc),
679 p += fni->NextEntryOffset; 691 action, fname);
680 fni = (PFILE_NOTIFY_INFORMATION)p; 692 kbd_buffer_store_event_hold (&inev, hold_quit);
681 info_size -= fni->NextEntryOffset; 693 nevents++;
694 if (!fni->NextEntryOffset)
695 break;
696 p += fni->NextEntryOffset;
697 fni = (PFILE_NOTIFY_INFORMATION)p;
698 info_size -= fni->NextEntryOffset;
699 }
682 } 700 }
701 /* Free this notification set. */
702 free (ns->notifications);
703 free (ns);
683 } 704 }
684 notification_buffer_in_use = 0;
685 } 705 }
686 leave_crit ();
687 return nevents; 706 return nevents;
688} 707}
689#else /* !HAVE_W32NOTIFY */ 708#else /* !HAVE_W32NOTIFY */
diff --git a/src/w32notify.c b/src/w32notify.c
index 586c2062f62..54d9bcc189a 100644
--- a/src/w32notify.c
+++ b/src/w32notify.c
@@ -22,27 +22,30 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22 22
23 For each watch request, we launch a separate worker thread. The 23 For each watch request, we launch a separate worker thread. The
24 worker thread runs the watch_worker function, which issues an 24 worker thread runs the watch_worker function, which issues an
25 asynchronous call to ReadDirectoryChangesW, and then waits in 25 asynchronous call to ReadDirectoryChangesW, and then calls
26 SleepEx for that call to complete. Waiting in SleepEx puts the 26 WaitForSingleObjectEx to wait that an event be signaled
27 thread in an "alertable" state, so it wakes up when either (a) the 27 to terminate the thread.
28 call to ReadDirectoryChangesW completes, or (b) the main thread 28 Waiting with WaitForSingleObjectEx puts the thread in an
29 instructs the worker thread to terminate by sending it an APC, see 29 "alertable" state, so it wakes up when either (a) the call to
30 below. 30 ReadDirectoryChangesW completes, or (b) the main thread instructs
31 the worker thread to terminate by signaling an event, see below.
31 32
32 When the ReadDirectoryChangesW call completes, its completion 33 When the ReadDirectoryChangesW call completes, its completion
33 routine watch_completion is automatically called. watch_completion 34 routine watch_completion is automatically called. watch_completion
34 stashes the received file events in a buffer used to communicate 35 stashes the received file events in a linked list used to
35 them to the main thread (using a critical section, so that several 36 communicate them to the main thread (using a critical section, so
36 threads could use the same buffer), posts a special message, 37 that several threads could alter the same linked list), posts a
37 WM_EMACS_FILENOTIFY, to the Emacs's message queue, and returns. 38 special message, WM_EMACS_FILENOTIFY, to the Emacs's message queue,
38 That causes the SleepEx function call inside watch_worker to 39 and returns. That causes the WaitForSingleObjectEx function call
39 return, and watch_worker then issues another call to 40 inside watch_worker to return, but the thread won't terminate until
40 ReadDirectoryChangesW. (Except when it does not, see below.) 41 the event telling to do so will be signaled. The completion
42 routine issued another call to ReadDirectoryChangesW as quickly as
43 possible. (Except when it does not, see below.)
41 44
42 In a GUI session, the WM_EMACS_FILENOTIFY message posted to the 45 In a GUI session, the WM_EMACS_FILENOTIFY message posted to the
43 message queue gets dispatched to the main Emacs window procedure, 46 message queue gets dispatched to the main Emacs window procedure,
44 which queues it for processing by w32_read_socket. When 47 which queues it for processing by w32_read_socket. When
45 w32_read_socket sees this message, it accesses the buffer with file 48 w32_read_socket sees this message, it accesses the linked list with file
46 notifications (using a critical section), extracts the information, 49 notifications (using a critical section), extracts the information,
47 converts it to a series of FILE_NOTIFY_EVENT events, and stuffs 50 converts it to a series of FILE_NOTIFY_EVENT events, and stuffs
48 them into the input event queue to be processed by keyboard.c input 51 them into the input event queue to be processed by keyboard.c input
@@ -53,7 +56,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
53 procedures in console programs. That message wakes up 56 procedures in console programs. That message wakes up
54 MsgWaitForMultipleObjects inside sys_select, which then signals to 57 MsgWaitForMultipleObjects inside sys_select, which then signals to
55 its caller that some keyboard input is available. This causes 58 its caller that some keyboard input is available. This causes
56 w32_console_read_socket to be called, which accesses the buffer 59 w32_console_read_socket to be called, which accesses the linked list
57 with file notifications and stuffs them into the input event queue 60 with file notifications and stuffs them into the input event queue
58 for keyboard.c to process. 61 for keyboard.c to process.
59 62
@@ -62,24 +65,21 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
62 bound to a command. The default binding is file-notify-handle-event, 65 bound to a command. The default binding is file-notify-handle-event,
63 defined on subr.el. 66 defined on subr.el.
64 67
65 After w32_read_socket or w32_console_read_socket are done 68 Routines w32_read_socket or w32_console_read_socket process notifications
66 processing the notifications, they reset a flag signaling to all 69 sets as long as some are available.
67 watch worker threads that the notifications buffer is available for
68 more input.
69 70
70 When the watch is removed by a call to w32notify-rm-watch, the main 71 When the watch is removed by a call to w32notify-rm-watch, the main
71 thread requests that the worker thread terminates by queuing an APC 72 thread requests that the worker thread terminates by signaling the
72 for the worker thread. The APC specifies the watch_end function to 73 appropriate event and queuing an APC for the worker thread. The
73 be called. watch_end calls CancelIo on the outstanding 74 APC specifies the watch_end function to be called. watch_end calls
74 ReadDirectoryChangesW call and closes the handle on which the 75 CancelIo on the outstanding ReadDirectoryChangesW call. When
75 watched directory was open. When watch_end returns, the 76 watch_end returns, the watch_completion function is called one last
76 watch_completion function is called one last time with the 77 time with the ERROR_OPERATION_ABORTED status, which causes it to
77 ERROR_OPERATION_ABORTED status, which causes it to clean up and set 78 clean up and set a flag telling watch_worker to exit without
78 a flag telling watch_worker to exit without issuing another 79 issuing another ReadDirectoryChangesW call. Since watch_worker is
79 ReadDirectoryChangesW call. Since watch_worker is the thread 80 the thread procedure of the worker thread, exiting it causes the
80 procedure of the worker thread, exiting it causes the thread to 81 thread to exit. The main thread waits for some time for the worker
81 exit. The main thread waits for some time for the worker thread to 82 thread to exit, and if it doesn't, terminates it forcibly. */
82 exit, and if it doesn't, terminates it forcibly. */
83 83
84#include <stddef.h> 84#include <stddef.h>
85#include <errno.h> 85#include <errno.h>
@@ -98,6 +98,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
98#include "frame.h" /* needed by termhooks.h */ 98#include "frame.h" /* needed by termhooks.h */
99#include "termhooks.h" /* for FILE_NOTIFY_EVENT */ 99#include "termhooks.h" /* for FILE_NOTIFY_EVENT */
100 100
101#define DIRWATCH_BUFFER_SIZE 16384
101#define DIRWATCH_SIGNATURE 0x01233210 102#define DIRWATCH_SIGNATURE 0x01233210
102 103
103struct notification { 104struct notification {
@@ -108,73 +109,52 @@ struct notification {
108 char *watchee; /* the file we are interested in, UTF-8 encoded */ 109 char *watchee; /* the file we are interested in, UTF-8 encoded */
109 HANDLE dir; /* handle to the watched directory */ 110 HANDLE dir; /* handle to the watched directory */
110 HANDLE thr; /* handle to the thread that watches */ 111 HANDLE thr; /* handle to the thread that watches */
111 volatile int terminate; /* if non-zero, request for the thread to terminate */ 112 HANDLE terminate; /* event signaling the thread to terminate */
112 unsigned signature; 113 unsigned signature;
113}; 114};
114 115
115/* Used for communicating notifications to the main thread. */ 116/* Used for communicating notifications to the main thread. */
116volatile int notification_buffer_in_use; 117struct notifications_set *notifications_set_head;
117BYTE file_notifications[16384];
118DWORD notifications_size;
119void *notifications_desc;
120 118
121static Lisp_Object watch_list; 119static Lisp_Object watch_list;
122 120
123/* Signal to the main thread that we have file notifications for it to 121/* Signal to the main thread that we have file notifications for it to
124 process. */ 122 process. */
125static void 123static void
126send_notifications (BYTE *info, DWORD info_size, void *desc, 124send_notifications (struct notifications_set *ns)
127 volatile int *terminate)
128{ 125{
129 int done = 0; 126 int done = 0;
130 struct frame *f = SELECTED_FRAME (); 127 struct frame *f = SELECTED_FRAME ();
131 128
132 /* A single buffer is used to communicate all notifications to the 129 /* We add the current notification set to the linked list. Use the
133 main thread. Since both the main thread and several watcher 130 critical section to make sure only one thread will access the
134 threads could be active at the same time, we use a critical area 131 linked list. */
135 and an "in-use" flag to synchronize them. A watcher thread can
136 only put its notifications in the buffer if it acquires the
137 critical area and finds the "in-use" flag reset. The main thread
138 resets the flag after it is done processing notifications.
139
140 FIXME: is there a better way of dealing with this? */
141 while (!done && !*terminate)
142 {
143 enter_crit (); 132 enter_crit ();
144 if (!notification_buffer_in_use) 133 ns->next = notifications_set_head;
145 { 134 ns->prev = notifications_set_head->prev;
146 if (info_size) 135 ns->prev->next = ns;
147 memcpy (file_notifications, info, 136 notifications_set_head->prev = ns;
148 min (info_size, sizeof (file_notifications))); 137 leave_crit();
149 notifications_size = min (info_size, sizeof (file_notifications)); 138
150 notifications_desc = desc; 139 /* If PostMessage fails, the message queue is full. If that
151 /* If PostMessage fails, the message queue is full. If that 140 happens, the last thing they will worry about is file
152 happens, the last thing they will worry about is file 141 notifications. So we effectively discard the notification in
153 notifications. So we effectively discard the 142 that case. */
154 notification in that case. */ 143 if (FRAME_TERMCAP_P (f))
155 if ((FRAME_TERMCAP_P (f) 144 /* We send the message to the main (a.k.a. "Lisp") thread, where
156 /* We send the message to the main (a.k.a. "Lisp") 145 it will wake up MsgWaitForMultipleObjects inside sys_select,
157 thread, where it will wake up MsgWaitForMultipleObjects 146 causing it to report that there's some keyboard input
158 inside sys_select, causing it to report that there's 147 available. This will in turn cause w32_console_read_socket to
159 some keyboard input available. This will in turn cause 148 be called, which will pick up the file notifications. */
160 w32_console_read_socket to be called, which will pick 149 PostThreadMessage (dwMainThreadId, WM_EMACS_FILENOTIFY, 0, 0);
161 up the file notifications. */ 150 else if (FRAME_W32_P (f))
162 && PostThreadMessage (dwMainThreadId, WM_EMACS_FILENOTIFY, 0, 0)) 151 PostMessage (FRAME_W32_WINDOW (f),
163 || (FRAME_W32_P (f) 152 WM_EMACS_FILENOTIFY, 0, 0);
164 && PostMessage (FRAME_W32_WINDOW (f), 153 /* When we are running in batch mode, there's no one to send a
165 WM_EMACS_FILENOTIFY, 0, 0)) 154 message, so we just signal the data is available and hope
166 /* When we are running in batch mode, there's no one to 155 sys_select will be called soon and will read the data. */
167 send a message, so we just signal the data is 156 else if (FRAME_INITIAL_P (f) && noninteractive)
168 available and hope sys_select will be called soon and 157 ;
169 will read the data. */
170 || (FRAME_INITIAL_P (f) && noninteractive))
171 notification_buffer_in_use = 1;
172 done = 1;
173 }
174 leave_crit ();
175 if (!done)
176 Sleep (5);
177 }
178} 158}
179 159
180/* An APC routine to cancel outstanding directory watch. Invoked by 160/* An APC routine to cancel outstanding directory watch. Invoked by
@@ -188,10 +168,7 @@ watch_end (ULONG_PTR arg)
188 HANDLE hdir = (HANDLE)arg; 168 HANDLE hdir = (HANDLE)arg;
189 169
190 if (hdir && hdir != INVALID_HANDLE_VALUE) 170 if (hdir && hdir != INVALID_HANDLE_VALUE)
191 { 171 CancelIo (hdir);
192 CancelIo (hdir);
193 CloseHandle (hdir);
194 }
195} 172}
196 173
197/* A completion routine (a.k.a. "APC function") for handling events 174/* A completion routine (a.k.a. "APC function") for handling events
@@ -202,13 +179,19 @@ VOID CALLBACK
202watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info) 179watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info)
203{ 180{
204 struct notification *dirwatch; 181 struct notification *dirwatch;
182 DWORD _bytes;
183 struct notifications_set *ns = NULL;
184 BOOL terminate = FALSE;
205 185
206 /* Who knows what happened? Perhaps the OVERLAPPED structure was 186 /* Who knows what happened? Perhaps the OVERLAPPED structure was
207 freed by someone already? In any case, we cannot do anything 187 freed by someone already? In any case, we cannot do anything
208 with this request, so just punt and skip it. FIXME: should we 188 with this request, so just punt and skip it. FIXME: should we
209 raise the 'terminate' flag in this case? */ 189 raise the 'terminate' flag in this case? */
210 if (!io_info) 190 if (!io_info)
211 return; 191 {
192 DebPrint(("watch_completion: io_info is null.\n"));
193 return;
194 }
212 195
213 /* We have a pointer to our dirwatch structure conveniently stashed 196 /* We have a pointer to our dirwatch structure conveniently stashed
214 away in the hEvent member of the OVERLAPPED struct. According to 197 away in the hEvent member of the OVERLAPPED struct. According to
@@ -216,26 +199,69 @@ watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info)
216 of the OVERLAPPED structure is not used by the system, so you can 199 of the OVERLAPPED structure is not used by the system, so you can
217 use it yourself." */ 200 use it yourself." */
218 dirwatch = (struct notification *)io_info->hEvent; 201 dirwatch = (struct notification *)io_info->hEvent;
202
219 if (status == ERROR_OPERATION_ABORTED) 203 if (status == ERROR_OPERATION_ABORTED)
220 { 204 {
221 /* We've been called because the main thread told us to issue 205 /* We've been called because the main thread told us to issue
222 CancelIo on the directory we watch, and watch_end did so. 206 CancelIo on the directory we watch, and watch_end did so.
223 The directory handle is already closed. We should clean up 207 We must exit, without issuing another call to
224 and exit, signaling to the thread worker routine not to 208 ReadDirectoryChangesW. */
225 issue another call to ReadDirectoryChangesW. Note that we 209 return;
226 don't free the dirwatch object itself nor the memory consumed
227 by its buffers; this is done by the main thread in
228 remove_watch. Calling malloc/free from a thread other than
229 the main thread is a no-no. */
230 dirwatch->dir = NULL;
231 dirwatch->terminate = 1;
232 } 210 }
233 else 211
212 /* We allocate a new set of notifications to be linked to the linked
213 list of notifications set. This will be processed by Emacs event
214 loop in the main thread. We need to duplicate the notifications
215 buffer, but not the dirwatch structure. */
216
217 /* Implementation note: In general, allocating memory in non-main
218 threads is a no-no in Emacs. We certainly cannot call xmalloc
219 and friends, because it can longjmp when allocation fails, which
220 will crash Emacs because the jmp_buf is set up to a location on
221 the main thread's stack. However, we can call 'malloc' directly,
222 since that is redirected to HeapAlloc that uses our private heap,
223 see w32heap.c, and that is thread-safe. */
224 ns = malloc (sizeof(struct notifications_set));
225 if (ns)
226 {
227 memset (ns, 0, sizeof(struct notifications_set));
228 ns->notifications = malloc (bytes_ret);
229 if (ns->notifications)
230 {
231 memcpy (ns->notifications, dirwatch->buf, bytes_ret);
232 ns->size = bytes_ret;
233 ns->desc = dirwatch;
234 }
235 else
236 {
237 free (ns);
238 ns = NULL;
239 }
240 }
241 if (ns == NULL)
242 DebPrint(("Out of memory. Notifications lost."));
243
244 /* Calling ReadDirectoryChangesW quickly to watch again for new
245 notifications. */
246 if (!ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf,
247 DIRWATCH_BUFFER_SIZE, dirwatch->subtree,
248 dirwatch->filter, &_bytes, dirwatch->io_info,
249 watch_completion))
234 { 250 {
235 /* Tell the main thread we have notifications for it. */ 251 DebPrint (("ReadDirectoryChangesW error: %lu\n", GetLastError ()));
236 send_notifications (dirwatch->buf, bytes_ret, dirwatch, 252 /* If this call fails, it means that the directory is not
237 &dirwatch->terminate); 253 watchable any more. We need to terminate the worker thread.
254 Still, we will wait until the current notifications have been
255 sent to the main thread. */
256 terminate = TRUE;
238 } 257 }
258
259 if (ns)
260 send_notifications(ns);
261
262 /* If we were asked to terminate the thread, then fire the event. */
263 if (terminate)
264 SetEvent(dirwatch->terminate);
239} 265}
240 266
241/* Worker routine for the watch thread. */ 267/* Worker routine for the watch thread. */
@@ -243,42 +269,43 @@ static DWORD WINAPI
243watch_worker (LPVOID arg) 269watch_worker (LPVOID arg)
244{ 270{
245 struct notification *dirwatch = (struct notification *)arg; 271 struct notification *dirwatch = (struct notification *)arg;
272 BOOL bErr;
273 DWORD _bytes = 0;
274 DWORD status;
275
276 if (dirwatch->dir)
277 {
278 bErr = ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf,
279 DIRWATCH_BUFFER_SIZE, dirwatch->subtree,
280 dirwatch->filter, &_bytes,
281 dirwatch->io_info, watch_completion);
282 if (!bErr)
283 {
284 DebPrint (("ReadDirectoryChangesW: %lu\n", GetLastError ()));
285 /* We cannot remove the dirwatch object from watch_list,
286 because we are in a separate thread. For the same
287 reason, we also cannot free memory consumed by the
288 buffers allocated for the dirwatch object. So we close
289 the directory handle, but do not free the object itself
290 or its buffers. We also don't touch the signature. This
291 way, remove_watch can still identify the object, remove
292 it, and free its memory. */
293 CloseHandle (dirwatch->dir);
294 dirwatch->dir = NULL;
295 return 1;
296 }
297 }
246 298
247 do { 299 do {
248 BOOL status; 300 status = WaitForSingleObjectEx(dirwatch->terminate, INFINITE, TRUE);
249 DWORD bytes_ret = 0; 301 } while (status == WAIT_IO_COMPLETION);
250 302
251 if (dirwatch->dir) 303 /* The thread is about to terminate, so we clean up the dir handle. */
252 { 304 CloseHandle (dirwatch->dir);
253 status = ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf, 16384, 305 dirwatch->dir = NULL;
254 dirwatch->subtree, dirwatch->filter,
255 &bytes_ret,
256 dirwatch->io_info, watch_completion);
257 if (!status)
258 {
259 DebPrint (("watch_worker, abnormal exit: %lu\n", GetLastError ()));
260 /* We cannot remove the dirwatch object from watch_list,
261 because we are in a separate thread. For the same
262 reason, we also cannot free memory consumed by the
263 buffers allocated for the dirwatch object. So we close
264 the directory handle, but do not free the object itself
265 or its buffers. We also don't touch the signature.
266 This way, remove_watch can still identify the object,
267 remove it, and free its memory. */
268 CloseHandle (dirwatch->dir);
269 dirwatch->dir = NULL;
270 return 1;
271 }
272 }
273 /* Sleep indefinitely until awoken by the I/O completion, which
274 could be either a change notification or a cancellation of the
275 watch. */
276 SleepEx (INFINITE, TRUE);
277 } while (!dirwatch->terminate);
278 306
279 return 0; 307 return 0;
280} 308}
281
282/* Launch a thread to watch changes to FILE in a directory open on 309/* Launch a thread to watch changes to FILE in a directory open on
283 handle HDIR. */ 310 handle HDIR. */
284static struct notification * 311static struct notification *
@@ -287,7 +314,7 @@ start_watching (const char *file, HANDLE hdir, BOOL subdirs, DWORD flags)
287 struct notification *dirwatch = xzalloc (sizeof (struct notification)); 314 struct notification *dirwatch = xzalloc (sizeof (struct notification));
288 315
289 dirwatch->signature = DIRWATCH_SIGNATURE; 316 dirwatch->signature = DIRWATCH_SIGNATURE;
290 dirwatch->buf = xmalloc (16384); 317 dirwatch->buf = xmalloc (DIRWATCH_BUFFER_SIZE);
291 dirwatch->io_info = xzalloc (sizeof(OVERLAPPED)); 318 dirwatch->io_info = xzalloc (sizeof(OVERLAPPED));
292 /* Stash a pointer to dirwatch structure for use by the completion 319 /* Stash a pointer to dirwatch structure for use by the completion
293 routine. According to MSDN documentation of ReadDirectoryChangesW: 320 routine. According to MSDN documentation of ReadDirectoryChangesW:
@@ -297,7 +324,9 @@ start_watching (const char *file, HANDLE hdir, BOOL subdirs, DWORD flags)
297 dirwatch->subtree = subdirs; 324 dirwatch->subtree = subdirs;
298 dirwatch->filter = flags; 325 dirwatch->filter = flags;
299 dirwatch->watchee = xstrdup (file); 326 dirwatch->watchee = xstrdup (file);
300 dirwatch->terminate = 0; 327
328 dirwatch->terminate = CreateEvent(NULL, FALSE, FALSE, NULL);
329
301 dirwatch->dir = hdir; 330 dirwatch->dir = hdir;
302 331
303 /* See w32proc.c where it calls CreateThread for the story behind 332 /* See w32proc.c where it calls CreateThread for the story behind
@@ -307,11 +336,11 @@ start_watching (const char *file, HANDLE hdir, BOOL subdirs, DWORD flags)
307 336
308 if (!dirwatch->thr) 337 if (!dirwatch->thr)
309 { 338 {
339 CloseHandle(dirwatch->terminate);
310 xfree (dirwatch->buf); 340 xfree (dirwatch->buf);
311 xfree (dirwatch->io_info); 341 xfree (dirwatch->io_info);
312 xfree (dirwatch->watchee); 342 xfree (dirwatch->watchee);
313 xfree (dirwatch); 343 xfree (dirwatch);
314 dirwatch = NULL;
315 } 344 }
316 return dirwatch; 345 return dirwatch;
317} 346}
@@ -370,7 +399,10 @@ add_watch (const char *parent_dir, const char *file, BOOL subdirs, DWORD flags)
370 return NULL; 399 return NULL;
371 400
372 if ((dirwatch = start_watching (file, hdir, subdirs, flags)) == NULL) 401 if ((dirwatch = start_watching (file, hdir, subdirs, flags)) == NULL)
373 CloseHandle (hdir); 402 {
403 CloseHandle (hdir);
404 dirwatch->dir = NULL;
405 }
374 406
375 return dirwatch; 407 return dirwatch;
376} 408}
@@ -383,7 +415,7 @@ remove_watch (struct notification *dirwatch)
383 { 415 {
384 int i; 416 int i;
385 BOOL status; 417 BOOL status;
386 DWORD exit_code, err; 418 DWORD exit_code = 0, err;
387 419
388 /* Only the thread that issued the outstanding I/O call can call 420 /* Only the thread that issued the outstanding I/O call can call
389 CancelIo on it. (CancelIoEx is available only since Vista.) 421 CancelIo on it. (CancelIoEx is available only since Vista.)
@@ -391,12 +423,10 @@ remove_watch (struct notification *dirwatch)
391 to terminate. */ 423 to terminate. */
392 if (!QueueUserAPC (watch_end, dirwatch->thr, (ULONG_PTR)dirwatch->dir)) 424 if (!QueueUserAPC (watch_end, dirwatch->thr, (ULONG_PTR)dirwatch->dir))
393 DebPrint (("QueueUserAPC failed (%lu)!\n", GetLastError ())); 425 DebPrint (("QueueUserAPC failed (%lu)!\n", GetLastError ()));
394 /* We also set the terminate flag, for when the thread is 426
395 waiting on the critical section that never gets acquired. 427 /* We also signal the thread that it can terminate. */
396 FIXME: is there a cleaner method? Using SleepEx there is a 428 SetEvent(dirwatch->terminate);
397 no-no, as that will lead to recursive APC invocations and 429
398 stack overflow. */
399 dirwatch->terminate = 1;
400 /* Wait for the thread to exit. FIXME: is there a better method 430 /* Wait for the thread to exit. FIXME: is there a better method
401 that is not overly complex? */ 431 that is not overly complex? */
402 for (i = 0; i < 50; i++) 432 for (i = 0; i < 50; i++)
@@ -406,11 +436,13 @@ remove_watch (struct notification *dirwatch)
406 break; 436 break;
407 Sleep (10); 437 Sleep (10);
408 } 438 }
439
409 if ((status == FALSE && (err = GetLastError ()) == ERROR_INVALID_HANDLE) 440 if ((status == FALSE && (err = GetLastError ()) == ERROR_INVALID_HANDLE)
410 || exit_code == STILL_ACTIVE) 441 || exit_code == STILL_ACTIVE)
411 { 442 {
412 if (!(status == FALSE && err == ERROR_INVALID_HANDLE)) 443 if (!(status == FALSE && err == ERROR_INVALID_HANDLE))
413 { 444 {
445 DebPrint(("Forcing thread termination.\n"));
414 TerminateThread (dirwatch->thr, 0); 446 TerminateThread (dirwatch->thr, 0);
415 if (dirwatch->dir) 447 if (dirwatch->dir)
416 CloseHandle (dirwatch->dir); 448 CloseHandle (dirwatch->dir);
@@ -423,11 +455,11 @@ remove_watch (struct notification *dirwatch)
423 CloseHandle (dirwatch->thr); 455 CloseHandle (dirwatch->thr);
424 dirwatch->thr = NULL; 456 dirwatch->thr = NULL;
425 } 457 }
458 CloseHandle(dirwatch->terminate);
426 xfree (dirwatch->buf); 459 xfree (dirwatch->buf);
427 xfree (dirwatch->io_info); 460 xfree (dirwatch->io_info);
428 xfree (dirwatch->watchee); 461 xfree (dirwatch->watchee);
429 xfree (dirwatch); 462 xfree (dirwatch);
430
431 return 0; 463 return 0;
432 } 464 }
433 else 465 else
diff --git a/src/w32term.c b/src/w32term.c
index 62ad4eb086b..8955ce26b4b 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -3211,71 +3211,85 @@ static void
3211queue_notifications (struct input_event *event, W32Msg *msg, struct frame *f, 3211queue_notifications (struct input_event *event, W32Msg *msg, struct frame *f,
3212 int *evcount) 3212 int *evcount)
3213{ 3213{
3214 BYTE *p = file_notifications; 3214 struct notifications_set *ns = NULL;
3215 FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p;
3216 const DWORD min_size
3217 = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t);
3218 Lisp_Object frame; 3215 Lisp_Object frame;
3216 int done = 0;
3219 3217
3220 /* We cannot process notification before Emacs is fully initialized, 3218 /* We cannot process notification before Emacs is fully initialized,
3221 since we need the UTF-16LE coding-system to be set up. */ 3219 since we need the UTF-16LE coding-system to be set up. */
3222 if (!initialized) 3220 if (!initialized)
3223 { 3221 return;
3224 notification_buffer_in_use = 0;
3225 return;
3226 }
3227 3222
3228 XSETFRAME (frame, f); 3223 XSETFRAME (frame, f);
3229 3224
3230 enter_crit (); 3225 while (!done)
3231 if (notification_buffer_in_use)
3232 { 3226 {
3233 DWORD info_size = notifications_size; 3227 ns = NULL;
3234 Lisp_Object cs = Qutf_16le; 3228
3235 Lisp_Object obj = w32_get_watch_object (notifications_desc); 3229 /* Find out if there is a record available in the linked list of
3236 3230 notifications sets. If so, unlink the set from the linked
3237 /* notifications_size could be zero when the buffer of 3231 list. Use critical section. */
3238 notifications overflowed on the OS level, or when the 3232 enter_crit ();
3239 directory being watched was itself deleted. Do nothing in 3233 if (notifications_set_head->next != notifications_set_head)
3240 that case. */
3241 if (info_size
3242 && !NILP (obj) && CONSP (obj))
3243 { 3234 {
3244 Lisp_Object callback = XCDR (obj); 3235 ns = notifications_set_head->next;
3236 ns->prev->next = ns->next;
3237 ns->next->prev = ns->prev;
3238 }
3239 else
3240 done = 1;
3241 leave_crit();
3245 3242
3246 while (info_size >= min_size) 3243 if (ns)
3244 {
3245 BYTE *p = ns->notifications;
3246 FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p;
3247 const DWORD min_size
3248 = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t);
3249 DWORD info_size = ns->size;
3250 Lisp_Object cs = Qutf_16le;
3251 Lisp_Object obj = w32_get_watch_object (ns->desc);
3252
3253 /* notifications size could be zero when the buffer of
3254 notifications overflowed on the OS level, or when the
3255 directory being watched was itself deleted. Do nothing in
3256 that case. */
3257 if (info_size
3258 && !NILP (obj) && CONSP (obj))
3247 { 3259 {
3248 Lisp_Object utf_16_fn 3260 Lisp_Object callback = XCDR (obj);
3249 = make_unibyte_string ((char *)fni->FileName, 3261
3250 fni->FileNameLength); 3262 while (info_size >= min_size)
3251 /* Note: mule-conf is preloaded, so utf-16le must 3263 {
3252 already be defined at this point. */ 3264 Lisp_Object utf_16_fn
3253 Lisp_Object fname 3265 = make_unibyte_string ((char *)fni->FileName,
3254 = code_convert_string_norecord (utf_16_fn, cs, 0); 3266 fni->FileNameLength);
3255 Lisp_Object action = lispy_file_action (fni->Action); 3267 /* Note: mule-conf is preloaded, so utf-16le must
3256 3268 already be defined at this point. */
3257 event->kind = FILE_NOTIFY_EVENT; 3269 Lisp_Object fname
3258 event->timestamp = msg->msg.time; 3270 = code_convert_string_norecord (utf_16_fn, cs, 0);
3259 event->modifiers = 0; 3271 Lisp_Object action = lispy_file_action (fni->Action);
3260 event->frame_or_window = callback; 3272
3261 event->arg = list3 (make_pointer_integer (notifications_desc), 3273 event->kind = FILE_NOTIFY_EVENT;
3262 action, fname); 3274 event->timestamp = msg->msg.time;
3263 kbd_buffer_store_event (event); 3275 event->modifiers = 0;
3264 (*evcount)++; 3276 event->frame_or_window = callback;
3265 3277 event->arg = list3 (make_pointer_integer (ns->desc),
3266 if (!fni->NextEntryOffset) 3278 action, fname);
3267 break; 3279 kbd_buffer_store_event (event);
3268 p += fni->NextEntryOffset; 3280 (*evcount)++;
3269 fni = (PFILE_NOTIFY_INFORMATION)p; 3281 if (!fni->NextEntryOffset)
3270 info_size -= fni->NextEntryOffset; 3282 break;
3283 p += fni->NextEntryOffset;
3284 fni = (PFILE_NOTIFY_INFORMATION)p;
3285 info_size -= fni->NextEntryOffset;
3286 }
3271 } 3287 }
3288 /* Free this notifications set. */
3289 xfree (ns->notifications);
3290 xfree (ns);
3272 } 3291 }
3273 notification_buffer_in_use = 0;
3274 } 3292 }
3275 else
3276 DebPrint (("We were promised notifications, but in-use flag is zero!\n"));
3277 leave_crit ();
3278
3279 /* We've stuffed all the events ourselves, so w32_read_socket shouldn't. */ 3293 /* We've stuffed all the events ourselves, so w32_read_socket shouldn't. */
3280 event->kind = NO_EVENT; 3294 event->kind = NO_EVENT;
3281} 3295}
@@ -6949,6 +6963,8 @@ w32_init_main_thread (void)
6949 DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), 6963 DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
6950 GetCurrentProcess (), &hMainThread, 0, TRUE, 6964 GetCurrentProcess (), &hMainThread, 0, TRUE,
6951 DUPLICATE_SAME_ACCESS); 6965 DUPLICATE_SAME_ACCESS);
6966
6967
6952} 6968}
6953 6969
6954DWORD WINAPI w32_msg_worker (void * arg); 6970DWORD WINAPI w32_msg_worker (void * arg);
diff --git a/src/w32term.h b/src/w32term.h
index d809be3c03d..8585c8190db 100644
--- a/src/w32term.h
+++ b/src/w32term.h
@@ -727,10 +727,18 @@ extern void x_delete_display (struct w32_display_info *dpyinfo);
727 727
728extern void x_query_color (struct frame *, XColor *); 728extern void x_query_color (struct frame *, XColor *);
729 729
730extern volatile int notification_buffer_in_use; 730#define FILE_NOTIFICATIONS_SIZE 16384
731extern BYTE file_notifications[16384]; 731/* Notifications come in sets. We use a doubly linked list with a
732extern DWORD notifications_size; 732 sentinel to communicate those sets from the watching threads to the
733extern void *notifications_desc; 733 main thread. */
734struct notifications_set {
735 LPBYTE notifications;
736 DWORD size;
737 void *desc;
738 struct notifications_set *next;
739 struct notifications_set *prev;
740};
741extern struct notifications_set *notifications_set_head;
734extern Lisp_Object w32_get_watch_object (void *); 742extern Lisp_Object w32_get_watch_object (void *);
735extern Lisp_Object lispy_file_action (DWORD); 743extern Lisp_Object lispy_file_action (DWORD);
736extern int handle_file_notifications (struct input_event *); 744extern int handle_file_notifications (struct input_event *);
diff --git a/src/w32xfns.c b/src/w32xfns.c
index 04bf5ce733e..9b633c4c56a 100644
--- a/src/w32xfns.c
+++ b/src/w32xfns.c
@@ -48,6 +48,19 @@ init_crit (void)
48 when the input queue is empty, so make it a manual reset event. */ 48 when the input queue is empty, so make it a manual reset event. */
49 input_available = CreateEvent (NULL, TRUE, FALSE, NULL); 49 input_available = CreateEvent (NULL, TRUE, FALSE, NULL);
50 50
51 /* Initialize the linked list of notifications sets that will be
52 used to communicate between the watching worker threads and the
53 main thread. */
54 notifications_set_head = malloc (sizeof(struct notifications_set));
55 if (notifications_set_head)
56 {
57 memset (notifications_set_head, 0, sizeof(struct notifications_set));
58 notifications_set_head->next
59 = notifications_set_head->prev = notifications_set_head;
60 }
61 else
62 DebPrint(("Out of memory: can't initialize notifications sets."));
63
51#ifdef WINDOWSNT 64#ifdef WINDOWSNT
52 keyboard_handle = input_available; 65 keyboard_handle = input_available;
53#endif /* WINDOWSNT */ 66#endif /* WINDOWSNT */
@@ -76,6 +89,21 @@ delete_crit (void)
76 CloseHandle (interrupt_handle); 89 CloseHandle (interrupt_handle);
77 interrupt_handle = NULL; 90 interrupt_handle = NULL;
78 } 91 }
92
93 if (notifications_set_head)
94 {
95 /* Free any remaining notifications set that could be left over. */
96 while (notifications_set_head->next != notifications_set_head)
97 {
98 struct notifications_set *ns = notifications_set_head->next;
99 notifications_set_head->next = ns->next;
100 ns->next->prev = notifications_set_head;
101 if (ns->notifications)
102 free (ns->notifications);
103 free (ns);
104 }
105 }
106 free (notifications_set_head);
79} 107}
80 108
81void 109void