aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2012-10-14 16:38:33 +0200
committerEli Zaretskii2012-10-14 16:38:33 +0200
commit37a4dabe8aaa51e15cf63e43710ee4b8f35d434b (patch)
treef2e68e1b5822f726e9b1d12c96b732bff607fad3
parentdd8c2f5adeba029790a007ec829e18442a4ade36 (diff)
downloademacs-37a4dabe8aaa51e15cf63e43710ee4b8f35d434b.tar.gz
emacs-37a4dabe8aaa51e15cf63e43710ee4b8f35d434b.zip
More than one watch is now supported.
Need to fix the issue with descriptor, now a pointer converted to Lisp integer.
-rw-r--r--src/emacs.c1
-rw-r--r--src/w32inevt.c2
-rw-r--r--src/w32notify.c158
-rw-r--r--src/w32term.c2
-rw-r--r--src/w32term.h5
5 files changed, 93 insertions, 75 deletions
diff --git a/src/emacs.c b/src/emacs.c
index c84da7411ad..6295450a405 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1279,6 +1279,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1279 1279
1280#ifdef WINDOWSNT 1280#ifdef WINDOWSNT
1281 globals_of_w32 (); 1281 globals_of_w32 ();
1282 globals_of_w32notify ();
1282 /* Initialize environment from registry settings. */ 1283 /* Initialize environment from registry settings. */
1283 init_environment (argv); 1284 init_environment (argv);
1284 init_ntproc (dumping); /* must precede init_editfns. */ 1285 init_ntproc (dumping); /* must precede init_editfns. */
diff --git a/src/w32inevt.c b/src/w32inevt.c
index a5868be612c..878106d7070 100644
--- a/src/w32inevt.c
+++ b/src/w32inevt.c
@@ -599,7 +599,7 @@ handle_file_notifications (struct input_event *hold_quit)
599 { 599 {
600 DWORD info_size = notifications_size; 600 DWORD info_size = notifications_size;
601 Lisp_Object cs = intern ("utf-16le"); 601 Lisp_Object cs = intern ("utf-16le");
602 Lisp_Object obj = get_watch_object (make_number (notifications_desc)); 602 Lisp_Object obj = w32_get_watch_object (make_number (notifications_desc));
603 603
604 /* notifications_size could be zero when the buffer of 604 /* notifications_size could be zero when the buffer of
605 notifications overflowed on the OS level, or when the 605 notifications overflowed on the OS level, or when the
diff --git a/src/w32notify.c b/src/w32notify.c
index bdfdf3472a0..244b0b872bf 100644
--- a/src/w32notify.c
+++ b/src/w32notify.c
@@ -93,6 +93,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
93#include "frame.h" /* needed by termhooks.h */ 93#include "frame.h" /* needed by termhooks.h */
94#include "termhooks.h" /* for FILE_NOTIFY_EVENT */ 94#include "termhooks.h" /* for FILE_NOTIFY_EVENT */
95 95
96#define DIRWATCH_SIGNATURE 0x01233210
97
96struct notification { 98struct notification {
97 BYTE *buf; /* buffer for ReadDirectoryChangesW */ 99 BYTE *buf; /* buffer for ReadDirectoryChangesW */
98 OVERLAPPED *io_info; /* the OVERLAPPED structure for async I/O */ 100 OVERLAPPED *io_info; /* the OVERLAPPED structure for async I/O */
@@ -102,17 +104,14 @@ struct notification {
102 HANDLE dir; /* handle to the watched directory */ 104 HANDLE dir; /* handle to the watched directory */
103 HANDLE thr; /* handle to the thread that watches */ 105 HANDLE thr; /* handle to the thread that watches */
104 int terminate; /* if non-zero, request for the thread to terminate */ 106 int terminate; /* if non-zero, request for the thread to terminate */
107 unsigned signature;
105}; 108};
106 109
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. */ 110/* Used for communicating notifications to the main thread. */
112int notification_buffer_in_use; 111int notification_buffer_in_use;
113BYTE file_notifications[16384]; 112BYTE file_notifications[16384];
114DWORD notifications_size; 113DWORD notifications_size;
115HANDLE notifications_desc; 114void *notifications_desc;
116 115
117static Lisp_Object Qfile_name, Qdirectory_name, Qattributes, Qsize; 116static Lisp_Object Qfile_name, Qdirectory_name, Qattributes, Qsize;
118static Lisp_Object Qlast_write_time, Qlast_access_time, Qcreation_time; 117static Lisp_Object Qlast_write_time, Qlast_access_time, Qcreation_time;
@@ -121,12 +120,11 @@ static Lisp_Object Qsecurity_desc, Qsubtree, watch_list;
121/* Signal to the main thread that we have file notifications for it to 120/* Signal to the main thread that we have file notifications for it to
122 process. */ 121 process. */
123static void 122static void
124send_notifications (BYTE *info, DWORD info_size, HANDLE hdir, int *terminate) 123send_notifications (BYTE *info, DWORD info_size, void *desc, int *terminate)
125{ 124{
126 int done = 0; 125 int done = 0;
127 FRAME_PTR f = SELECTED_FRAME (); 126 FRAME_PTR f = SELECTED_FRAME ();
128 127
129
130 /* A single buffer is used to communicate all notifications to the 128 /* A single buffer is used to communicate all notifications to the
131 main thread. Since both the main thread and several watcher 129 main thread. Since both the main thread and several watcher
132 threads could be active at the same time, we use a critical area 130 threads could be active at the same time, we use a critical area
@@ -144,7 +142,7 @@ send_notifications (BYTE *info, DWORD info_size, HANDLE hdir, int *terminate)
144 if (info_size) 142 if (info_size)
145 memcpy (file_notifications, info, info_size); 143 memcpy (file_notifications, info, info_size);
146 notifications_size = info_size; 144 notifications_size = info_size;
147 notifications_desc = hdir; 145 notifications_desc = desc;
148 /* If PostMessage fails, the message queue is full. If that 146 /* If PostMessage fails, the message queue is full. If that
149 happens, the last thing they will worry about is file 147 happens, the last thing they will worry about is file
150 notifications. So we effectively discard the 148 notifications. So we effectively discard the
@@ -214,7 +212,9 @@ watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info)
214 CancelIo on the directory we watch, and watch_end did so. 212 CancelIo on the directory we watch, and watch_end did so.
215 The directory handle is already closed. We should clean up 213 The directory handle is already closed. We should clean up
216 and exit, signalling to the thread worker routine not to 214 and exit, signalling to the thread worker routine not to
217 issue another call to ReadDirectoryChangesW. */ 215 issue another call to ReadDirectoryChangesW. Note that we
216 don't free the dirwatch object itself; this is done by the
217 main thread in remove_watch. */
218 xfree (dirwatch->buf); 218 xfree (dirwatch->buf);
219 dirwatch->buf = NULL; 219 dirwatch->buf = NULL;
220 xfree (dirwatch->io_info); 220 xfree (dirwatch->io_info);
@@ -227,7 +227,7 @@ watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info)
227 else 227 else
228 { 228 {
229 /* Tell the main thread we have notifications for it. */ 229 /* Tell the main thread we have notifications for it. */
230 send_notifications (dirwatch->buf, bytes_ret, dirwatch->dir, 230 send_notifications (dirwatch->buf, bytes_ret, dirwatch,
231 &dirwatch->terminate); 231 &dirwatch->terminate);
232 } 232 }
233} 233}
@@ -252,6 +252,12 @@ watch_worker (LPVOID arg)
252 if (!status) 252 if (!status)
253 { 253 {
254 DebPrint (("watch_worker, abnormal exit: %lu\n", GetLastError ())); 254 DebPrint (("watch_worker, abnormal exit: %lu\n", GetLastError ()));
255 /* We cannot remove the dirwatch object from watch_list,
256 because we are in a separate thread. So we free and
257 zero out all the pointers in the object, but do not
258 free the object itself. We also don't touch the
259 signature. This way, remove_watch can still identify
260 the object, remove it, and free its memory. */
255 xfree (dirwatch->buf); 261 xfree (dirwatch->buf);
256 dirwatch->buf = NULL; 262 dirwatch->buf = NULL;
257 xfree (dirwatch->io_info); 263 xfree (dirwatch->io_info);
@@ -274,50 +280,51 @@ watch_worker (LPVOID arg)
274 280
275/* Launch a thread to watch changes to FILE in a directory open on 281/* Launch a thread to watch changes to FILE in a directory open on
276 handle HDIR. */ 282 handle HDIR. */
277static int 283static struct notification *
278start_watching (const char *file, HANDLE hdir, BOOL subdirs, DWORD flags) 284start_watching (const char *file, HANDLE hdir, BOOL subdirs, DWORD flags)
279{ 285{
280 dirwatch.buf = xmalloc (16384); 286 struct notification *dirwatch = xzalloc (sizeof (struct notification));
281 dirwatch.io_info = xzalloc (sizeof(OVERLAPPED)); 287 HANDLE thr;
288
289 dirwatch->signature = DIRWATCH_SIGNATURE;
290 dirwatch->buf = xmalloc (16384);
291 dirwatch->io_info = xzalloc (sizeof(OVERLAPPED));
282 /* Stash a pointer to dirwatch structure for use by the completion 292 /* Stash a pointer to dirwatch structure for use by the completion
283 routine. According to MSDN documentation of ReadDirectoryChangesW: 293 routine. According to MSDN documentation of ReadDirectoryChangesW:
284 "The hEvent member of the OVERLAPPED structure is not used by the 294 "The hEvent member of the OVERLAPPED structure is not used by the
285 system, so you can use it yourself." */ 295 system, so you can use it yourself." */
286 dirwatch.io_info->hEvent = &dirwatch; 296 dirwatch->io_info->hEvent = dirwatch;
287 dirwatch.subtree = subdirs; 297 dirwatch->subtree = subdirs;
288 dirwatch.filter = flags; 298 dirwatch->filter = flags;
289 dirwatch.watchee = xstrdup (file); 299 dirwatch->watchee = xstrdup (file);
290 dirwatch.terminate = 0; 300 dirwatch->terminate = 0;
291 dirwatch.dir = hdir; 301 dirwatch->dir = hdir;
292 302
293 /* See w32proc.c where it calls CreateThread for the story behind 303 /* See w32proc.c where it calls CreateThread for the story behind
294 the 2nd and 5th argument in the call to CreateThread. */ 304 the 2nd and 5th argument in the call to CreateThread. */
295 dirwatch.thr = CreateThread (NULL, 64 * 1024, watch_worker, 305 dirwatch->thr = CreateThread (NULL, 64 * 1024, watch_worker, (void *)dirwatch,
296 (void *)&dirwatch, 0x00010000, NULL); 306 0x00010000, NULL);
297 307
298 if (!dirwatch.thr) 308 if (!dirwatch->thr)
299 { 309 {
300 dirwatch.terminate = 1; 310 xfree (dirwatch->buf);
301 xfree (dirwatch.buf); 311 xfree (dirwatch->io_info);
302 dirwatch.buf = NULL; 312 xfree (dirwatch->watchee);
303 xfree (dirwatch.io_info); 313 xfree (dirwatch);
304 dirwatch.io_info = NULL; 314 dirwatch = NULL;
305 xfree (dirwatch.watchee);
306 dirwatch.watchee = NULL;
307 dirwatch.dir = NULL;
308 return -1;
309 } 315 }
310 return 0; 316 return dirwatch;
311} 317}
312 318
313/* Called from the main thread to start watching FILE in PARENT_DIR, 319/* Called from the main thread to start watching FILE in PARENT_DIR,
314 subject to FLAGS. If SUBDIRS is TRUE, watch the subdirectories of 320 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 321 PARENT_DIR as well. Value is a pointer to 'struct notification'
316 open. */ 322 used by the thread that watches the changes. */
317static HANDLE * 323static struct notification *
318add_watch (const char *parent_dir, const char *file, BOOL subdirs, DWORD flags) 324add_watch (const char *parent_dir, const char *file, BOOL subdirs, DWORD flags)
319{ 325{
320 HANDLE hdir; 326 HANDLE hdir;
327 struct notification *dirwatch = NULL;
321 328
322 if (!file || !*file) 329 if (!file || !*file)
323 return NULL; 330 return NULL;
@@ -334,18 +341,17 @@ add_watch (const char *parent_dir, const char *file, BOOL subdirs, DWORD flags)
334 if (hdir == INVALID_HANDLE_VALUE) 341 if (hdir == INVALID_HANDLE_VALUE)
335 return NULL; 342 return NULL;
336 343
337 if (start_watching (file, hdir, subdirs, flags) == 0) 344 if ((dirwatch = start_watching (file, hdir, subdirs, flags)) == NULL)
338 return hdir; 345 CloseHandle (hdir);
339 346
340 CloseHandle (hdir); 347 return dirwatch;
341 return NULL;
342} 348}
343 349
344/* Stop watching a directory specified by its handle HDIR. */ 350/* Stop watching a directory specified by a pointer to its dirwatch object. */
345static int 351static int
346remove_watch (HANDLE hdir) 352remove_watch (struct notification *dirwatch)
347{ 353{
348 if (hdir == dirwatch.dir) 354 if (dirwatch && dirwatch->signature == DIRWATCH_SIGNATURE)
349 { 355 {
350 int i; 356 int i;
351 BOOL status; 357 BOOL status;
@@ -355,19 +361,19 @@ remove_watch (HANDLE hdir)
355 CancelIo on it. (CancelIoEx is available only since Vista.) 361 CancelIo on it. (CancelIoEx is available only since Vista.)
356 So we need to queue an APC for the worker thread telling it 362 So we need to queue an APC for the worker thread telling it
357 to terminate. */ 363 to terminate. */
358 if (!QueueUserAPC (watch_end, dirwatch.thr, (ULONG_PTR)dirwatch.dir)) 364 if (!QueueUserAPC (watch_end, dirwatch->thr, (ULONG_PTR)dirwatch->dir))
359 DebPrint (("QueueUserAPC failed (%lu)!\n", GetLastError ())); 365 DebPrint (("QueueUserAPC failed (%lu)!\n", GetLastError ()));
360 /* We also set the terminate flag, for when the thread is 366 /* We also set the terminate flag, for when the thread is
361 waiting on the critical section that never gets acquired. 367 waiting on the critical section that never gets acquired.
362 FIXME: is there a cleaner method? Using SleepEx there is a 368 FIXME: is there a cleaner method? Using SleepEx there is a
363 no-no, as that will lead to recursive APC invocations and 369 no-no, as that will lead to recursive APC invocations and
364 stack overflow. */ 370 stack overflow. */
365 dirwatch.terminate = 1; 371 dirwatch->terminate = 1;
366 /* Wait for the thread to exit. FIXME: is there a better method 372 /* Wait for the thread to exit. FIXME: is there a better method
367 that is not overly complex? */ 373 that is not overly complex? */
368 for (i = 0; i < 50; i++) 374 for (i = 0; i < 50; i++)
369 { 375 {
370 if (!((status = GetExitCodeThread (dirwatch.thr, &exit_code)) 376 if (!((status = GetExitCodeThread (dirwatch->thr, &exit_code))
371 && exit_code == STILL_ACTIVE)) 377 && exit_code == STILL_ACTIVE))
372 break; 378 break;
373 Sleep (10); 379 Sleep (10);
@@ -376,25 +382,29 @@ remove_watch (HANDLE hdir)
376 || exit_code == STILL_ACTIVE) 382 || exit_code == STILL_ACTIVE)
377 { 383 {
378 if (!(status == FALSE && err == ERROR_INVALID_HANDLE)) 384 if (!(status == FALSE && err == ERROR_INVALID_HANDLE))
379 TerminateThread (dirwatch.thr, 0); 385 {
386 TerminateThread (dirwatch->thr, 0);
387 if (dirwatch->dir)
388 CloseHandle (dirwatch->dir);
389 }
380 } 390 }
381 391
382 /* Clean up. */ 392 /* Clean up. */
383 if (dirwatch.thr) 393 if (dirwatch->thr)
384 { 394 {
385 CloseHandle (dirwatch.thr); 395 CloseHandle (dirwatch->thr);
386 dirwatch.thr = NULL; 396 dirwatch->thr = NULL;
387 } 397 }
388 return 0; 398 xfree (dirwatch->buf);
389 } 399 xfree (dirwatch->io_info);
390 else if (!dirwatch.dir) 400 xfree (dirwatch->watchee);
391 { 401 xfree (dirwatch);
392 DebPrint (("Directory handle already closed!\n")); 402
393 return 0; 403 return 0;
394 } 404 }
395 else 405 else
396 { 406 {
397 DebPrint (("Unknown directory handle!\n")); 407 DebPrint (("Unknown dirwatch object!\n"));
398 return -1; 408 return -1;
399 } 409 }
400} 410}
@@ -474,9 +484,9 @@ FILE is the name of the file whose event is being reported. */)
474 Lisp_Object encoded_file, watch_object, watch_descriptor; 484 Lisp_Object encoded_file, watch_object, watch_descriptor;
475 char parent_dir[MAX_PATH], *basename; 485 char parent_dir[MAX_PATH], *basename;
476 size_t fn_len; 486 size_t fn_len;
477 HANDLE hdir;
478 DWORD flags; 487 DWORD flags;
479 BOOL subdirs = FALSE; 488 BOOL subdirs = FALSE;
489 struct notification *dirwatch = NULL;
480 Lisp_Object lisp_errstr; 490 Lisp_Object lisp_errstr;
481 char *errstr; 491 char *errstr;
482 492
@@ -491,10 +501,7 @@ FILE is the name of the file whose event is being reported. */)
491 Qnil); 501 Qnil);
492 } 502 }
493 503
494 if (dirwatch.dir) 504 /* We need a full absolute file name of FILE, and we need to remove
495 error ("File watch already active");
496
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 505 any trailing slashes from it, so that GetFullPathName below gets
499 the basename part correctly. */ 506 the basename part correctly. */
500 file = Fdirectory_file_name (Fexpand_file_name (file, Qnil)); 507 file = Fdirectory_file_name (Fexpand_file_name (file, Qnil));
@@ -528,8 +535,8 @@ FILE is the name of the file whose event is being reported. */)
528 535
529 flags = filter_list_to_flags (filter); 536 flags = filter_list_to_flags (filter);
530 537
531 hdir = add_watch (parent_dir, basename, subdirs, flags); 538 dirwatch = add_watch (parent_dir, basename, subdirs, flags);
532 if (!hdir) 539 if (!dirwatch)
533 { 540 {
534 DWORD err = GetLastError (); 541 DWORD err = GetLastError ();
535 542
@@ -550,7 +557,7 @@ FILE is the name of the file whose event is being reported. */)
550 report_file_error ("Cannot watch file", Fcons (file, Qnil)); 557 report_file_error ("Cannot watch file", Fcons (file, Qnil));
551 } 558 }
552 /* Store watch object in watch list. */ 559 /* Store watch object in watch list. */
553 watch_descriptor = make_number (hdir); 560 watch_descriptor = make_number (dirwatch);
554 watch_object = Fcons (watch_descriptor, callback); 561 watch_object = Fcons (watch_descriptor, callback);
555 watch_list = Fcons (watch_object, watch_list); 562 watch_list = Fcons (watch_object, watch_list);
556 563
@@ -565,24 +572,33 @@ WATCH-DESCRIPTOR should be an object returned by `w32notify-add-watch'. */)
565 (Lisp_Object watch_descriptor) 572 (Lisp_Object watch_descriptor)
566{ 573{
567 Lisp_Object watch_object; 574 Lisp_Object watch_object;
568 HANDLE hdir = (HANDLE)XINT (watch_descriptor); 575 struct notification *dirwatch =
576 (struct notification *)XINT (watch_descriptor);
569 577
570 if (remove_watch (hdir) == -1) 578 /* Remove the watch object from watch list. Do this before freeing
571 report_file_error ("Could not remove watch", Fcons (watch_descriptor, 579 the object, do that even if we fail to free it, watch_list is
572 Qnil)); 580 kept free of junk. */
573
574 /* Remove watch descriptor from watch list. */
575 watch_object = Fassoc (watch_descriptor, watch_list); 581 watch_object = Fassoc (watch_descriptor, watch_list);
576 if (!NILP (watch_object)) 582 if (!NILP (watch_object))
577 watch_list = Fdelete (watch_object, watch_list); 583 watch_list = Fdelete (watch_object, watch_list);
578 584
585 if (remove_watch (dirwatch) == -1)
586 report_file_error ("Invalid watch descriptor", Fcons (watch_descriptor,
587 Qnil));
588
579 return Qnil; 589 return Qnil;
580} 590}
581 591
582Lisp_Object 592Lisp_Object
583get_watch_object (Lisp_Object desc) 593w32_get_watch_object (Lisp_Object desc)
594{
595 return NILP (watch_list) ? Qnil : assoc_no_quit (desc, watch_list);
596}
597
598void
599globals_of_w32notify (void)
584{ 600{
585 return Fassoc (desc, watch_list); 601 watch_list = Qnil;
586} 602}
587 603
588void 604void
diff --git a/src/w32term.c b/src/w32term.c
index 6d19d9a93ce..1285b5a06f6 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -3282,7 +3282,7 @@ queue_notifications (struct input_event *event, W32Msg *msg, struct frame *f,
3282 { 3282 {
3283 DWORD info_size = notifications_size; 3283 DWORD info_size = notifications_size;
3284 Lisp_Object cs = intern ("utf-16le"); 3284 Lisp_Object cs = intern ("utf-16le");
3285 Lisp_Object obj = get_watch_object (make_number (notifications_desc)); 3285 Lisp_Object obj = w32_get_watch_object (make_number (notifications_desc));
3286 3286
3287 /* notifications_size could be zero when the buffer of 3287 /* notifications_size could be zero when the buffer of
3288 notifications overflowed on the OS level, or when the 3288 notifications overflowed on the OS level, or when the
diff --git a/src/w32term.h b/src/w32term.h
index a3579c8ff60..91723c3758a 100644
--- a/src/w32term.h
+++ b/src/w32term.h
@@ -685,8 +685,8 @@ extern void x_delete_display (struct w32_display_info *dpyinfo);
685extern int notification_buffer_in_use; 685extern int notification_buffer_in_use;
686extern BYTE file_notifications[16384]; 686extern BYTE file_notifications[16384];
687extern DWORD notifications_size; 687extern DWORD notifications_size;
688extern HANDLE notifications_desc; 688extern void *notifications_desc;
689extern Lisp_Object get_watch_object (Lisp_Object); 689extern Lisp_Object w32_get_watch_object (Lisp_Object);
690extern Lisp_Object lispy_file_action (DWORD); 690extern Lisp_Object lispy_file_action (DWORD);
691 691
692/* Keypad command key support. W32 doesn't have virtual keys defined 692/* Keypad command key support. W32 doesn't have virtual keys defined
@@ -767,6 +767,7 @@ extern void syms_of_w32fns (void);
767 767
768extern void globals_of_w32menu (void); 768extern void globals_of_w32menu (void);
769extern void globals_of_w32fns (void); 769extern void globals_of_w32fns (void);
770extern void globals_of_w32notify (void);
770 771
771#ifdef CYGWIN 772#ifdef CYGWIN
772extern int w32_message_fd; 773extern int w32_message_fd;