all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: "Rüdiger Sonderfeld" <ruediger@c-plusplus.de>
To: Stefan Monnier <monnier@iro.umontreal.ca>
Cc: Leo <sdl.web@gmail.com>, emacs-devel@gnu.org
Subject: [PATCH] Added inotify support.
Date: Mon, 01 Oct 2012 16:09:55 +0200	[thread overview]
Message-ID: <2181827.T3JxG88qQt@descartes> (raw)
In-Reply-To: <jwv391yopa9.fsf-monnier+emacs@gnu.org>

On Monday 01 October 2012 00:38:09 Stefan Monnier wrote:
> If there's a good chance this won't work without breaking compatibility,
> maybe a better option is to provide a low-level API that maps very
> closely to inotify and then an Elisp layer on top which abstracts away
> differences between different systems.  In that case we can install the
> inotify support right away while we're still experimenting with the
> higher-level abstraction.

That's probably the best approach here.  I changed the patch to provide a low
level inotify interface.  However I did not provide an inotify_init(2) like 
function and instead initialization and closing of the inotify handle is done
internally.  I don't think that this should be exposed to elisp even in the 
low level interface.

> But if they're unlikely to be important in practice, then
> I guess the current solution might be acceptable.

I think we are safe.  I added that `equal' should be used to compare cookies.  
So we can easily change it without breaking the API.

> I think the cleaner option is to define a new object type for it.
> It could be either a new Lisp_Misc type, so you can make them print as
> something like "#<file-watcher NNN>" (take a look at "enum
> Lisp_Misc_Type" and "union Lisp_Misc" in src/lisp.h for starters; adding
> a new type will require adding corresponding branches to the switch
> statements in alloc.c and in print.c).

That sounds like the best option.  I haven't implemented it yet.  Is it 
possible to make the Lisp_Misc_Type comparable with `equal'? Because the 
watch-descriptor has to be comparable.

Regards,
Rüdiger

-- >8 --

Inotify is a Linux kernel API to monitor file system events.  This
patch adds a basic inotify based API to Emacs:

`inotify-add-watch' is based on inotify_add_watch(2).  But uses
callbacks and accepts lisp objects instead of a bit mask.

`inotify-rm-watch' is based on inotify_rm_watch(2).

The creation and destruction of an inotify fd with inotify_init1(2) is
handled internally.

Example:

    (let ((wd (inotify-add-watch "foo.txt" t
          (lambda (ev) (message "FS Event %s" ev)))))
      ;; ...
      (inotify-rm-watch wd))

Signed-off-by: Rüdiger Sonderfeld <ruediger@c-plusplus.de>
---
 configure.ac                   |  13 ++
 lisp/subr.el                   |  21 ++
 src/Makefile.in                |   2 +-
 src/emacs.c                    |   4 +
 src/inotify.c                  | 431 
+++++++++++++++++++++++++++++++++++++++++
 src/keyboard.c                 |  28 +++
 src/lisp.h                     |   5 +
 src/termhooks.h                |   5 +
 test/automated/inotify-test.el |  60 ++++++
 9 files changed, 568 insertions(+), 1 deletion(-)
 create mode 100644 src/inotify.c
 create mode 100644 test/automated/inotify-test.el

diff --git a/configure.ac b/configure.ac
index 5a3aea7..c1ce23f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -184,6 +184,7 @@ OPTION_DEFAULT_ON([gconf],[don't compile with GConf 
support])
 OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support])
 OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support])
 OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support])
+OPTION_DEFAULT_ON([inotify],[don't compile with inotify (file-watch) 
support])
 
 ## For the times when you want to build Emacs but don't have
 ## a suitable makeinfo, and can live without the manuals.
@@ -2101,6 +2102,18 @@ fi
 AC_SUBST(LIBGNUTLS_LIBS)
 AC_SUBST(LIBGNUTLS_CFLAGS)
 
+dnl inotify is only available on GNU/Linux.
+HAVE_INOTIFY=no
+if test "${with_inotify}" = "yes"; then
+   AC_CHECK_HEADERS(sys/inotify.h)
+   if test "$ac_cv_header_sys_inotify_h" = yes ; then
+     AC_CHECK_FUNCS(inotify_init1 inotify_add_watch inotify_rm_watch, 
HAVE_INOTIFY=yes)
+   fi
+fi
+if test "${HAVE_INOTIFY}" = "yes"; then
+   AC_DEFINE(HAVE_INOTIFY, [1], [Define to 1 to use inotify])
+fi
+
 dnl Do not put whitespace before the #include statements below.
 dnl Older compilers (eg sunos4 cc) choke on it.
 HAVE_XAW3D=no
