aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2012-10-07 15:41:15 +0200
committerEli Zaretskii2012-10-07 15:41:15 +0200
commitc5c91b847a41ec7e09dee582816d702c8a9adcdd (patch)
treec96da676a40396ee6e0aaaa969fd01f984791559
parent25d99a950debf417295e68a7a7d519b4ddf3e546 (diff)
downloademacs-c5c91b847a41ec7e09dee582816d702c8a9adcdd.tar.gz
emacs-c5c91b847a41ec7e09dee582816d702c8a9adcdd.zip
Final version that supports only one watch at a time.
-rw-r--r--lib-src/ChangeLog4
-rw-r--r--lisp/ChangeLog4
-rw-r--r--src/ChangeLog34
-rw-r--r--src/w32fns.c3
-rw-r--r--src/w32notify.c102
-rw-r--r--src/w32term.c4
6 files changed, 94 insertions, 57 deletions
diff --git a/lib-src/ChangeLog b/lib-src/ChangeLog
index 2a8ac9b8131..a9031d74758 100644
--- a/lib-src/ChangeLog
+++ b/lib-src/ChangeLog
@@ -1,3 +1,7 @@
12012-10-07 Eli Zaretskii <eliz@gnu.org>
2
3 * makefile.w32-in (obj): Add w32notify.o.
4
12012-10-01 Fabrice Popineau <fabrice.popineau@gmail.com> 52012-10-01 Fabrice Popineau <fabrice.popineau@gmail.com>
2 6
3 * make-docfile.c (write_globals): Special-case 7 * make-docfile.c (write_globals): Special-case
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index e54e82233a2..7d40007f435 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,7 @@
12012-10-07 Eli Zaretskii <eliz@gnu.org>
2
3 * subr.el (w32notify-handle-event): New function.
4
12012-10-07 Glenn Morris <rgm@gnu.org> 52012-10-07 Glenn Morris <rgm@gnu.org>
2 6
3 * mail/rmailmm.el (rmail-mime-process-multipart): 7 * mail/rmailmm.el (rmail-mime-process-multipart):
diff --git a/src/ChangeLog b/src/ChangeLog
index 492b966a256..cb2aab2166c 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,37 @@
12012-10-07 Eli Zaretskii <eliz@gnu.org>
2
3 * w32term.h (WM_EMACS_FILENOTIFY): New custom message.
4 (WM_EMACS_END): Bump value by 1.
5
6 * w32term.c (lispy_file_action, queue_notifications): New functions.
7 (syms_of_w32term) <Qadded, Qremoved, Qmodified, Qrenamed_from>
8 <Qrenamed_to>: New symbols.
9
10 * w32notify.c: New file, implement file event notifications for
11 MS-Windows.
12
13 * w32fns.c (w32_wnd_proc): Handle the WM_EMACS_FILENOTIFY message
14 by posting it to the w32_read_socket queue.
15
16 * termhooks.h (enum event_kind) [WINDOWSNT]: New event kind
17 FILE_NOTIFY_EVENT.
18
19 * makefile.w32-in (OBJ2): Add $(BLD)/w32notify.$(O).
20 (GLOBAL_SOURCES): Add w32notify.c
21 ($(BLD)/w32notify.$(O)): New set of dependencies.
22
23 * lisp.h (syms_of_w32notify) [WINDOWSNT]: Add prototype.
24
25 * keyboard.c (kbd_buffer_get_event) [WINDOWSNT]: Handle
26 FILE_NOTIFY_EVENT.
27 (syms_of_keyboard) [WINDOWSNT] <Qfile_notify>: New symbol.
28 (keys_of_keyboard) [WINDOWSNT]: Bind file-notify to
29 w32notify-handle-event by default.
30
31 * emacs.c (main) [WINDOWSNT]: Call syms_of_w32notify.
32
33 * alloc.c (NSTATICS): Enlarge to 0x660.
34
12012-10-07 Jan Djärv <jan.h.d@swipnet.se> 352012-10-07 Jan Djärv <jan.h.d@swipnet.se>
2 36
3 * nsterm.m (ns_dumpglyphs_image): Only draw slize of image (Bug#12506). 37 * nsterm.m (ns_dumpglyphs_image): Only draw slize of image (Bug#12506).
diff --git a/src/w32fns.c b/src/w32fns.c
index 2d36da3b56b..fac6030b9b5 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -2259,8 +2259,6 @@ w32_msg_pump (deferred_msg * msg_buf)
2259 2259
2260 while ((w32_unicode_gui ? GetMessageW : GetMessageA) (&msg, NULL, 0, 0)) 2260 while ((w32_unicode_gui ? GetMessageW : GetMessageA) (&msg, NULL, 0, 0))
2261 { 2261 {
2262 if (msg.message == WM_EMACS_FILENOTIFY)
2263 DebPrint (("w32_msg_pump: File notification, hwnd = 0x%p\n", msg.hwnd));
2264 if (msg.hwnd == NULL) 2262 if (msg.hwnd == NULL)
2265 { 2263 {
2266 switch (msg.message) 2264 switch (msg.message)
@@ -3810,7 +3808,6 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
3810 return retval; 3808 return retval;
3811 } 3809 }
3812 case WM_EMACS_FILENOTIFY: 3810 case WM_EMACS_FILENOTIFY:
3813 DebPrint (("w32_wnd_proc: File notification arrived, posting\n"));
3814 my_post_msg (&wmsg, hwnd, msg, wParam, lParam); 3811 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3815 return 1; 3812 return 1;
3816 3813
diff --git a/src/w32notify.c b/src/w32notify.c
index 0dc4d27d33f..81199b2a0a1 100644
--- a/src/w32notify.c
+++ b/src/w32notify.c
@@ -16,6 +16,54 @@ GNU General Public License for more details.
16You should have received a copy of the GNU General Public License 16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18 18
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
64 ReadDirectoryChangesW call. The main thread waits for the worker
65 thread to exit, and if it doesn't, terminate it forcibly. */
66
19#include <stddef.h> 67#include <stddef.h>
20#include <errno.h> 68#include <errno.h>
21 69
@@ -58,51 +106,6 @@ static Lisp_Object Qfile_name, Qdirectory_name, Qattributes, Qsize;
58static Lisp_Object Qlast_write_time, Qlast_access_time, Qcreation_time; 106static Lisp_Object Qlast_write_time, Qlast_access_time, Qcreation_time;
59static Lisp_Object Qsecurity_desc, Qsubtree, watch_list; 107static Lisp_Object Qsecurity_desc, Qsubtree, watch_list;
60 108
61#if 0
62/* FIXME: Debugging code, should be removed eventually. */
63const wchar_t *
64format_file_action (DWORD action)
65{
66 static const wchar_t *action_str[] =
67 { L"???", L"Added", L"Removed", L"Modified", L"Renamed from", L"Renamed to" };
68
69 if (action >= sizeof(action_str)/sizeof(action_str[0]))
70 action = 0;
71 return action_str[action];
72}
73
74void
75parse_notifications (BYTE *info, DWORD info_size)
76{
77 BYTE *p = info;
78 FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p;
79 const DWORD min_size
80 = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t);
81
82 if (!info_size)
83 {
84 printf ("No info in notifications!\n");
85 return;
86 }
87
88 while (info_size >= min_size)
89 {
90 wchar_t *fn = alloca (fni->FileNameLength + sizeof(wchar_t));
91 const wchar_t *action_str;
92
93 memcpy (fn, fni->FileName, fni->FileNameLength);
94 fn[fni->FileNameLength/sizeof(wchar_t)] = 0;
95 action_str = format_file_action (fni->Action);
96 wprintf (L"%s: %s\n", action_str, fn);
97 if (!fni->NextEntryOffset)
98 break;
99 p += fni->NextEntryOffset;
100 fni = (PFILE_NOTIFY_INFORMATION)p;
101 info_size -= fni->NextEntryOffset;
102 }
103}
104#endif /* debugging code */
105
106/* Signal to the main thread that we have file notifications for it to 109/* Signal to the main thread that we have file notifications for it to
107 process. */ 110 process. */
108static void 111static void
@@ -141,7 +144,6 @@ send_notifications (BYTE *info, DWORD info_size, HANDLE hdir, int *terminate)
141 if (PostMessage (FRAME_W32_WINDOW (f), WM_EMACS_FILENOTIFY, 0, 0)) 144 if (PostMessage (FRAME_W32_WINDOW (f), WM_EMACS_FILENOTIFY, 0, 0))
142 notification_buffer_in_use = 1; 145 notification_buffer_in_use = 1;
143 done = 1; 146 done = 1;
144 DebPrint (("Announced notifications of %lu bytes\n", info_size));
145 } 147 }
146 leave_crit (); 148 leave_crit ();
147 if (!done) 149 if (!done)
@@ -205,9 +207,6 @@ watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info)
205 } 207 }
206 else 208 else
207 { 209 {
208#if 0 /* debugging code */
209 parse_notifications (dirwatch->buf, bytes_ret);
210#endif
211 /* Tell the main thread we have notifications for it. */ 210 /* Tell the main thread we have notifications for it. */
212 send_notifications (dirwatch->buf, bytes_ret, dirwatch->dir, 211 send_notifications (dirwatch->buf, bytes_ret, dirwatch->dir,
213 &dirwatch->terminate); 212 &dirwatch->terminate);
@@ -233,7 +232,7 @@ watch_worker (LPVOID arg)
233 dirwatch->io_info, watch_completion); 232 dirwatch->io_info, watch_completion);
234 if (!status) 233 if (!status)
235 { 234 {
236 DebPrint (("watch_worker(1): %lu\n", GetLastError ())); 235 DebPrint (("watch_worker, abnormal exit: %lu\n", GetLastError ()));
237 xfree (dirwatch->buf); 236 xfree (dirwatch->buf);
238 dirwatch->buf = NULL; 237 dirwatch->buf = NULL;
239 xfree (dirwatch->io_info); 238 xfree (dirwatch->io_info);
@@ -249,11 +248,8 @@ watch_worker (LPVOID arg)
249 could be either a change notification or a cancellation of the 248 could be either a change notification or a cancellation of the
250 watch. */ 249 watch. */
251 sleep_result = SleepEx (INFINITE, TRUE); 250 sleep_result = SleepEx (INFINITE, TRUE);
252 if (dirwatch->terminate)
253 DebPrint (("watch_worker: exiting by request\n"));
254 } while (!dirwatch->terminate); 251 } while (!dirwatch->terminate);
255 252
256 DebPrint (("watch_worker(2): %lu\n", GetLastError ()));
257 return 0; 253 return 0;
258} 254}
259 255
diff --git a/src/w32term.c b/src/w32term.c
index 1c32383098f..71e6c7235a1 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -3204,6 +3204,9 @@ construct_drag_n_drop (struct input_event *result, W32Msg *msg, struct frame *f)
3204 return Qnil; 3204 return Qnil;
3205} 3205}
3206 3206
3207
3208/* File event notifications (see w32notify.c). */
3209
3207static Lisp_Object 3210static Lisp_Object
3208lispy_file_action (DWORD action) 3211lispy_file_action (DWORD action)
3209{ 3212{
@@ -4945,7 +4948,6 @@ w32_read_socket (struct terminal *terminal,
4945 break; 4948 break;
4946 4949
4947 case WM_EMACS_FILENOTIFY: 4950 case WM_EMACS_FILENOTIFY:
4948 DebPrint (("w32_read_socket: File notification arrived\n"));
4949 f = x_window_to_frame (dpyinfo, msg.msg.hwnd); 4951 f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
4950 if (f) 4952 if (f)
4951 queue_notifications (&inev, &msg, f, &count); 4953 queue_notifications (&inev, &msg, f, &count);