Re: Rox's directory caching

Stephen Watson <[email protected]> Fri, 29 Aug 2008 12:46:59 +0100
Newsgroups gmane.comp.desktop.rox.devel
Message-ID <[email protected]>
Stephen Watson <[email protected]> wrote:

> "Thomas Leonard" <[email protected]> wrote:
> 
> > >> 2008/8/17 Stephen Watson <[email protected]>:
> > >> > dnotify stopped working for me when I upgraded from SuSE 10.2 to
> 11.0.
> > > As
> > >> > far as I can tell it compiles with dnotify support, it just doesn't
> > > notice
> > >> > when the directory changes.
> > Maybe it's in a separate package? The Ubuntu command comes from the
> > "dnotify" package.
> 
> No such package in SuSE 11.  There's an iwatch for inotify but nothing for
> dnotify.  I wonder if SuSE have given up on dnotify.

This patch adds inotify support, overriding the dnotify support at compile
time.

-- 
Stephen Watson     http://www.kerofin.demon.co.uk/
If you read this on a mailing list, send any reply back to the list and not
to me.  Not even CC.
Forget the shooty dog thing.

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

_______________________________________________
rox-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/rox-devel
0011-Use-inotify-to-monitor-directories-when-available-i.patch (application/octet-stream, 9.9 KB)
From e97ee6b37a8d62145e0034aafd4da797e57f16b2 Mon Sep 17 00:00:00 2001
From: Stephen Watson <[email protected]>
Date: Fri, 22 Aug 2008 22:19:04 +0100
Subject: [PATCH] Use inotify to monitor directories when available, in preference to dnotify.

---
 ROX-Filer/src/action.c     |    2 +-
 ROX-Filer/src/config.h.in  |    1 +
 ROX-Filer/src/configure.in |    2 +-
 ROX-Filer/src/dir.c        |  143 +++++++++++++++++++++++++++++++++++++-------
 ROX-Filer/src/dir.h        |   20 +++++--
 ROX-Filer/src/main.c       |    7 ++
 6 files changed, 145 insertions(+), 30 deletions(-)

