diff options
| author | Michael Albinus | 2015-11-11 09:22:06 +0100 |
|---|---|---|
| committer | Michael Albinus | 2015-11-25 15:07:11 +0100 |
| commit | e0a68f25877c9b2497d7c4ad0aa1b69e34a3b11f (patch) | |
| tree | 0e8ef95ac11a1ad0b4869b1e43978e1343b65182 /src/kqueue.c | |
| parent | 7543d1cf46e475bd14a147ef676abe3935a8f96e (diff) | |
| download | emacs-e0a68f25877c9b2497d7c4ad0aa1b69e34a3b11f.tar.gz emacs-e0a68f25877c9b2497d7c4ad0aa1b69e34a3b11f.zip | |
Continue kqueue implementation
* lisp/filenotify.el (file-notify-handle-event)
(file-notify-callback): Enable trace messages.
* src/kqueue.c: Include also <sys/types.h>.
(kqueue_callback): Remove watch in case of NOTE_DELETE or NOTE_RENAME.
(Fkqueue_rm_watch, Fkqueue_valid_p): New functions.
(syms_of_kqueue): Add them.
Diffstat (limited to 'src/kqueue.c')
| -rw-r--r-- | src/kqueue.c | 80 |
1 files changed, 41 insertions, 39 deletions
diff --git a/src/kqueue.c b/src/kqueue.c index a4c3892e9f2..c2e859f8db9 100644 --- a/src/kqueue.c +++ b/src/kqueue.c | |||
| @@ -20,6 +20,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 20 | 20 | ||
| 21 | #ifdef HAVE_KQUEUE | 21 | #ifdef HAVE_KQUEUE |
| 22 | #include <stdio.h> | 22 | #include <stdio.h> |
| 23 | #include <sys/types.h> | ||
| 23 | #include <sys/event.h> | 24 | #include <sys/event.h> |
| 24 | #include <sys/file.h> | 25 | #include <sys/file.h> |
| 25 | #include "lisp.h" | 26 | #include "lisp.h" |
| @@ -41,9 +42,9 @@ kqueue_callback (int fd, void *data) | |||
| 41 | for (;;) { | 42 | for (;;) { |
| 42 | struct kevent kev; | 43 | struct kevent kev; |
| 43 | struct input_event event; | 44 | struct input_event event; |
| 44 | Lisp_Object monitor_object, watch_object, name, callback, actions; | 45 | Lisp_Object monitor_object, watch_object, file, callback, actions; |
| 45 | 46 | ||
| 46 | static const struct timespec nullts = { 0, 0 }; | 47 | /* Read one event. */ |
| 47 | int ret = kevent (kqueuefd, NULL, 0, &kev, 1, NULL); | 48 | int ret = kevent (kqueuefd, NULL, 0, &kev, 1, NULL); |
| 48 | if (ret < 1) { | 49 | if (ret < 1) { |
| 49 | /* All events read. */ | 50 | /* All events read. */ |
| @@ -55,7 +56,7 @@ kqueue_callback (int fd, void *data) | |||
| 55 | watch_object = assq_no_quit (monitor_object, watch_list); | 56 | watch_object = assq_no_quit (monitor_object, watch_list); |
| 56 | 57 | ||
| 57 | if (CONSP (watch_object)) { | 58 | if (CONSP (watch_object)) { |
| 58 | name = XCAR (XCDR (watch_object)); | 59 | file = XCAR (XCDR (watch_object)); |
| 59 | callback = XCAR (XCDR (XCDR (XCDR (watch_object)))); | 60 | callback = XCAR (XCDR (XCDR (XCDR (watch_object)))); |
| 60 | } | 61 | } |
| 61 | else | 62 | else |
| @@ -76,13 +77,13 @@ kqueue_callback (int fd, void *data) | |||
| 76 | if (kev.fflags & NOTE_RENAME) | 77 | if (kev.fflags & NOTE_RENAME) |
| 77 | actions = Fcons (Qrename, actions); | 78 | actions = Fcons (Qrename, actions); |
| 78 | 79 | ||
| 79 | if (!NILP (actions)) { | 80 | if (! NILP (actions)) { |
| 80 | /* Construct an event. */ | 81 | /* Construct an event. */ |
| 81 | EVENT_INIT (event); | 82 | EVENT_INIT (event); |
| 82 | event.kind = FILE_NOTIFY_EVENT; | 83 | event.kind = FILE_NOTIFY_EVENT; |
| 83 | event.frame_or_window = Qnil; | 84 | event.frame_or_window = Qnil; |
| 84 | event.arg = list2 (Fcons (monitor_object, | 85 | event.arg = list2 (Fcons (monitor_object, |
| 85 | Fcons (actions, Fcons (name, Qnil))), | 86 | Fcons (actions, Fcons (file, Qnil))), |
| 86 | callback); | 87 | callback); |
| 87 | 88 | ||
| 88 | /* Store it into the input event queue. */ | 89 | /* Store it into the input event queue. */ |
| @@ -90,7 +91,8 @@ kqueue_callback (int fd, void *data) | |||
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | /* Cancel monitor if file or directory is deleted. */ | 93 | /* Cancel monitor if file or directory is deleted. */ |
| 93 | /* TODO: Implement it. */ | 94 | if (kev.fflags & (NOTE_DELETE | NOTE_RENAME)) |
| 95 | Fkqueue_rm_watch (monitor_object); | ||
| 94 | } | 96 | } |
| 95 | return; | 97 | return; |
| 96 | } | 98 | } |
| @@ -101,7 +103,7 @@ DEFUN ("kqueue-add-watch", Fkqueue_add_watch, Skqueue_add_watch, 3, 3, 0, | |||
| 101 | This arranges for filesystem events pertaining to FILE to be reported | 103 | This arranges for filesystem events pertaining to FILE to be reported |
| 102 | to Emacs. Use `kqueue-rm-watch' to cancel the watch. | 104 | to Emacs. Use `kqueue-rm-watch' to cancel the watch. |
| 103 | 105 | ||
| 104 | Value is a descriptor for the added watch. If the file cannot be | 106 | Returned value is a descriptor for the added watch. If the file cannot be |
| 105 | watched for some reason, this function signals a `file-notify-error' error. | 107 | watched for some reason, this function signals a `file-notify-error' error. |
| 106 | 108 | ||
| 107 | FLAGS is a list of events to be watched for. It can include the | 109 | FLAGS is a list of events to be watched for. It can include the |
| @@ -138,12 +140,12 @@ will be reported only in case of the `rename' event. */) | |||
| 138 | report_file_error ("File does not exist", file); | 140 | report_file_error ("File does not exist", file); |
| 139 | 141 | ||
| 140 | /* TODO: Directories shall be supported as well. */ | 142 | /* TODO: Directories shall be supported as well. */ |
| 141 | if (!NILP (Ffile_directory_p (file))) | 143 | if (! NILP (Ffile_directory_p (file))) |
| 142 | report_file_error ("Directory watching is not supported (yet)", file); | 144 | report_file_error ("Directory watching is not supported (yet)", file); |
| 143 | 145 | ||
| 144 | CHECK_LIST (flags); | 146 | CHECK_LIST (flags); |
| 145 | 147 | ||
| 146 | if (!FUNCTIONP (callback)) | 148 | if (! FUNCTIONP (callback)) |
| 147 | wrong_type_argument (Qinvalid_function, callback); | 149 | wrong_type_argument (Qinvalid_function, callback); |
| 148 | 150 | ||
| 149 | if (kqueuefd < 0) | 151 | if (kqueuefd < 0) |
| @@ -166,16 +168,16 @@ will be reported only in case of the `rename' event. */) | |||
| 166 | report_file_error ("File cannot be opened", file); | 168 | report_file_error ("File cannot be opened", file); |
| 167 | 169 | ||
| 168 | /* Assemble filter flags */ | 170 | /* Assemble filter flags */ |
| 169 | if (!NILP (Fmember (Qdelete, flags))) fflags |= NOTE_DELETE; | 171 | if (! NILP (Fmember (Qdelete, flags))) fflags |= NOTE_DELETE; |
| 170 | if (!NILP (Fmember (Qwrite, flags))) fflags |= NOTE_WRITE; | 172 | if (! NILP (Fmember (Qwrite, flags))) fflags |= NOTE_WRITE; |
| 171 | if (!NILP (Fmember (Qextend, flags))) fflags |= NOTE_EXTEND; | 173 | if (! NILP (Fmember (Qextend, flags))) fflags |= NOTE_EXTEND; |
| 172 | if (!NILP (Fmember (Qattrib, flags))) fflags |= NOTE_ATTRIB; | 174 | if (! NILP (Fmember (Qattrib, flags))) fflags |= NOTE_ATTRIB; |
| 173 | if (!NILP (Fmember (Qlink, flags))) fflags |= NOTE_LINK; | 175 | if (! NILP (Fmember (Qlink, flags))) fflags |= NOTE_LINK; |
| 174 | if (!NILP (Fmember (Qrename, flags))) fflags |= NOTE_RENAME; | 176 | if (! NILP (Fmember (Qrename, flags))) fflags |= NOTE_RENAME; |
| 175 | 177 | ||
| 176 | /* Register event. */ | 178 | /* Register event. */ |
| 177 | EV_SET (&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, | 179 | EV_SET (&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, |
| 178 | fflags, 0, NULL); | 180 | fflags, 0, NULL); |
| 179 | 181 | ||
| 180 | if (kevent (kqueuefd, &ev, 1, NULL, 0, NULL) < 0) | 182 | if (kevent (kqueuefd, &ev, 1, NULL, 0, NULL) < 0) |
| 181 | report_file_error ("Cannot watch file", file); | 183 | report_file_error ("Cannot watch file", file); |
| @@ -188,7 +190,6 @@ will be reported only in case of the `rename' event. */) | |||
| 188 | return watch_descriptor; | 190 | return watch_descriptor; |
| 189 | } | 191 | } |
| 190 | 192 | ||
| 191 | #if 0 | ||
| 192 | DEFUN ("kqueue-rm-watch", Fkqueue_rm_watch, Skqueue_rm_watch, 1, 1, 0, | 193 | DEFUN ("kqueue-rm-watch", Fkqueue_rm_watch, Skqueue_rm_watch, 1, 1, 0, |
| 193 | doc: /* Remove an existing WATCH-DESCRIPTOR. | 194 | doc: /* Remove an existing WATCH-DESCRIPTOR. |
| 194 | 195 | ||
| @@ -202,42 +203,35 @@ WATCH-DESCRIPTOR should be an object returned by `kqueue-add-watch'. */) | |||
| 202 | watch_descriptor); | 203 | watch_descriptor); |
| 203 | 204 | ||
| 204 | eassert (INTEGERP (watch_descriptor)); | 205 | eassert (INTEGERP (watch_descriptor)); |
| 205 | GFileMonitor *monitor = XINTPTR (watch_descriptor); | 206 | int fd = XINT (watch_descriptor); |
| 206 | if (!g_file_monitor_is_cancelled (monitor) && | 207 | if ( fd >= 0) |
| 207 | !g_file_monitor_cancel (monitor)) | 208 | emacs_close (fd); |
| 208 | xsignal2 (Qfile_notify_error, build_string ("Could not rm watch"), | ||
| 209 | watch_descriptor); | ||
| 210 | 209 | ||
| 211 | /* Remove watch descriptor from watch list. */ | 210 | /* Remove watch descriptor from watch list. */ |
| 212 | watch_list = Fdelq (watch_object, watch_list); | 211 | watch_list = Fdelq (watch_object, watch_list); |
| 213 | 212 | ||
| 214 | /* Cleanup. */ | 213 | if (NILP (watch_list) && (kqueuefd >= 0)) { |
| 215 | g_object_unref (monitor); | 214 | delete_read_fd (kqueuefd); |
| 215 | emacs_close (kqueuefd); | ||
| 216 | kqueuefd = -1; | ||
| 217 | } | ||
| 216 | 218 | ||
| 217 | return Qt; | 219 | return Qt; |
| 218 | } | 220 | } |
| 219 | 221 | ||
| 220 | DEFUN ("gfile-valid-p", Fgfile_valid_p, Sgfile_valid_p, 1, 1, 0, | 222 | DEFUN ("kqueue-valid-p", Fkqueue_valid_p, Skqueue_valid_p, 1, 1, 0, |
| 221 | doc: /* "Check a watch specified by its WATCH-DESCRIPTOR. | 223 | doc: /* "Check a watch specified by its WATCH-DESCRIPTOR. |
| 222 | 224 | ||
| 223 | WATCH-DESCRIPTOR should be an object returned by `gfile-add-watch'. | 225 | WATCH-DESCRIPTOR should be an object returned by `kqueue-add-watch'. |
| 224 | 226 | ||
| 225 | A watch can become invalid if the file or directory it watches is | 227 | A watch can become invalid if the file or directory it watches is |
| 226 | deleted, or if the watcher thread exits abnormally for any other | 228 | deleted, or if the watcher thread exits abnormally for any other |
| 227 | reason. Removing the watch by calling `gfile-rm-watch' also makes it | 229 | reason. Removing the watch by calling `kqueue-rm-watch' also makes it |
| 228 | invalid. */) | 230 | invalid. */) |
| 229 | (Lisp_Object watch_descriptor) | 231 | (Lisp_Object watch_descriptor) |
| 230 | { | 232 | { |
| 231 | Lisp_Object watch_object = Fassoc (watch_descriptor, watch_list); | 233 | return NILP (assq_no_quit (watch_descriptor, watch_list)) ? Qnil : Qt; |
| 232 | if (NILP (watch_object)) | ||
| 233 | return Qnil; | ||
| 234 | else | ||
| 235 | { | ||
| 236 | GFileMonitor *monitor = XINTPTR (watch_descriptor); | ||
| 237 | return g_file_monitor_is_cancelled (monitor) ? Qnil : Qt; | ||
| 238 | } | ||
| 239 | } | 234 | } |
| 240 | #endif /* 0 */ | ||
| 241 | 235 | ||
| 242 | 236 | ||
| 243 | void | 237 | void |
| @@ -250,8 +244,8 @@ void | |||
| 250 | syms_of_kqueue (void) | 244 | syms_of_kqueue (void) |
| 251 | { | 245 | { |
| 252 | defsubr (&Skqueue_add_watch); | 246 | defsubr (&Skqueue_add_watch); |
| 253 | // defsubr (&Skqueue_rm_watch); | 247 | defsubr (&Skqueue_rm_watch); |
| 254 | // defsubr (&Skqueue_valid_p); | 248 | defsubr (&Skqueue_valid_p); |
| 255 | 249 | ||
| 256 | /* Event types. */ | 250 | /* Event types. */ |
| 257 | DEFSYM (Qdelete, "delete"); /* NOTE_DELETE */ | 251 | DEFSYM (Qdelete, "delete"); /* NOTE_DELETE */ |
| @@ -267,3 +261,11 @@ syms_of_kqueue (void) | |||
| 267 | } | 261 | } |
| 268 | 262 | ||
| 269 | #endif /* HAVE_KQUEUE */ | 263 | #endif /* HAVE_KQUEUE */ |
| 264 | |||
| 265 | /* TODO | ||
| 266 | * Implement watching directories. | ||
| 267 | * Add FILE1 in case of `rename'. */ | ||
| 268 | |||
| 269 | /* PROBLEMS | ||
| 270 | * https://bugs.launchpad.net/ubuntu/+source/libkqueue/+bug/1514837 | ||
| 271 | prevents tests on Ubuntu. */ | ||