diff --git a/lisp/subr.el b/lisp/subr.el
index 8dfe78d..134a1dc 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -4159,6 +4159,27 @@ convenience wrapper around `make-progress-reporter' and 
friends.
        nil ,@(cdr (cdr spec)))))
 
 \f
+;;;; Support for watching filesystem events.
+
+(defun inotify-event-p (event)
+  "Check if EVENT is an inotify event."
+  (and (listp event)
+       (>= (length event) 3)
+       (eq (car event) 'inotify-event)))
+
+;;;###autoload
+(defun inotify-handle-event (event)
+  "Handle file system monitoring event.
+If EVENT is a filewatch event then the callback is called.  If EVENT is
+not a filewatch event then a `filewatch-error' is signaled."
+  (interactive "e")
+
+  (unless (inotify-event-p event)
+    (signal 'inotify-error (cons "Not a valid inotify event" event)))
+
+  (funcall (nth 2 event) (nth 1 event)))
+
+\f
 ;;;; Comparing version strings.
 
 (defconst version-separator "."
diff --git a/src/Makefile.in b/src/Makefile.in
index f8da009..1492dc6 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -339,7 +339,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o 
$(XMENU_OBJ) window.o \
 	syntax.o $(UNEXEC_OBJ) bytecode.o \
 	process.o gnutls.o callproc.o \
 	region-cache.o sound.o atimer.o \
-	doprnt.o intervals.o textprop.o composite.o xml.o \
+	doprnt.o intervals.o textprop.o composite.o xml.o inotify.o \
 	profiler.o \
 	$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \
 	$(WINDOW_SYSTEM_OBJ)
diff --git a/src/emacs.c b/src/emacs.c
index 05affee..e43fa0e 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1411,6 +1411,10 @@ Using an Emacs configured with --with-x-toolkit=lucid 
does not have this problem
       syms_of_gnutls ();
 #endif
 
+#ifdef HAVE_INOTIFY
+      syms_of_inotify ();
+#endif /* HAVE_INOTIFY */
+
 #ifdef HAVE_DBUS
       syms_of_dbusbind ();
 #endif /* HAVE_DBUS */
diff --git a/src/inotify.c b/src/inotify.c
new file mode 100644
index 0000000..49a45cb
--- /dev/null
+++ b/src/inotify.c
@@ -0,0 +1,431 @@
+/* Inotify support for Emacs
+
+Copyright (C) 2012
+  Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#ifdef HAVE_INOTIFY
+
+#include "lisp.h"
+#include "coding.h"
+#include "process.h"
+#include "keyboard.h"
+#include "character.h"
+#include "frame.h" /* Required for termhooks.h.  */
+#include "termhooks.h"
+
+static Lisp_Object Qaccess;        /* IN_ACCESS */
+static Lisp_Object Qattrib;        /* IN_ATTRIB */
+static Lisp_Object Qclose_write;   /* IN_CLOSE_WRITE */
+static Lisp_Object Qclose_nowrite; /* IN_CLOSE_NOWRITE */
+static Lisp_Object Qcreate;        /* IN_CREATE */
+static Lisp_Object Qdelete;        /* IN_DELETE */
+static Lisp_Object Qdelete_self;   /* IN_DELETE_SELF */
+static Lisp_Object Qmodify;        /* IN_MODIFY */
+static Lisp_Object Qmove_self;     /* IN_MOVE_SELF */
+static Lisp_Object Qmoved_from;    /* IN_MOVED_FROM */
+static Lisp_Object Qmoved_to;      /* IN_MOVED_TO */
+static Lisp_Object Qopen;          /* IN_OPEN */
+
+static Lisp_Object Qall_events;    /* IN_ALL_EVENTS */
+static Lisp_Object Qmove;          /* IN_MOVE */
+static Lisp_Object Qclose;         /* IN_CLOSE */
+
+static Lisp_Object Qdont_follow;   /* IN_DONT_FOLLOW */
+static Lisp_Object Qexcl_unlink;   /* IN_EXCL_UNLINK */
+static Lisp_Object Qmask_add;      /* IN_MASK_ADD */
+static Lisp_Object Qoneshot;       /* IN_ONESHOT */
+static Lisp_Object Qonlydir;       /* IN_ONLYDIR */
+
+static Lisp_Object Qignored;       /* IN_IGNORED */
+static Lisp_Object Qisdir;         /* IN_ISDIR */
+static Lisp_Object Qq_overflow;    /* IN_Q_OVERFLOW */
+static Lisp_Object Qunmount;       /* IN_UNMOUNT */
+
+static Lisp_Object Qinotify_event;
+
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+
+enum { uninitialized = -100 };
+/* File handle for inotify.  */
+static int inotifyfd = uninitialized;
+
+/* Assoc list of files being watched.
+   Format:
+   (watch-descriptor . callback)
+ */
+static Lisp_Object watch_list;
+
+static Lisp_Object
+make_watch_descriptor (int wd)
+{
+  /* TODO replace this with a Misc Object! */
+  return make_number (wd);
+}
+
+static Lisp_Object
+mask_to_aspects (uint32_t mask) {
+  Lisp_Object aspects = Qnil;
+  if (mask & IN_ACCESS)
+    aspects = Fcons (Qaccess, aspects);
+  if (mask & IN_ATTRIB)
+    aspects = Fcons (Qattrib, aspects);
+  if (mask & IN_CLOSE_WRITE)
+    aspects = Fcons (Qclose_write, aspects);
+  if (mask & IN_CLOSE_NOWRITE)
+    aspects = Fcons (Qclose_nowrite, aspects);
+  if (mask & IN_CREATE)
+    aspects = Fcons (Qcreate, aspects);
+  if (mask & IN_DELETE)
+    aspects = Fcons (Qdelete, aspects);
+  if (mask & IN_DELETE_SELF)
+    aspects = Fcons (Qdelete_self, aspects);
+  if (mask & IN_MODIFY)
+    aspects = Fcons (Qmodify, aspects);
+  if (mask & IN_MOVE_SELF)
+    aspects = Fcons (Qmove_self, aspects);
+  if (mask & IN_MOVED_FROM)
+    aspects = Fcons (Qmoved_from, aspects);
+  if (mask & IN_MOVED_TO)
+    aspects = Fcons (Qmoved_to, aspects);
+  if (mask & IN_OPEN)
+    aspects = Fcons (Qopen,  aspects);
+  if (mask & IN_IGNORED)
+    aspects = Fcons (Qignored, aspects);
+  if (mask & IN_ISDIR)
+    aspects = Fcons (Qisdir, aspects);
+  if (mask & IN_Q_OVERFLOW)
+    aspects = Fcons (Qq_overflow, aspects);
+  if (mask & IN_UNMOUNT)
+    aspects = Fcons (Qunmount, aspects);
+  return aspects;
+}
+
+static Lisp_Object
+inotifyevent_to_event (Lisp_Object watch_object, struct inotify_event const 
*ev)
+{
+  Lisp_Object name = Qnil;
+  if (ev->len > 0)
+    {
+      size_t const len = strlen (ev->name);
+      name = make_unibyte_string (ev->name, min (len, ev->len));
+      name = DECODE_FILE (name);
+    }
+
+  return list2 (list4 (make_watch_descriptor (ev->wd),
+                       mask_to_aspects (ev->mask),
+                       make_number (ev->cookie),
+                       name),
+                XCDR (watch_object));
+}
+
+/* This callback is called when the FD is available for read.  The inotify
+   events are read from FD and converted into input_events.  */
+static void
+inotify_callback (int fd, void *_)
+{
+  struct input_event event;
+  Lisp_Object watch_object;
+  int to_read;
+  char *buffer;
+  ssize_t n;
+  size_t i;
+
+  to_read = 0;
+  if (ioctl (fd, FIONREAD, &to_read) == -1)
+    report_file_error ("Error while trying to retrieve file system events",
+                       Qnil);
+  buffer = xmalloc (to_read);
+  n = read (fd, buffer, to_read);
+  if (n < 0)
+    {
+      xfree (buffer);
+      report_file_error ("Error while trying to read file system events",
+                         Qnil);
+    }
+
+  EVENT_INIT (event);
+  event.kind = INOTIFY_EVENT;
+  event.arg = Qnil;
+
+  i = 0;
+  while (i < (size_t)n)
+    {
+      struct inotify_event *ev = (struct inotify_event*)&buffer[i];
+
+      watch_object = Fassoc (make_watch_descriptor (ev->wd), watch_list);
+      if (!NILP (watch_object))
+        {
+          event.arg = inotifyevent_to_event (watch_object, ev);
+
+          /* If event was removed automatically: Drop it from watch list.  */
+          if (ev->mask & IN_IGNORED)
+            watch_list = Fdelete (watch_object, watch_list);
+        }
+
+      i += sizeof (*ev) + ev->len;
+    }
+
+  if (!NILP (event.arg))
+    kbd_buffer_store_event (&event);
+
+  xfree (buffer);
+}
+
+static uint32_t
+symbol_to_inotifymask (Lisp_Object symb)
+{
+  if (EQ (symb, Qaccess))
+    return IN_ACCESS;
+  else if (EQ (symb, Qattrib))
+    return IN_ATTRIB;
+  else if (EQ (symb, Qclose_write))
+    return IN_CLOSE_WRITE;
+  else if (EQ (symb, Qclose_nowrite))
+    return IN_CLOSE_NOWRITE;
+  else if (EQ (symb, Qcreate))
+    return IN_CREATE;
+  else if (EQ (symb, Qdelete))
+    return IN_DELETE;
+  else if (EQ (symb, Qdelete_self))
+    return IN_DELETE_SELF;
+  else if (EQ (symb, Qmodify))
+    return IN_MODIFY;
+  else if (EQ (symb, Qmove_self))
+    return IN_MOVE_SELF;
+  else if (EQ (symb, Qmoved_from))
+    return IN_MOVED_FROM;
+  else if (EQ (symb, Qmoved_to))
+    return IN_MOVED_TO;
+  else if (EQ (symb, Qopen))
+    return IN_OPEN;
+  else if (EQ (symb, Qmove))
+    return IN_MOVE;
+  else if (EQ (symb, Qclose))
+    return IN_CLOSE;
+
+  else if (EQ (symb, Qdont_follow))
+    return IN_DONT_FOLLOW;
+  else if (EQ (symb, Qexcl_unlink))
+    return IN_EXCL_UNLINK;
+  else if (EQ (symb, Qmask_add))
+    return IN_MASK_ADD;
+  else if (EQ (symb, Qoneshot))
+    return IN_ONESHOT;
+  else if (EQ (symb, Qonlydir))
+    return IN_ONLYDIR;
+
+  else if (EQ (symb, Qt) || EQ (symb, Qall_events))
+    return IN_ALL_EVENTS;
+  else
+    signal_error ("Unknown aspect", symb);
+}
+
+static uint32_t
+aspect_to_inotifymask (Lisp_Object aspect)
+{
+  if (CONSP (aspect))
+    {
+      Lisp_Object x = aspect;
+      uint32_t mask = 0;
+      while (CONSP (x))
+        {
+          mask |= symbol_to_inotifymask (XCAR (x));
+          x = XCDR (x);
+        }
+      return mask;
+    }
+  else
+    return symbol_to_inotifymask (aspect);
+}
+
+DEFUN ("inotify-add-watch", Finotify_add_watch, Sinotify_add_watch, 3, 3, 0,
+       doc: /* Add a watch for FILE-NAME to inotify.
+
+A WATCH-DESCRIPTOR is returned on success.  ASPECT might be one of the 
following
+symbols or a list of those symbols:
+
+access
+attrib
+close-write
+close-nowrite
+create
+delete
+delete-self
+modify
+move-self
+moved-from
+moved-to
+open
+
+all-events or t
+move
+close
+
+The following symbols can also be added to a list of aspects
+
+dont-follow
+excl-unlink
+mask-add
+oneshot
+onlydir
+
+Watching a directory is not recursive.  CALLBACK gets called in case of an
+event.  It gets passed a single argument EVENT which contains an event 
structure
+of the format
+
+(WATCH-DESCRIPTOR ASPECTS COOKIE NAME)
+
+WATCH-DESCRIPTOR is the same object that was returned by this function.  It 
can
+be tested for equality using `equal'.  ASPECTS describes the event.  It is a
+list of ASPECT symbols described above and can also contain one of the 
following
+symbols
+
+ignored
+isdir
+q-overflow
+unmount
+
+COOKIE is an object that can be compared using `equal' to identify two 
matching
+renames (moved-from and moved-to).
+
+If a directory is watched then NAME is the name of file that caused the 
event.
+
+See inotify(7) and inotify_add_watch(2) for further information.  The inotify 
fd
+is managed internally and there is no corresponding inotify_init.  Use
+`inotify-rm-watch' to remove a watch.
+             */)
+     (Lisp_Object file_name, Lisp_Object aspect, Lisp_Object callback)
+{
+  uint32_t mask;
+  Lisp_Object watch_object;
+  Lisp_Object decoded_file_name;
+  Lisp_Object watch_descriptor;
+  int watchdesc = -1;
+
+  CHECK_STRING (file_name);
+
+  if (inotifyfd == uninitialized)
+    {
+      inotifyfd = inotify_init1 (IN_NONBLOCK|IN_CLOEXEC);
+      if (inotifyfd == -1)
+        {
+          inotifyfd = uninitialized;
+          report_file_error ("File watching feature (inotify) is not 
available",
+                             Qnil);
+        }
+      watch_list = Qnil;
+      add_read_fd (inotifyfd, &inotify_callback, NULL);
+    }
+
+  mask = aspect_to_inotifymask (aspect);
+  decoded_file_name = ENCODE_FILE (file_name);
+  watchdesc = inotify_add_watch (inotifyfd, SSDATA (decoded_file_name), 
mask);
+  if (watchdesc == -1)
+    report_file_error ("Could not add watch for file", Fcons (file_name, 
Qnil));
+
+  watch_descriptor = make_watch_descriptor (watchdesc);
+
+  /* Delete existing watch object. */
+  watch_object = Fassoc (watch_descriptor, watch_list);
+  if (!NILP (watch_object))
+      watch_list = Fdelete (watch_object, watch_list);
+
+  /* Store watch object in watch list. */
+  watch_object = Fcons (watch_descriptor, callback);
+  watch_list = Fcons (watch_object, watch_list);
+
+  return watch_descriptor;
+}
+
+DEFUN ("inotify-rm-watch", Finotify_rm_watch, Sinotify_rm_watch, 1, 1, 0,
+       doc: /* Remove an existing WATCH-DESCRIPTOR.
+
+WATCH-DESCRIPTOR should be an object returned by `inotify-add-watch'.
+
+See inotify_rm_watch(2) for more information.
+             */)
+     (Lisp_Object watch_descriptor)
+{
+  Lisp_Object watch_object;
+  int wd = XINT (watch_descriptor);
+
+  if (inotify_rm_watch (inotifyfd, wd) == -1)
+    report_file_error ("Could not rm watch", Fcons (watch_descriptor,
+                                                    Qnil));
+
+  /* Remove watch descriptor from watch list. */
+  watch_object = Fassoc (watch_descriptor, watch_list);
+  if (!NILP (watch_object))
+    watch_list = Fdelete (watch_object, watch_list);
+
+  /* Cleanup if no more files are watched. */
+  if (NILP (watch_list))
+    {
+      close (inotifyfd);
+      delete_read_fd (inotifyfd);
+      inotifyfd = uninitialized;
+    }
+
+  return Qt;
+}
+
+void
+syms_of_inotify (void)
+{
+  DEFSYM (Qaccess, "access");
+  DEFSYM (Qattrib, "attrib");
+  DEFSYM (Qclose_write, "close-write");
+  DEFSYM (Qclose_nowrite, "close-nowrite");
+  DEFSYM (Qcreate, "create");
+  DEFSYM (Qdelete, "delete");
+  DEFSYM (Qdelete_self, "delete-self");
+  DEFSYM (Qmodify, "modify");
+  DEFSYM (Qmove_self, "move-self");
+  DEFSYM (Qmoved_from, "moved-from");
+  DEFSYM (Qmoved_to, "moved-to");
+  DEFSYM (Qopen, "open");
+
+  DEFSYM (Qall_events, "all-events");
+  DEFSYM (Qmove, "move");
+  DEFSYM (Qclose, "close");
+
+  DEFSYM (Qdont_follow, "dont-follow");
+  DEFSYM (Qexcl_unlink, "excl-unlink");
+  DEFSYM (Qmask_add, "mask-add");
+  DEFSYM (Qoneshot, "oneshot");
+  DEFSYM (Qonlydir, "onlydir");
+
+  DEFSYM (Qignored, "ignored");
+  DEFSYM (Qisdir, "isdir");
+  DEFSYM (Qq_overflow, "q-overflow");
+  DEFSYM (Qunmount, "unmount");
+
+  DEFSYM (Qinotify_event, "inotify-event");
+
+  defsubr (&Sinotify_add_watch);
+  defsubr (&Sinotify_rm_watch);
+
+  staticpro (&watch_list);
+
+  Fprovide (intern_c_string ("inotify"), Qnil);
+}
+
+#endif /* HAVE_INOTIFY */
diff --git a/src/keyboard.c b/src/keyboard.c
index f3d7df5..02e1473 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -321,6 +321,9 @@ static Lisp_Object Qsave_session;
 #ifdef HAVE_DBUS
 static Lisp_Object Qdbus_event;
 #endif
+#ifdef HAVE_INOTIFY
+static Lisp_Object Qinotify_event;
+#endif /* HAVE_INOTIFY */
 static Lisp_Object Qconfig_changed_event;
 
 /* Lisp_Object Qmouse_movement; - also an event header */
@@ -4021,6 +4024,13 @@ kbd_buffer_get_event (KBOARD **kbp,
 	  kbd_fetch_ptr = event + 1;
 	}
 #endif
+#ifdef HAVE_INOTIFY
+      else if (event->kind == INOTIFY_EVENT)
+        {
+          obj = make_lispy_event (event);
+          kbd_fetch_ptr = event + 1;
+        }
+#endif
       else if (event->kind == CONFIG_CHANGED_EVENT)
 	{
 	  obj = make_lispy_event (event);
@@ -5938,6 +5948,13 @@ make_lispy_event (struct input_event *event)
       }
 #endif /* HAVE_DBUS */
 
+#ifdef HAVE_INOTIFY
+    case INOTIFY_EVENT:
+      {
+        return Fcons (Qinotify_event, event->arg);
+      }
+#endif /* HAVE_INOTIFY */
+
     case CONFIG_CHANGED_EVENT:
 	return Fcons (Qconfig_changed_event,
                       Fcons (event->arg,
@@ -11408,6 +11425,10 @@ syms_of_keyboard (void)
   DEFSYM (Qdbus_event, "dbus-event");
 #endif
 
+#ifdef HAVE_INOTIFY
+  DEFSYM (Qinotify_event, "inotify-event");
+#endif /* HAVE_INOTIFY */
+
   DEFSYM (QCenable, ":enable");
   DEFSYM (QCvisible, ":visible");
   DEFSYM (QChelp, ":help");
@@ -12168,6 +12189,13 @@ keys_of_keyboard (void)
 			    "dbus-handle-event");
 #endif
 
+#ifdef HAVE_INOTIFY
+  /* Define a special event which is raised for inotify callback
+     functions.  */
+  initial_define_lispy_key (Vspecial_event_map, "inotify-event",
+                            "inotify-handle-event");
+#endif /* HAVE_INOTIFY */
+
   initial_define_lispy_key (Vspecial_event_map, "config-changed-event",
 			    "ignore");
 #if defined (WINDOWSNT)
diff --git a/src/lisp.h b/src/lisp.h
index c3cabe0..02bfa08 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3497,6 +3497,11 @@ extern void syms_of_fontset (void);
 extern Lisp_Object Qfont_param;
 #endif
 
+/* Defined in inotify.c */
+#ifdef HAVE_INOTIFY
+extern void syms_of_inotify (void);
+#endif
+
 /* Defined in xfaces.c.  */
 extern Lisp_Object Qdefault, Qtool_bar, Qfringe;
 extern Lisp_Object Qheader_line, Qscroll_bar, Qcursor;
diff --git a/src/termhooks.h b/src/termhooks.h
index f35bd92..5890d10 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -211,6 +211,11 @@ enum event_kind
   , NS_NONKEY_EVENT
 #endif
 
+#ifdef HAVE_INOTIFY
+  /* File or directory was changed.  */
+  , INOTIFY_EVENT
+#endif
+
 };
 
 /* If a struct input_event has a kind which is SELECTION_REQUEST_EVENT
diff --git a/test/automated/inotify-test.el b/test/automated/inotify-test.el
new file mode 100644
index 0000000..edda7ef
--- /dev/null
+++ b/test/automated/inotify-test.el
@@ -0,0 +1,60 @@
+;;; inotify-tests.el --- Test suite for inotify. -*- lexical-binding: t -*-
+
+;; Copyright (C) 2012 Free Software Foundation, Inc.
+
+;; Author: Rüdiger Sonderfeld <ruediger@c-plusplus.de>
+;; Keywords:       internal
+;; Human-Keywords: internal
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+
+(when (featurep 'inotify)
+
+  ;; (ert-deftest filewatch-file-watch-aspects-check ()
+  ;;   "Test whether `file-watch' properly checks the aspects."
+  ;;   (let ((temp-file (make-temp-file "filewatch-aspects")))
+  ;;     (should (stringp temp-file))
+  ;;     (should-error (file-watch temp-file 'wrong nil)
+  ;;                   :type 'error)
+  ;;     (should-error (file-watch temp-file '(modify t) nil)
+  ;;                   :type 'error)
+  ;;     (should-error (file-watch temp-file '(modify all-modify) nil)
+  ;;                   :type 'error)
+  ;;     (should-error (file-watch temp-file '(access wrong modify) nil)
+  ;;                   :type 'error)))
+
+  (ert-deftest inotify-file-watch-simple ()
+    "Test if watching a normal file works."
+    (let ((temp-file (make-temp-file "inotify-simple"))
+	   (events 0))
+      (let ((wd
+	     (inotify-add-watch temp-file t (lambda (ev)
+                                              (setq events (1+ events))))))
+	(unwind-protect
+	    (progn
+	      (with-temp-file temp-file
+		(insert "Foo\n"))
+	      (sit-for 5) ;; Hacky. Wait for 5s until events are processed
+	      (should (> events 0)))
+	  (inotify-rm-watch wd)))))
+)
+
+(provide 'inotify-tests)
+;;; inotify-tests.el ends here.
-- 
1.7.11.3




  parent reply	other threads:[~2012-10-01 14:09 UTC|newest]

Thread overview: 148+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-06-03 22:34 [PATCH] Support for filesystem watching (inotify) Rüdiger Sonderfeld
2011-06-04  8:52 ` joakim
2011-06-04 16:40   ` Rüdiger Sonderfeld
2011-06-04 10:43 ` Jan Djärv
2011-06-04 23:36   ` [PATCH update2] " Rüdiger Sonderfeld
2011-06-05  5:45     ` Eli Zaretskii
2011-06-05  9:48       ` [PATCH update3] " Rüdiger Sonderfeld
2011-06-05  7:48     ` [PATCH update2] " Jan Djärv
2011-06-05  7:54     ` Andreas Schwab
2011-06-05  9:49       ` Rüdiger Sonderfeld
2011-06-05 15:59         ` John Yates
2011-06-05 16:14           ` Rüdiger Sonderfeld
2011-06-05 16:58             ` Eli Zaretskii
2011-06-06 18:56               ` Rüdiger Sonderfeld
2011-06-06 19:57                 ` Eli Zaretskii
2011-06-04 11:30 ` [PATCH] " Eli Zaretskii
2011-06-04 17:13   ` [PATCH updated] " Rüdiger Sonderfeld
2011-06-04 19:15     ` Eli Zaretskii
2011-06-04 20:10     ` Thien-Thi Nguyen
2011-06-04 23:43       ` Rüdiger Sonderfeld
2011-06-05  2:15         ` Thien-Thi Nguyen
2011-06-05  9:22           ` Štěpán Němec
2011-06-15 20:53             ` Johan Bockgård
2011-06-16  8:52               ` Inlined cl functions -- how to learn about them Štěpán Němec
2011-06-06 15:21       ` [PATCH updated] Support for filesystem watching (inotify) Stefan Monnier
2011-06-06 16:25         ` Rüdiger Sonderfeld
2011-06-06 17:11           ` Stefan Monnier
2011-06-06 20:16             ` Ted Zlatanov
2011-06-07 14:42               ` Stefan Monnier
2011-06-07 16:46                 ` Ted Zlatanov
2011-06-07 18:06                   ` Stefan Monnier
2011-06-07 18:26                     ` Ted Zlatanov
2011-06-24  0:50             ` Rüdiger Sonderfeld
2011-06-24 10:19               ` Ted Zlatanov
2011-06-24 12:18                 ` Ted Zlatanov
2011-07-06 13:36               ` Stefan Monnier
2011-07-06 15:54                 ` Paul Eggert
2011-07-06 18:30                   ` Stefan Monnier
2011-07-06 20:39                     ` Paul Eggert
2011-07-06 19:14                   ` wide-int crash [was Re: [PATCH updated] Support for filesystem watching (inotify)] Glenn Morris
2011-07-06 22:31                     ` bug#8884: " Paul Eggert
2011-07-06 22:31                     ` Paul Eggert
2011-10-07  7:30                       ` bug#8884: wide-int crash Glenn Morris
2011-06-17 17:50                         ` bug#8884: 24.0.50; temacs crashes and dumps core when configured --with-wide-int Peter Dyballa
2011-06-17 20:07                           ` Peter Dyballa
     [not found]                           ` <handler.8884.D8884.131797266119606.notifdone@debbugs.gnu.org>
2011-10-08 13:35                             ` bug#8884: closed (Re: bug#8884: wide-int crash) Peter Dyballa
2011-10-17 22:24                             ` Peter Dyballa
2011-10-18  5:42                               ` Paul Eggert
2011-10-18  9:14                                 ` Peter Dyballa
2011-10-18 10:55                                   ` Eli Zaretskii
2011-10-18 13:33                                     ` Stefan Monnier
2011-10-18 15:38                                     ` Paul Eggert
2011-10-18 15:45                                       ` Andreas Schwab
2011-10-18 15:57                                         ` Paul Eggert
2011-10-18 21:41                                         ` Peter Dyballa
2011-10-19  1:47                                           ` Paul Eggert
2011-10-19 22:46                                             ` Peter Dyballa
2011-10-19  3:43                                           ` Stefan Monnier
2011-10-19 13:59                                             ` Peter Dyballa
2011-10-19 14:44                                               ` Stefan Monnier
2011-10-19 14:59                                                 ` Peter Dyballa
2011-10-19 18:00                                                   ` Stefan Monnier
2011-10-19 21:59                                                     ` Peter Dyballa
2011-10-20  0:32                                                       ` Stefan Monnier
2011-07-07 19:43               ` [PATCH updated] Support for filesystem watching (inotify) Stefan Monnier
2012-09-28 13:06                 ` [PATCH] Added basic file system watching support Rüdiger Sonderfeld
2012-09-28 14:13                   ` Stefan Monnier
2012-09-28 16:27                     ` Rüdiger Sonderfeld
2012-10-01  4:38                       ` Stefan Monnier
2012-10-01  7:24                         ` Eli Zaretskii
2012-10-01 14:09                         ` Rüdiger Sonderfeld [this message]
2012-10-01 16:27                           ` [PATCH] Added inotify support Stefan Monnier
2012-10-02 21:28                           ` Eli Zaretskii
2012-10-02 23:46                             ` Óscar Fuentes
2012-10-03  2:10                               ` Stefan Monnier
2012-10-03  3:54                                 ` Eli Zaretskii
2012-10-03 12:46                                   ` Stefan Monnier
2012-10-03 18:34                                     ` Eli Zaretskii
2012-10-03 18:47                                       ` Stefan Monnier
2012-10-03 19:08                                         ` Eli Zaretskii
2012-10-03 20:59                                           ` Stefan Monnier
2012-10-12 13:54                                             ` Eli Zaretskii
2012-10-14 14:55                                               ` Eli Zaretskii
2012-10-03 19:33                                       ` Óscar Fuentes
2012-10-05  7:40                                         ` Eli Zaretskii
2012-10-05 13:07                                           ` Óscar Fuentes
2012-10-05 15:19                                             ` Eli Zaretskii
2012-10-05 16:55                                 ` Nix
2012-10-05 17:15                                   ` Eli Zaretskii
2012-10-05 17:46                                     ` Nix
2012-10-05 18:22                                   ` Stefan Monnier
2012-10-05 18:30                                     ` Óscar Fuentes
2012-10-06 16:39                                     ` Nix
2012-10-06 17:01                                       ` Stefan Monnier
2012-10-06 18:51                                         ` Nix
2012-10-06 21:26                                           ` Stefan Monnier
2012-10-06 21:28                                             ` Nix
2012-10-07  7:38                                               ` Achim Gratz
2012-10-07 13:58                                                 ` Stefan Monnier
2012-10-07 14:54                                                   ` Achim Gratz
2012-10-07  8:24                                               ` Stephen J. Turnbull
2012-10-07 14:00                                                 ` Stefan Monnier
2012-10-07 14:28                                                   ` Óscar Fuentes
2012-10-07 14:38                                                     ` Stefan Monnier
2012-10-08  7:07                                                   ` Stephen J. Turnbull
2012-10-08  8:06                                                     ` Eli Zaretskii
2012-10-14 15:52                                           ` Jim Meyering
2012-10-06  7:04                                   ` Stephen J. Turnbull
2012-10-06  7:23                                     ` Andreas Schwab
2012-10-06 16:41                                       ` Nix
2012-10-07  8:09                                         ` Stephen J. Turnbull
2012-10-07 14:08                                           ` Stefan Monnier
2012-10-03  3:57                               ` Eli Zaretskii
2012-12-02 20:08                           ` Eli Zaretskii
2012-12-03 17:18                             ` Stefan Monnier
2012-12-10 14:16                               ` Eli Zaretskii
2012-12-10 14:47                                 ` Stefan Monnier
2012-12-10 11:52                           ` Eli Zaretskii
2012-12-10 12:11                             ` Rüdiger Sonderfeld
2012-12-11  7:43                             ` Michael Albinus
2012-12-11  8:20                               ` Eli Zaretskii
2012-12-11 16:36                                 ` Michael Albinus
2012-12-11 16:46                                   ` Rüdiger Sonderfeld
2012-12-11 20:17                                     ` Michael Albinus
2012-12-11  7:54                         ` [PATCH] Added basic file system watching support Michael Albinus
2012-12-11  8:12                           ` Eli Zaretskii
2012-12-11  8:19                             ` Michael Albinus
2012-12-11  8:29                               ` Eli Zaretskii
2012-12-11  8:44                                 ` Michael Albinus
2012-12-11  9:39                                   ` Eli Zaretskii
2012-12-11 10:15                                     ` Eli Zaretskii
2012-12-11 10:38                                       ` Michael Albinus
2012-12-11 10:24                                     ` Michael Albinus
2012-12-11 12:51                                       ` Eli Zaretskii
2012-12-11 13:17                                         ` Michael Albinus
2012-12-11 13:23                                           ` Eli Zaretskii
2012-12-12  1:09                                         ` Leo
2012-12-12  3:57                                           ` Eli Zaretskii
2013-01-07 11:33                                     ` Michael Albinus
2013-01-07 15:57                                       ` Eli Zaretskii
2013-01-07 16:00                                         ` Michael Albinus
2013-01-07 20:26                                           ` Stefan Monnier
2013-01-08  7:44                                             ` Michael Albinus
2011-06-06 15:14     ` [PATCH updated] Support for filesystem watching (inotify) Stefan Monnier
2011-06-06 16:21       ` Rüdiger Sonderfeld
2012-09-18 11:50 ` [PATCH] " Leo
2012-09-26 12:15   ` Rüdiger Sonderfeld
2012-09-26 17:52     ` Stefan Monnier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2181827.T3JxG88qQt@descartes \
    --to=ruediger@c-plusplus.de \
    --cc=emacs-devel@gnu.org \
    --cc=monnier@iro.umontreal.ca \
    --cc=sdl.web@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.