diff --git a/ROX-Filer/src/action.c b/ROX-Filer/src/action.c
index e4f7dce..7179519 100644
--- a/ROX-Filer/src/action.c
+++ b/ROX-Filer/src/action.c
@@ -818,7 +818,7 @@ static GUIside *start_action(GtkWidget *abox, ActionChild *func, gpointer data,
 
 			quiet = autoq;
 
-			dir_drop_all_dnotifies();
+			dir_drop_all_notifies();
 
 			/* Reset the SIGCHLD handler */
 			act.sa_handler = SIG_DFL;
diff --git a/ROX-Filer/src/config.h.in b/ROX-Filer/src/config.h.in
index d5bbc01..5bb2428 100644
--- a/ROX-Filer/src/config.h.in
+++ b/ROX-Filer/src/config.h.in
@@ -20,6 +20,7 @@
 #undef HAVE_SYS_VFS_H
 #undef HAVE_SYS_STATVFS_H
 #undef HAVE_LIBINTL_H
+#undef HAVE_SYS_INOTIFY_H
 
 #undef HAVE_MBRTOWC
 #undef HAVE_WCTYPE_H
diff --git a/ROX-Filer/src/configure.in b/ROX-Filer/src/configure.in
index c47db4b..a9ab9d2 100644
--- a/ROX-Filer/src/configure.in
+++ b/ROX-Filer/src/configure.in
@@ -164,7 +164,7 @@ dnl Checks for header files.
 AC_HEADER_DIRENT
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h mntent.h sys/ucred.h sys/mntent.h apsymbols.h apbuild/apsymbols.h sys/statvfs.h sys/vfs.h wctype.h libintl.h)
+AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h mntent.h sys/ucred.h sys/mntent.h apsymbols.h apbuild/apsymbols.h sys/statvfs.h sys/vfs.h wctype.h libintl.h sys/inotify.h)
 
 AC_CHECK_HEADER([X11/SM/SMlib.h], [],
   [AC_MSG_ERROR([Session management library (libsm) missing. It is part of the X server distribution. Try installing the libsm-dev package.])]
diff --git a/ROX-Filer/src/dir.c b/ROX-Filer/src/dir.c
index fa820cf..1172c2e 100644
--- a/ROX-Filer/src/dir.c
+++ b/ROX-Filer/src/dir.c
@@ -69,11 +69,18 @@
 #include "usericons.h"
 #include "main.h"
 
+#ifdef USE_NOTIFY
+static GHashTable *notify_fd_to_dir = NULL;
+#endif
+#ifdef USE_INOTIFY
+# include <sys/inotify.h>
+GIOChannel *inotify_channel;
+static int inotify_fd;
+#endif
 #ifdef USE_DNOTIFY
 /* Newer Linux kernels can tell us when the directories we are watching
  * change, using the dnotify system.
  */
-static GHashTable *dnotify_fd_to_dir = NULL;
 gboolean dnotify_wakeup_flag = FALSE;
 static int dnotify_last_fd = -1;
 #endif
@@ -94,9 +101,14 @@ static GPtrArray *hash_to_array(GHashTable *hash);
 static void dir_force_update_item(Directory *dir, const gchar *leaf);
 static Directory *dir_new(const char *pathname);
 static void dir_rescan(Directory *dir);
-#ifdef USE_DNOTIFY
+#ifdef USE_NOTIFY
 static void dir_rescan_soon(Directory *dir);
+# ifdef USE_INOTIFY
+static gboolean inotify_handler(GIOChannel *source, GIOCondition condition,
+			    gpointer udata);
+# else
 static void dnotify_handler(int sig, siginfo_t *si, void *data);
+# endif
 #endif
 
 /****************************************************************
@@ -108,8 +120,16 @@ void dir_init(void)
 	dir_cache = g_fscache_new((GFSLoadFunc) dir_new,
 				(GFSUpdateFunc) update, NULL);
 
-	/* Check for dnotify support in the kernel */
-#ifdef USE_DNOTIFY
+#ifdef USE_NOTIFY
+	notify_fd_to_dir = g_hash_table_new(NULL, NULL);
+
+# ifdef USE_INOTIFY
+	inotify_fd = inotify_init();
+	inotify_channel = g_io_channel_unix_new(inotify_fd);
+	g_io_add_watch(inotify_channel, G_IO_IN, inotify_handler, NULL);
+# endif
+	
+# ifdef USE_DNOTIFY
 	{
 		struct sigaction act;
 
@@ -126,8 +146,8 @@ void dir_init(void)
 		act.sa_flags = 0;
 		sigaction(SIGIO, &act, NULL);
 
-		dnotify_fd_to_dir = g_hash_table_new(NULL, NULL);
 	}
+# endif
 #endif
 }
 
@@ -151,21 +171,45 @@ void dir_attach(Directory *dir, DirCallback callback, gpointer data)
 	user->callback = callback;
 	user->data = data;
 
