diff options
author | Fabrice Popineau <fabrice.popineau@gmail.com> | 2016-03-19 14:44:53 +0200 |
---|---|---|
committer | Eli Zaretskii <eliz@gnu.org> | 2016-03-19 14:44:53 +0200 |
commit | 326fff41fa9f674d80be00b5c97c44f8043bbace (patch) | |
tree | 15f5e2fb315130ce923970d16a96c8e951914857 /src/w32inevt.c | |
parent | 2fbdb1bb4c878f8ae17bd69d1b4ff51c47497e41 (diff) | |
download | emacs-326fff41fa9f674d80be00b5c97c44f8043bbace.tar.gz |
Improve w32notify notifications
* src/w32notify.c (DIRWATCH_BUFFER_SIZE): New macro.
(struct notification): 'terminate' is now a HANDLE.
(send_notifications): Argument is now a pointer to a
notification. Don't loop waiting for the notification to be
acknowledged by the main thread; instead, just add the
notification to the linked list of notifications waiting to be
acknowledged.
(watch_end): Don't close the directory handle.
(watch_completion): Allocate a new notification structure to be
added to the notifications set. Call ReadDirectoryChangesW
immediately after adding the new notification, and before sending
a message to the main thread about them.
(watch_worker): Don't loop calling ReadDirectoryChangesW; instead,
call it just once -- it will be called again in watch_completion.
Loop waiting for the main thread's indication to terminate.
(start_watching): Create the event to be used to indicate to the
worker thread that its should terminate.
(remove_watch): Indicate to the worker thread that it should
terminate.
* src/w32term.c (queue_notifications): Loop over all the
notifications in the linked list, processing all of them in one
go.
* src/w32inevt.c (handle_file_notifications): Loop over all the
notifications in the linked list.
* src/w32xfns.c (init_crit): Initialize the linked list of file
notifications.
(delete_crit): Free the linked list of file notifications,
including any unprocessed notifications left in it.
* src/w32term.h (struct notifications_se): New struct.
* test/lisp/filenotify-tests.el (file-notify-test02-events)
(file-notify-test05-dir-validity): Add read-event calls to
facilitate event recognition by the main thread in batch mode.
Diffstat (limited to 'src/w32inevt.c')
-rw-r--r-- | src/w32inevt.c | 115 |
1 files changed, 67 insertions, 48 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) int handle_file_notifications (struct input_event *hold_quit) { - BYTE *p = file_notifications; - FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p; - const DWORD min_size - = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t); - struct input_event inev; + struct notifications_set *ns = NULL; int nevents = 0; + int done = 0; /* We cannot process notification before Emacs is fully initialized, since we need the UTF-16LE coding-system to be set up. */ if (!initialized) { - notification_buffer_in_use = 0; return nevents; } - enter_crit (); - if (notification_buffer_in_use) + while (!done) { - DWORD info_size = notifications_size; - Lisp_Object cs = Qutf_16le; - Lisp_Object obj = w32_get_watch_object (notifications_desc); - - /* notifications_size could be zero when the buffer of - notifications overflowed on the OS level, or when the - directory being watched was itself deleted. Do nothing in - that case. */ - if (info_size - && !NILP (obj) && CONSP (obj)) - { - Lisp_Object callback = XCDR (obj); + ns = NULL; - EVENT_INIT (inev); + /* Find out if there is a record available in the linked list of + notifications sets. If so, unlink te set from the linked list. + Use the critical section. */ + enter_crit (); + if (notifications_set_head->next != notifications_set_head) + { + ns = notifications_set_head->next; + ns->prev->next = ns->next; + ns->next->prev = ns->prev; + } + else + done = 1; + leave_crit(); - while (info_size >= min_size) + if (ns) + { + BYTE *p = ns->notifications; + FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p; + const DWORD min_size + = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t); + struct input_event inev; + DWORD info_size = ns->size; + Lisp_Object cs = Qutf_16le; + Lisp_Object obj = w32_get_watch_object (ns->desc); + + /* notifications size could be zero when the buffer of + notifications overflowed on the OS level, or when the + directory being watched was itself deleted. Do nothing in + that case. */ + if (info_size + && !NILP (obj) && CONSP (obj)) { - Lisp_Object utf_16_fn - = make_unibyte_string ((char *)fni->FileName, - fni->FileNameLength); - /* Note: mule-conf is preloaded, so utf-16le must - already be defined at this point. */ - Lisp_Object fname - = code_convert_string_norecord (utf_16_fn, cs, 0); - Lisp_Object action = lispy_file_action (fni->Action); - - inev.kind = FILE_NOTIFY_EVENT; - inev.timestamp = GetTickCount (); - inev.modifiers = 0; - inev.frame_or_window = callback; - inev.arg = Fcons (action, fname); - inev.arg = list3 (make_pointer_integer (notifications_desc), - action, fname); - kbd_buffer_store_event_hold (&inev, hold_quit); - nevents++; - - if (!fni->NextEntryOffset) - break; - p += fni->NextEntryOffset; - fni = (PFILE_NOTIFY_INFORMATION)p; - info_size -= fni->NextEntryOffset; + Lisp_Object callback = XCDR (obj); + + EVENT_INIT (inev); + + while (info_size >= min_size) + { + Lisp_Object utf_16_fn + = make_unibyte_string ((char *)fni->FileName, + fni->FileNameLength); + /* Note: mule-conf is preloaded, so utf-16le must + already be defined at this point. */ + Lisp_Object fname + = code_convert_string_norecord (utf_16_fn, cs, 0); + Lisp_Object action = lispy_file_action (fni->Action); + + inev.kind = FILE_NOTIFY_EVENT; + inev.timestamp = GetTickCount (); + inev.modifiers = 0; + inev.frame_or_window = callback; + inev.arg = Fcons (action, fname); + inev.arg = list3 (make_pointer_integer (ns->desc), + action, fname); + kbd_buffer_store_event_hold (&inev, hold_quit); + nevents++; + if (!fni->NextEntryOffset) + break; + p += fni->NextEntryOffset; + fni = (PFILE_NOTIFY_INFORMATION)p; + info_size -= fni->NextEntryOffset; + } } + /* Free this notification set. */ + free (ns->notifications); + free (ns); } - notification_buffer_in_use = 0; } - leave_crit (); return nevents; } #else /* !HAVE_W32NOTIFY */ |