From: "Rüdiger Sonderfeld" <ruediger@c-plusplus.de>
To: "emacs-devel@gnu.org" <emacs-devel@gnu.org>
Subject: Re: [PATCH update2] Support for filesystem watching (inotify)
Date: Sun, 5 Jun 2011 01:36:35 +0200 [thread overview]
Message-ID: <201106050136.35939.ruediger@c-plusplus.de> (raw)
In-Reply-To: <CC0812B7-C74F-4C21-9D18-0DF044CD7FCD@swipnet.se>
Hi,
On Saturday 04 June 2011 12:43:37 you wrote:
> In general, you should not call Lisp from the read fd callback. Recursive
> calls into Lisp may fail. Instead post a Lisp event and handle it in
> keyboard.c and some Lisp code.
Thanks for your advise. I changed the code to use events. I imitated the
behaviour of the dbus subsystem. I hope this is what you had in mind.
Subject: [PATCH] Added basic file system watching support.
It currently only works with inotify/Linux. It adds file-watch and file-
unwatch functions.
---
configure.in | 14 +++
src/Makefile.in | 2 +-
src/emacs.c | 4 +
src/filewatch.c | 268
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/lisp.h | 5 +
5 files changed, 292 insertions(+), 1 deletions(-)
create mode 100644 src/filewatch.c
diff --git a/configure.in b/configure.in
index 06880ea..5696fa2 100644
--- a/configure.in
+++ b/configure.in
@@ -169,6 +169,7 @@ OPTION_DEFAULT_ON([dbus],[don't compile with D-Bus
support])
OPTION_DEFAULT_ON([gconf],[don't compile with GConf 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.
@@ -1981,6 +1982,19 @@ 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])
+ AC_DEFINE(HAVE_FILEWATCH, [1], [Define to 1 to support filewatch])
+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/src/Makefile.in b/src/Makefile.in
index c4250b9..9135e7d 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -334,7 +334,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 filewatch.o \
$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ)
obj = $(base_obj) $(NS_OBJC_OBJ)
diff --git a/src/emacs.c b/src/emacs.c
index 3a7c5c0..fb734e5 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1558,6 +1558,10 @@ main (int argc, char **argv)
syms_of_gnutls ();
#endif
+#ifdef HAVE_FILEWATCH
+ syms_of_filewatch ();
+#endif /* HAVE_FILEWATCH */
+
#ifdef HAVE_DBUS
syms_of_dbusbind ();
#endif /* HAVE_DBUS */
diff --git a/src/filewatch.c b/src/filewatch.c
new file mode 100644
index 0000000..55da25f
--- /dev/null
+++ b/src/filewatch.c
@@ -0,0 +1,268 @@
+/* Watching file system changes.
+
+Copyright (C) 2011
+ 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_FILEWATCH
+#include <setjmp.h>
+#include "lisp.h"
+#include "coding.h"
+#include "process.h"
+
+static Lisp_Object QCmodify, QCmove, QCattrib, QCdelete, QCfrom, QCto, QCall;
+
+#ifdef HAVE_INOTIFY
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+
+enum { uninitialized = -100 };
+static int inotifyfd = uninitialized;
+
+/* Assoc list of files being watched. */
+static Lisp_Object watch_list;
+
+static void
+inotify_callback(int fd, void *_, int for_read)
+{
+ int to_read;
+ char *buffer;
+ ssize_t n;
+ size_t i;
+
+ if(!for_read)
+ return;
+
+ 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)
+ report_file_error("Error while trying to read file system events",
+ Qnil);
+
+ i = 0;
+ while(i < (size_t)n)
+ {
+ struct inotify_event *ev = (struct inotify_event*)&buffer[i];
+
+ Lisp_Object callback = Fassoc(make_number(ev->wd), watch_list);
+ if(!NILP(callback))
+ {
+ size_t len;
+ Lisp_Object name, events;
+ Lisp_Object call[3];
+ call[0] = Fcar(Fcdr(Fcdr(callback))); /* callback */
+ call[1] = Fcar(Fcdr(callback)); /* file name */
+
+ /* If a directory is watched name contains the name
+ of the file that was changed. */
+ len = strlen(ev->name);
+ name = make_unibyte_string (ev->name, len);
+ name = DECODE_FILE(name);
+
+ events = Qnil;
+ if(ev->mask & (IN_MODIFY|IN_CREATE) )
+ events = Fcons(Fcons(QCmodify, name), events);
+ if(ev->mask & IN_MOVE_SELF)
+ events = Fcons(Fcons(QCmove, name), events);
+ if(ev->mask & IN_MOVED_FROM)
+ events = Fcons(Fcons(QCmove,
+ Fcons(QCfrom,
+ Fcons(name, make_number(ev-
>cookie)))),
+ events);
+ if(ev->mask & IN_MOVED_TO)
+ events = Fcons(Fcons(QCmove,
+ Fcons(QCto,
+ Fcons(name, make_number(ev-
>cookie)))),
+ events);
+ if(ev->mask & IN_ATTRIB)
+ events = Fcons(Fcons(QCattrib, name), events);
+ if(ev->mask & (IN_DELETE|IN_DELETE_SELF) )
+ events = Fcons(Fcons(QCdelete, name), events);
+
+ if(!NILP(events))
+ {
+ call[2] = events;
+ Ffuncall(3, call);
+ }
+
+ if(ev->mask & IN_IGNORED)
+ {
+ /* Event was removed automatically: Drop it from data list. */
+ add_to_log("File-watch: \"%s\" will be ignored", call[1],
Qnil);
+ watch_list = Fdelete(callback, watch_list);
+ }
+ if(ev->mask & IN_Q_OVERFLOW)
+ add_to_log("File watch: Inotify Queue Overflow!", Qnil, Qnil);
+ }
+
+ i += sizeof(*ev) + ev->len;
+ }
+
+ xfree(buffer);
+}
+
+DEFUN ("file-watch", Ffile_watch, Sfile_watch, 3, MANY, 0,
+ doc: /* Watch a file or directory.
+
+file-watch watches the file or directory given in FILENAME. If a change
occurs
+CALLBACK is called with FILENAME as first argument and a list of changes as
second
+argument. FLAGS can be
+
+:modify -- notify when a file is modified or created.
+
+:move -- notify when a file/directory is moved.
+
+:attrib -- notify when attributes change.
+
+:delete -- notify when a file/directory is deleted.
+
+:all -- notify for all of the above.
+
+Watching a directory is not recursive. CALLBACK receives the events as a
list
+with each list element being a list containing information about an event.
The
+first element is a flag symbol. If a directory is watched the second element
is
+the name of the file that changed. If a file is moved from or to the
directory
+the second element is either :from or :to and the third element is the file
+name. A fourth element contains a numeric identifier (cookie) that can be
used
+to identify matching move operations if a file is moved inside the directory.
+
+Example:
+(file-watch "foo" #'(lambda (file event) (message "%s %s" file event)) :all)
+
+Use `file-unwatch' to stop watching.
+
+usage: (file-watch FILENAME CALLBACK &rest FLAGS) */)
+ (size_t nargs, Lisp_Object *args)
+{
+ uint32_t mask;
+ size_t i;
+ int watchdesc;
+ Lisp_Object decoded_file_name;
+
+ if(nargs < 3)
+ return Qnil;
+
+ CHECK_STRING(args[0]);
+
+ if(inotifyfd == uninitialized)
+ {
+ inotifyfd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+ if(inotifyfd == -1)
+ report_file_error("File watching feature (inotify) is not available",
+ Qnil);
+ watch_list = Qnil;
+ add_read_fd(inotifyfd, &inotify_callback, &watch_list);
+ }
+ mask = 0;
+ for(i = 2; i < nargs; ++i)
+ {
+ if(EQ(args[i], QCmodify))
+ mask |= IN_MODIFY | IN_CREATE;
+ else if(EQ(args[i], QCmove))
+ mask |= IN_MOVE_SELF | IN_MOVE;
+ else if(EQ(args[i], QCattrib))
+ mask |= IN_ATTRIB;
+ else if(EQ(args[i], QCdelete))
+ mask |= IN_DELETE_SELF | IN_DELETE;
+ else if(EQ(args[i], QCall))
+ mask |= IN_MODIFY | IN_CREATE | IN_MOVE_SELF | IN_MOVE | IN_ATTRIB
+ | IN_DELETE_SELF | IN_DELETE;
+ else /* TODO: should this be an error? */
+ message("Unkown parameter %s (ignored)",
+ SSDATA(Fprin1_to_string(args[i], Qnil)));
+ }
+ decoded_file_name = ENCODE_FILE(args[0]);
+ watchdesc = inotify_add_watch(inotifyfd, SSDATA(decoded_file_name), mask);
+ if(watchdesc == -1) {
+ report_file_error("Could not watch file", Fcons(args[0], Qnil));
+ }
+ /* TODO: check if file is already in the watch_list. */
+ watch_list = Fcons(Fcons(make_number(watchdesc), Flist(2, args)),
watch_list);
+ return Qt;
+}
+
+DEFUN ("file-unwatch", Ffile_unwatch, Sfile_unwatch, 1, 1, 0,
+ doc: /* Stop watching a file or directory. */)
+ (Lisp_Object file_name)
+{
+ Lisp_Object cell, file_name_data;
+ Lisp_Object x = watch_list;
+
+ if(inotifyfd == uninitialized)
+ return Qnil;
+ CHECK_STRING(file_name);
+
+ while(!NILP(x))
+ {
+ cell = Fcar(x);
+ x = Fcdr(x);
+ file_name_data = Fcdr(cell);
+ if(!NILP(file_name_data) && STRINGP(Fcar(file_name_data))
+ && Fstring_equal(Fcar(file_name_data), file_name)
+ && NUMBERP(Fcar(cell)))
+ {
+ int const magicno = XINT(Fcar(cell));
+ watch_list = Fdelete(cell, watch_list);
+ if(inotify_rm_watch(inotifyfd, magicno) == -1)
+ report_file_error("Could not unwatch file", Fcons(file_name,
Qnil));
+ /* Cleanup if watch_list is empty. */
+ if(NILP(watch_list))
+ {
+ close(inotifyfd);
+ delete_read_fd(inotifyfd);
+ inotifyfd = uninitialized;
+ }
+ return Qt;
+ }
+ }
+ return Qnil;
+}
+
+#else /* HAVE_INOTIFY */
+#error "Filewatch defined but no watch mechanism (inotify) available"
+#endif /* HAVE_INOTIFY */
+
+void
+syms_of_filewatch (void)
+{
+ QCmodify = intern_c_string (":modify");
+ staticpro (&QCmodify);
+ QCmove = intern_c_string (":move");
+ staticpro (&QCmove);
+ QCattrib = intern_c_string (":attrib");
+ staticpro (&QCattrib);
+ QCdelete = intern_c_string (":delete");
+ staticpro (&QCdelete);
+ QCfrom = intern_c_string (":from");
+ staticpro (&QCfrom);
+ QCto = intern_c_string (":to");
+ staticpro (&QCto);
+ QCall = intern_c_string (":all");
+ staticpro (&QCall);
+
+ defsubr (&Sfile_watch);
+ defsubr (&Sfile_unwatch);
+}
+
+
+#endif /* HAVE_FILEWATCH */
diff --git a/src/lisp.h b/src/lisp.h
index 8a504e8..8b21e0e 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3430,6 +3430,11 @@ EXFUN (Fxw_display_color_p, 1);
EXFUN (Fx_focus_frame, 1);
#endif
+/* Defined in filewatch.c */
+#ifdef HAVE_FILEWATCH
+extern void syms_of_filewatch (void);
+#endif
+
/* Defined in xfaces.c */
extern Lisp_Object Qdefault, Qtool_bar, Qfringe;
extern Lisp_Object Qheader_line, Qscroll_bar, Qcursor;
--
1.7.5.2
next prev parent reply other threads:[~2011-06-04 23:36 UTC|newest]
Thread overview: 125+ 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 ` Rüdiger Sonderfeld [this message]
2011-06-05 5:45 ` [PATCH update2] " 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 ` Paul Eggert
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 ` [PATCH] Added inotify support Rüdiger Sonderfeld
2012-10-01 16:27 ` 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
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201106050136.35939.ruediger@c-plusplus.de \
--to=ruediger@c-plusplus.de \
--cc=emacs-devel@gnu.org \
/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 public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).