+#ifdef USE_INOTIFY
+	if (!dir->users)
+	{
+		int fd;
+
+		if (dir->notify_fd != -1)
+			g_warning("dir_attach: inotify error\n");
+
+		fd = inotify_add_watch( inotify_fd,
+					dir->pathname,
+					IN_CREATE | IN_DELETE | IN_MOVE |
+					IN_ATTRIB); 
+		
+		g_return_if_fail(g_hash_table_lookup(notify_fd_to_dir,
+						 GINT_TO_POINTER(fd)) == NULL);
+		if (fd != -1)
+		{
+		  
+			dir->notify_fd = fd;
+			g_hash_table_insert(notify_fd_to_dir,
+					    GINT_TO_POINTER(fd), dir);
+		}
+	}
+#endif
 #ifdef USE_DNOTIFY
 	if (!dir->users)
 	{
 		int fd;
 		
-		if (dir->dnotify_fd != -1)
+		if (dir->notify_fd != -1)
 			g_warning("dir_attach: dnotify error\n");
 		
 		fd = open(dir->pathname, O_RDONLY);
-		g_return_if_fail(g_hash_table_lookup(dnotify_fd_to_dir,
+		g_return_if_fail(g_hash_table_lookup(notify_fd_to_dir,
 				 GINT_TO_POINTER(fd)) == NULL);
 		if (fd != -1)
 		{
-			dir->dnotify_fd = fd;
-			g_hash_table_insert(dnotify_fd_to_dir,
+			dir->notify_fd = fd;
+			g_hash_table_insert(notify_fd_to_dir,
 					GINT_TO_POINTER(fd), dir);
 			fcntl(fd, F_SETSIG, SIGRTMIN);
 			fcntl(fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_RENAME |
@@ -217,14 +261,22 @@ void dir_detach(Directory *dir, DirCallback callback, gpointer data)
 			/* May stop scanning if noone's watching */
 			set_idle_callback(dir);
 
-#ifdef USE_DNOTIFY
-			if (!dir->users && dir->dnotify_fd != -1)
+#ifdef USE_NOTIFY
+			if (!dir->users && dir->notify_fd != -1)
 			{
-				close(dir->dnotify_fd);
-				g_hash_table_remove(dnotify_fd_to_dir,
-					GINT_TO_POINTER(dir->dnotify_fd));
-				dir->dnotify_fd = -1;
+# ifdef USE_DNOTIFY
+				close(dir->notify_fd);
+# endif
+				g_hash_table_remove(notify_fd_to_dir,
+					GINT_TO_POINTER(dir->notify_fd));
+				dir->notify_fd = -1;
 			}
+# ifdef USE_INOTIFY
+			if (dir->inotify_source) {
+				g_source_remove(dir->inotify_source);
+				dir->inotify_source = 0;
+			}
+# endif
 #endif
 			return;
 		}
@@ -268,20 +320,26 @@ void dir_check_this(const guchar *path)
 	g_free(real_path);
 }
 
-#ifdef USE_DNOTIFY
-static void drop_dnotify(gpointer key, gpointer value, gpointer data)
+#ifdef USE_NOTIFY
+static void drop_notify(gpointer key, gpointer value, gpointer data)
 {
+#ifdef USE_INOTIFY
+        inotify_rm_watch(inotify_fd, GPOINTER_TO_INT(key));
+#endif
+#ifdef USE_DNOTIFY
 	close(GPOINTER_TO_INT(key));
+#endif
 }
 #endif
 
 /* Used when we fork an action child, otherwise we can't delete or unmount
- * any directory which we're watching!
+ * any directory which we're watching via dnotify!  inotify does not have
+ * this problem
  */
-void dir_drop_all_dnotifies(void)
+void dir_drop_all_notifies(void)
 {
 #ifdef USE_DNOTIFY
-	g_hash_table_foreach(dnotify_fd_to_dir, drop_dnotify, NULL);
+	g_hash_table_foreach(notify_fd_to_dir, drop_notify, NULL);
 #endif
 }
 
@@ -502,7 +560,7 @@ void dnotify_wakeup(void)
  *			INTERNAL FUNCTIONS			*
  ****************************************************************/
 
-#ifdef USE_DNOTIFY
+#ifdef USE_NOTIFY
 static gint rescan_soon_timeout(gpointer data)
 {
 	Directory *dir = (Directory *) data;
@@ -899,8 +957,11 @@ static void directory_init(GTypeInstance *object, gpointer gclass)
 	dir->pathname = NULL;
 	dir->error = NULL;
 	dir->rescan_timeout = -1;
-#ifdef USE_DNOTIFY
-	dir->dnotify_fd = -1;
+#ifdef USE_NOTIFY
+	dir->notify_fd = -1;
+#endif
+#ifdef USE_INOTIFY
+	dir->inotify_source = 0;
 #endif
 
 	dir->new_items = g_ptr_array_new();
@@ -1080,3 +1141,39 @@ static void dnotify_handler(int sig, siginfo_t *si, void *data)
 	write(to_wakeup_pipe, "\0", 1);	/* Wake up! */
 }
 #endif
+
+#ifdef USE_INOTIFY
+static gboolean inotify_handler(GIOChannel *source, GIOCondition condition,
+				gpointer udata)
+{
+	int fd = g_io_channel_unix_get_fd(source);
+	Directory *dir;
+	char buf[sizeof(struct inotify_event)+1024];
+	int len, i = 0;
+
+	len = read(fd, buf, sizeof(buf));
+	if (len<0)
+	{
+		if (errno != EINTR)
+			perror("read");
+		return TRUE;
+	}
+	else if (!len)
+		return TRUE;
+
+	while (i<len)
+	{
+		struct inotify_event *event=(struct inotify_event *) (buf+i);
+
+		dir = g_hash_table_lookup(notify_fd_to_dir,
+					  GINT_TO_POINTER(event->wd));
+		if (dir)
+			dir_rescan_soon(dir);
+    
+		i += sizeof(*event)+event->len;
+	}
+
+
+	return TRUE;
+}
+#endif
diff --git a/ROX-Filer/src/dir.h b/ROX-Filer/src/dir.h
index a66e413..deb71aa 100644
--- a/ROX-Filer/src/dir.h
+++ b/ROX-Filer/src/dir.h
@@ -13,9 +13,14 @@
 #include <signal.h>
 #include <fcntl.h>
 
-/* Check for dnotify support */
-#if defined(DN_MULTISHOT) && defined(SIGRTMIN)
+/* Check for [id]notify support */
+#if defined(HAVE_SYS_INOTIFY_H)
+# define USE_INOTIFY
+#elif defined(DN_MULTISHOT) && defined(SIGRTMIN)
 # define USE_DNOTIFY
+#endif
+#if defined(USE_INOTIFY) || defined(USE_DNOTIFY)
+#define USE_NOTIFY
 extern gboolean dnotify_wakeup_flag;
 #endif
 
@@ -84,8 +89,11 @@ struct _Directory
 
 	gint		rescan_timeout;	/* See dir_rescan_soon() */
 
-#ifdef USE_DNOTIFY
-	int		dnotify_fd;	/* -1 if not watching */
+#ifdef USE_NOTIFY
+	int		notify_fd;	/* -1 if not watching */
+#endif
+#ifdef USE_INOTIFY
+        guint           inotify_source;
 #endif
 };
 
@@ -98,8 +106,10 @@ void dir_check_this(const guchar *path);
 DirItem *dir_update_item(Directory *dir, const gchar *leafname);
 void dir_merge_new(Directory *dir);
 void dir_force_update_path(const gchar *path);
+#if defined(USE_DNOTIFY)
 void dnotify_wakeup(void);
-void dir_drop_all_dnotifies(void);
+#endif
+void dir_drop_all_notifies(void);
 void dir_queue_recheck(Directory *dir, DirItem *item);
 
 #endif /* _DIR_H */
diff --git a/ROX-Filer/src/main.c b/ROX-Filer/src/main.c
index 3f3949e..f8463ae 100644
--- a/ROX-Filer/src/main.c
+++ b/ROX-Filer/src/main.c
@@ -695,6 +695,13 @@ static void show_features(void)
 		_("No")
 #endif
 		);
+	g_print("%s... %s\n", _("Inotify support"),
+#ifdef USE_INOTIFY
+		_("Yes")
+#else
+		_("No")
+#endif
+	       );
 	g_print("%s... %s\n", _("Dnotify support"),
 #ifdef USE_DNOTIFY
 		_("Yes")
-- 
1.5.4.5