aboutsummaryrefslogtreecommitdiffstats
path: root/src/kqueue.c
diff options
context:
space:
mode:
authorMichael Albinus2015-11-09 10:00:56 +0100
committerMichael Albinus2015-11-25 15:07:10 +0100
commite3354e2265bc442e4c7b84b806be482db88581a2 (patch)
tree21c79b24540c150ada3fe3b7c7941985327cc16f /src/kqueue.c
parentc6457cef92342d586d894504fdefc1bec1367725 (diff)
downloademacs-e3354e2265bc442e4c7b84b806be482db88581a2.tar.gz
emacs-e3354e2265bc442e4c7b84b806be482db88581a2.zip
Add kqueue support
* configure.ac (--with-file-notification): Add kqueue. (top): Remove special test for "${HAVE_NS}" and ${with_file_notification}, this is handled inside gfilenotify tests. Add kqueue tests. Use NOTIFY_CFLAGS and NOTIFY_LIBS instead of library specific variables. * src/Makefile.in: Use NOTIFY_CFLAGS and NOTIFY_LIBS. * src/emacs.c (main): Call globals_of_kqueue and syms_of_kqueue. * src/kqueue.c: New file. * src/lisp.h: Declare extern globals_of_kqueue and syms_of_kqueue.
Diffstat (limited to 'src/kqueue.c')
-rw-r--r--src/kqueue.c339
1 files changed, 339 insertions, 0 deletions
diff --git a/src/kqueue.c b/src/kqueue.c
new file mode 100644
index 00000000000..69bf5f61080
--- /dev/null
+++ b/src/kqueue.c
@@ -0,0 +1,339 @@
1/* Filesystem notifications support with glib API.
2 Copyright (C) 2013-2015 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#ifdef HAVE_KQUEUE
22#include <stdio.h>
23#include <sys/event.h>
24#include "lisp.h"
25#include "coding.h"
26#include "termhooks.h"
27#include "keyboard.h"
28
29
30/* File handle for kqueue. */
31static int kqueuefd = -1;
32
33/* This is a list, elements are triples (DESCRIPTOR FILE FLAGS CALLBACK) */
34static Lisp_Object watch_list;
35
36#if 0
37/* This is the callback function for arriving signals from
38 g_file_monitor. It shall create a Lisp event, and put it into
39 Emacs input queue. */
40static gboolean
41dir_monitor_callback (GFileMonitor *monitor,
42 GFile *file,
43 GFile *other_file,
44 GFileMonitorEvent event_type,
45 gpointer user_data)
46{
47 Lisp_Object symbol, monitor_object, watch_object, flags;
48 char *name = g_file_get_parse_name (file);
49 char *oname = other_file ? g_file_get_parse_name (other_file) : NULL;
50
51 /* Determine event symbol. */
52 switch (event_type)
53 {
54 case G_FILE_MONITOR_EVENT_CHANGED:
55 symbol = Qchanged;
56 break;
57 case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
58 symbol = Qchanges_done_hint;
59 break;
60 case G_FILE_MONITOR_EVENT_DELETED:
61 symbol = Qdeleted;
62 break;
63 case G_FILE_MONITOR_EVENT_CREATED:
64 symbol = Qcreated;
65 break;
66 case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
67 symbol = Qattribute_changed;
68 break;
69 case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
70 symbol = Qpre_unmount;
71 break;
72 case G_FILE_MONITOR_EVENT_UNMOUNTED:
73 symbol = Qunmounted;
74 break;
75 case G_FILE_MONITOR_EVENT_MOVED:
76 symbol = Qmoved;
77 break;
78 default:
79 goto cleanup;
80 }
81
82 /* Determine callback function. */
83 monitor_object = make_pointer_integer (monitor);
84 eassert (INTEGERP (monitor_object));
85 watch_object = assq_no_quit (monitor_object, watch_list);
86
87 if (CONSP (watch_object))
88 {
89 struct input_event event;
90 Lisp_Object otail = oname ? list1 (build_string (oname)) : Qnil;
91
92 /* Check, whether event_type is expected. */
93 flags = XCAR (XCDR (XCDR (watch_object)));
94 if ((!NILP (Fmember (Qchange, flags)) &&
95 !NILP (Fmember (symbol, list5 (Qchanged, Qchanges_done_hint,
96 Qdeleted, Qcreated, Qmoved)))) ||
97 (!NILP (Fmember (Qattribute_change, flags)) &&
98 ((EQ (symbol, Qattribute_changed)))))
99 {
100 /* Construct an event. */
101 EVENT_INIT (event);
102 event.kind = FILE_NOTIFY_EVENT;
103 event.frame_or_window = Qnil;
104 event.arg = list2 (Fcons (monitor_object,
105 Fcons (symbol,
106 Fcons (build_string (name),
107 otail))),
108 XCAR (XCDR (XCDR (XCDR (watch_object)))));
109
110 /* Store it into the input event queue. */
111 kbd_buffer_store_event (&event);
112 // XD_DEBUG_MESSAGE ("%s", XD_OBJECT_TO_STRING (event.arg));
113 }
114
115 /* Cancel monitor if file or directory is deleted. */
116 if (!NILP (Fmember (symbol, list2 (Qdeleted, Qmoved))) &&
117 (strcmp (name, SSDATA (XCAR (XCDR (watch_object)))) == 0) &&
118 !g_file_monitor_is_cancelled (monitor))
119 g_file_monitor_cancel (monitor);
120 }
121
122 /* Cleanup. */
123 cleanup:
124 g_free (name);
125 g_free (oname);
126
127 return TRUE;
128}
129#endif /* 0 */
130
131DEFUN ("kqueue-add-watch", Fkqueue_add_watch, Skqueue_add_watch, 3, 3, 0,
132 doc: /* Add a watch for filesystem events pertaining to FILE.
133
134This arranges for filesystem events pertaining to FILE to be reported
135to Emacs. Use `gfile-rm-watch' to cancel the watch.
136
137Value is a descriptor for the added watch. If the file cannot be
138watched for some reason, this function signals a `file-notify-error' error.
139
140FLAGS is a list of conditions to set what will be watched for. It can
141include the following symbols:
142
143 `change' -- watch for file changes
144 `attribute-change' -- watch for file attributes changes, like
145 permissions or modification time
146 `watch-mounts' -- watch for mount events
147 `send-moved' -- pair `deleted' and `created' events caused by
148 file renames and send a single `renamed' event
149 instead
150
151When any event happens, Emacs will call the CALLBACK function passing
152it a single argument EVENT, which is of the form
153
154 (DESCRIPTOR ACTION FILE [FILE1])
155
156DESCRIPTOR is the same object as the one returned by this function.
157ACTION is the description of the event. It could be any one of the
158following:
159
160 `changed' -- FILE has changed
161 `changes-done-hint' -- a hint that this was probably the last change
162 in a set of changes
163 `deleted' -- FILE was deleted
164 `created' -- FILE was created
165 `attribute-changed' -- a FILE attribute was changed
166 `pre-unmount' -- the FILE location will soon be unmounted
167 `unmounted' -- the FILE location was unmounted
168 `moved' -- FILE was moved to FILE1
169
170FILE is the name of the file whose event is being reported. FILE1
171will be reported only in case of the `moved' event. */)
172 (Lisp_Object file, Lisp_Object flags, Lisp_Object callback)
173{
174 Lisp_Object watch_object;
175 GFile *gfile;
176 GFileMonitor *monitor;
177 GFileMonitorFlags gflags = G_FILE_MONITOR_NONE;
178 GError *gerror = NULL;
179
180 /* Check parameters. */
181 CHECK_STRING (file);
182 file = Fdirectory_file_name (Fexpand_file_name (file, Qnil));
183 if (NILP (Ffile_exists_p (file)))
184 report_file_error ("File does not exist", file);
185
186 CHECK_LIST (flags);
187
188 if (!FUNCTIONP (callback))
189 wrong_type_argument (Qinvalid_function, callback);
190
191 /* Create GFile name. */
192 // gfile = g_file_new_for_path (SSDATA (ENCODE_FILE (file)));
193
194 /* Assemble flags. */
195 // if (!NILP (Fmember (Qwatch_mounts, flags)))
196 // gflags |= G_FILE_MONITOR_WATCH_MOUNTS;
197 // if (!NILP (Fmember (Qsend_moved, flags)))
198 // gflags |= G_FILE_MONITOR_SEND_MOVED;
199
200 if (kqueuefd < 0)
201 {
202 kqueuefd = kqueue ();
203 if (kqueuefd < 0)
204 report_file_notify_error ("File watching is not available", Qnil);
205 watch_list = Qnil;
206 // add_read_fd (inotifyfd, &inotify_callback, NULL);
207 }
208
209
210}
211#if 0
212
213 mask = aspect_to_inotifymask (aspect);
214 encoded_file_name = ENCODE_FILE (file_name);
215 watchdesc = inotify_add_watch (inotifyfd, SSDATA (encoded_file_name), mask);
216 if (watchdesc == -1)
217 report_file_notify_error ("Could not add watch for file", file_name);
218
219 /* Enable watch. */
220 monitor = g_file_monitor (gfile, gflags, NULL, &gerror);
221 g_object_unref (gfile);
222 if (gerror)
223 {
224 char msg[1024];
225 strcpy (msg, gerror->message);
226 g_error_free (gerror);
227 xsignal1 (Qfile_notify_error, build_string (msg));
228 }
229 if (! monitor)
230 xsignal2 (Qfile_notify_error, build_string ("Cannot watch file"), file);
231
232 Lisp_Object watch_descriptor = make_pointer_integer (monitor);
233
234 /* Check the dicey assumption that make_pointer_integer is safe. */
235 if (! INTEGERP (watch_descriptor))
236 {
237 g_object_unref (monitor);
238 xsignal2 (Qfile_notify_error, build_string ("Unsupported file watcher"),
239 file);
240 }
241
242 /* The default rate limit is 800 msec. We adapt this. */
243 g_file_monitor_set_rate_limit (monitor, 100);
244
245 /* Subscribe to the "changed" signal. */
246 g_signal_connect (monitor, "changed",
247 (GCallback) dir_monitor_callback, NULL);
248
249 /* Store watch object in watch list. */
250 watch_object = list4 (watch_descriptor, file, flags, callback);
251 watch_list = Fcons (watch_object, watch_list);
252
253 return watch_descriptor;
254}
255
256DEFUN ("gfile-rm-watch", Fgfile_rm_watch, Sgfile_rm_watch, 1, 1, 0,
257 doc: /* Remove an existing WATCH-DESCRIPTOR.
258
259WATCH-DESCRIPTOR should be an object returned by `gfile-add-watch'. */)
260 (Lisp_Object watch_descriptor)
261{
262 Lisp_Object watch_object = assq_no_quit (watch_descriptor, watch_list);
263
264 if (! CONSP (watch_object))
265 xsignal2 (Qfile_notify_error, build_string ("Not a watch descriptor"),
266 watch_descriptor);
267
268 eassert (INTEGERP (watch_descriptor));
269 GFileMonitor *monitor = XINTPTR (watch_descriptor);
270 if (!g_file_monitor_is_cancelled (monitor) &&
271 !g_file_monitor_cancel (monitor))
272 xsignal2 (Qfile_notify_error, build_string ("Could not rm watch"),
273 watch_descriptor);
274
275 /* Remove watch descriptor from watch list. */
276 watch_list = Fdelq (watch_object, watch_list);
277
278 /* Cleanup. */
279 g_object_unref (monitor);
280
281 return Qt;
282}
283
284DEFUN ("gfile-valid-p", Fgfile_valid_p, Sgfile_valid_p, 1, 1, 0,
285 doc: /* "Check a watch specified by its WATCH-DESCRIPTOR.
286
287WATCH-DESCRIPTOR should be an object returned by `gfile-add-watch'.
288
289A watch can become invalid if the file or directory it watches is
290deleted, or if the watcher thread exits abnormally for any other
291reason. Removing the watch by calling `gfile-rm-watch' also makes it
292invalid. */)
293 (Lisp_Object watch_descriptor)
294{
295 Lisp_Object watch_object = Fassoc (watch_descriptor, watch_list);
296 if (NILP (watch_object))
297 return Qnil;
298 else
299 {
300 GFileMonitor *monitor = XINTPTR (watch_descriptor);
301 return g_file_monitor_is_cancelled (monitor) ? Qnil : Qt;
302 }
303}
304#endif /* 0 */
305
306
307void
308globals_of_kqueue (void)
309{
310 watch_list = Qnil;
311}
312
313void
314syms_of_kqueue (void)
315{
316 defsubr (&Skqueue_add_watch);
317 // defsubr (&Skqueue_rm_watch);
318 // defsubr (&Skqueue_valid_p);
319
320 /* Filter objects. */
321 DEFSYM (Qchange, "change");
322 DEFSYM (Qattribute_change, "attribute-change");
323 DEFSYM (Qwatch_mounts, "watch-mounts"); /* G_FILE_MONITOR_WATCH_MOUNTS */
324 DEFSYM (Qsend_moved, "send-moved"); /* G_FILE_MONITOR_SEND_MOVED */
325
326 /* Event types. */
327 DEFSYM (Qdelete, "delete"); /* NOTE_DELETE */
328 DEFSYM (Qwrite, "write"); /* NOTE_WRITE */
329 DEFSYM (Qextend, "extend"); /* NOTE_EXTEND */
330 DEFSYM (Qattrib, "attrib"); /* NOTE_ATTRIB */
331 DEFSYM (Qlink, "link"); /* NOTE_LINK */
332 DEFSYM (Qrename, "rename"); /* NOTE_RENAME */
333
334 staticpro (&watch_list);
335
336 Fprovide (intern_c_string ("kqueue"), Qnil);
337}
338
339#endif /* HAVE_KQUEUE */