/* Signal to the main thread that we have file notifications for it to process. */ static void send_notifications (BYTE *info, DWORD info_size, void *desc, volatile int *terminate) { int done = 0; struct frame *f = SELECTED_FRAME (); /* A single buffer is used to communicate all notifications to the main thread. Since both the main thread and several watcher threads could be active at the same time, we use a critical area and an "in-use" flag to synchronize them. A watcher thread can only put its notifications in the buffer if it acquires the critical area and finds the "in-use" flag reset. The main thread resets the flag after it is done processing notifications. FIXME: is there a better way of dealing with this? */ while (!done && !*terminate) { enter_crit (); if (!notification_buffer_in_use) { if (info_size) memcpy (file_notifications, info, min (info_size, sizeof (file_notifications))); notifications_size = min (info_size, sizeof (file_notifications)); notifications_desc = desc; /* If PostMessage fails, the message queue is full. If that happens, the last thing they will worry about is file notifications. So we effectively discard the notification in that case. */ if ((FRAME_TERMCAP_P (f) /* We send the message to the main (a.k.a. "Lisp") thread, where it will wake up MsgWaitForMultipleObjects inside sys_select, causing it to report that there's some keyboard input available. This will in turn cause w32_console_read_socket to be called, which will pick up the file notifications. */ && PostThreadMessage (dwMainThreadId, WM_EMACS_FILENOTIFY, 0, 0)) || (FRAME_W32_P (f) && PostMessage (FRAME_W32_WINDOW (f), WM_EMACS_FILENOTIFY, 0, 0)) /* When we are running in batch mode, there's no one to send a message, so we just signal the data is available and hope sys_select will be called soon and will read the data. */ || (FRAME_INITIAL_P (f) && noninteractive)) notification_buffer_in_use = 1; done = 1; } leave_crit (); if (!done) Sleep (5); } }
/* Signal to the main thread that we have file notifications for it to process. */ static void send_notifications (struct notifications_set *ns) { struct frame *f = SELECTED_FRAME (); /* We add the current notification set to the linked list. Use the critical section to make sure only one thread will access the linked list. */ enter_crit (); ns->next = notifications_set_head; ns->prev = notifications_set_head->prev; ns->prev->next = ns; notifications_set_head->prev = ns; leave_crit(); /* If PostMessage fails, the message queue is full. If that happens, the last thing they will worry about is file notifications. So we effectively discard the notification in that case. */ if (FRAME_TERMCAP_P (f)) /* We send the message to the main (a.k.a. "Lisp") thread, where it will wake up MsgWaitForMultipleObjects inside sys_select, causing it to report that there's some keyboard input available. This will in turn cause w32_console_read_socket to be called, which will pick up the file notifications. */ PostThreadMessage (dwMainThreadId, WM_EMACS_FILENOTIFY, 0, 0); else if (FRAME_W32_P (f)) PostMessage (FRAME_W32_WINDOW (f), WM_EMACS_FILENOTIFY, 0, 0); /* When we are running in batch mode, there's no one to send a message, so we just signal the data is available and hope sys_select will be called soon and will read the data. */ #if 0 else if (FRAME_INITIAL_P (f) && noninteractive) ; #endif }
static 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; int nevents = 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) { DWORD info_size = notifications_size; Lisp_Object cs = intern ("utf-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); 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.code = (ptrdiff_t)XINT (XIL ((EMACS_INT)notifications_desc)); inev.timestamp = GetTickCount (); inev.modifiers = 0; inev.frame_or_window = callback; inev.arg = Fcons (action, fname); kbd_buffer_store_event_hold (&inev, hold_quit); if (!fni->NextEntryOffset) break; p += fni->NextEntryOffset; fni = (PFILE_NOTIFY_INFORMATION)p; info_size -= fni->NextEntryOffset; } } notification_buffer_in_use = 0; } leave_crit (); return nevents; }
int handle_file_notifications (struct input_event *hold_quit) { 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) { return nevents; } while (!done) { ns = NULL; /* 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(); 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 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); } } return nevents; }