[gamin] An updated gam_inotify.c
- From: John McCutchan <ttb tentacle dhs org>
- To: gamin-list gnome org, nautilus-list gnome org
- Cc:
- Subject: [gamin] An updated gam_inotify.c
- Date: Mon, 19 Jul 2004 20:47:14 -0400
I had left on some inotify debug messages in the first gam_inotify.c
file. Also I have tested this while running nautilus and things didn't
blow up (They actually worked).
Attached is a new gam_inotify.c
John
/* Marmot
* Copyright (C) 2004 John McCutchan, James Willcox, Corey Bowers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#define _GNU_SOURCE
#include <fcntl.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <glib.h>
#include "/usr/src/linux/include/linux/inotify.h"
#include "gam_error.h"
#include "gam_poll.h"
#include "gam_inotify.h"
#include "gam_tree.h"
#include "gam_event.h"
#include "gam_server.h"
#include "gam_event.h"
/* just pulling a value out of nowhere here...may need tweaking */
#define MAX_QUEUE_SIZE 500
typedef struct {
char *path;
int wd;
int refcount;
} INotifyData;
static GHashTable *path_hash = NULL;
static GHashTable *wd_hash = NULL;
G_LOCK_DEFINE_STATIC(inotify);
static GQueue *changes = NULL;
#ifdef WITH_TREADING
static GMainContext *loop_context;
#endif
static GIOChannel *inotify_read_ioc = NULL;
static gboolean have_consume_idler = FALSE;
int fd = -1; // the device fd
static INotifyData *
gam_inotify_data_new(const char *path, int wd)
{
INotifyData *data;
data = g_new0(INotifyData, 1);
data->path = g_strdup(path);
data->wd = wd;
data->refcount = 1;
return data;
}
static void
gam_inotify_data_free(INotifyData * data)
{
g_free(data->path);
g_free(data);
}
static void
gam_inotify_directory_handler(const char *path, gboolean added)
{
INotifyData *data;
struct inotify_watch_request iwr;
int wd,r;
G_LOCK(inotify);
if (added) {
if ((data = g_hash_table_lookup(path_hash, path)) != NULL) {
data->refcount++;
G_UNLOCK(inotify);
return;
}
iwr.dirname = g_strdup(path);
iwr.mask = IN_MODIFY|IN_CREATE|IN_DELETE|IN_RENAME|IN_ATTRIB|IN_UNMOUNT|IN_IGNORED;
wd = ioctl(fd, INOTIFY_WATCH,&iwr);
g_free(iwr.dirname);
if (wd < 0) {
G_UNLOCK(inotify);
return;
}
data = gam_inotify_data_new(path, wd);
g_hash_table_insert(wd_hash, GINT_TO_POINTER(data->wd), data);
g_hash_table_insert(path_hash, data->path, data);
gam_debug(DEBUG_INFO, "activated INotify for %s\n", path);
} else {
data = g_hash_table_lookup(path_hash, path);
if (!data) {
G_UNLOCK(inotify);
return;
}
data->refcount--;
if (data->refcount == 0) {
r = ioctl (fd, INOTIFY_IGNORE, &data->wd);
if (r < 0) {
gam_debug (DEBUG_INFO, "INOTIFY_IGNORE failed for %s\n", data->path);
}
gam_debug(DEBUG_INFO, "deactivated INotify for %s\n",
data->path);
g_hash_table_remove(path_hash, data->path);
g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd));
gam_inotify_data_free(data);
}
}
G_UNLOCK(inotify);
}
static void
gam_inotify_file_handler(const char *path, gboolean added)
{
char *dir;
dir = g_path_get_dirname(path);
gam_inotify_directory_handler(dir, added);
g_free(dir);
}
#ifdef WITH_TREADING
static gpointer
gam_inotify_scan_loop(gpointer data)
{
g_main_loop_run(g_main_loop_new(loop_context, TRUE));
return (NULL);
}
#endif
static gboolean
gam_inotify_read_handler(gpointer user_data)
{
struct inotify_event event;
INotifyData *data;
gam_debug(DEBUG_INFO, "gam_inotify_read_handler()\n");
if (g_io_channel_read_chars(inotify_read_ioc, (char *)&event, sizeof(struct inotify_event), NULL, NULL) != G_IO_STATUS_NORMAL) {
gam_debug(DEBUG_INFO, "gam_inotify_read_handler failed\n");
return FALSE;
}
// ioctl(fd, INOTIFY_STATS,0); // inotify debug
G_LOCK(inotify);
data = g_hash_table_lookup (wd_hash, GINT_TO_POINTER(event.wd));
G_UNLOCK(inotify);
if (!data) {
gam_debug(DEBUG_INFO, "Could not find WD %d in hash\n", event.wd);
return TRUE;
}
gam_debug(DEBUG_INFO, "gam_inotify event for %s (%x)\n", data->path, event.mask);
gam_poll_scan_directory(data->path, NULL);
gam_debug(DEBUG_INFO, "gam_inotify_read_handler() done\n");
return TRUE;
}
static gboolean
gam_inotify_consume_subscriptions_real(gpointer data)
{
gam_poll_consume_subscriptions();
have_consume_idler = FALSE;
return FALSE;
}
static void
gam_inotify_consume_subscriptions(void)
{
GSource *source;
if (have_consume_idler)
return;
have_consume_idler = TRUE;
source = g_idle_source_new();
g_source_set_callback(source, gam_inotify_consume_subscriptions_real,
NULL, NULL);
#ifdef WITH_TREADING
g_source_attach(source, loop_context);
#else
g_source_attach(source, NULL);
#endif
}
/**
* @defgroup INotify INotify Backend
* @ingroup Backends
* @brief INotify backend API
*
* Since version 2.X, Linux kernels have included the Linux Inode
* Notification system (inotify). This backend uses inotify to know when
* files are changed/created/deleted. Since inotify doesn't tell us
* exactly what event happened to which file (just that some even happened
* in some directory), we still have to cache stat() information. For this,
* we can just use the code in the polling backend.
*
* @{
*/
/**
* Initializes the inotify system. This must be called before
* any other functions in this module.
*
* @returns TRUE if initialization succeeded, FALSE otherwise
*/
gboolean
gam_inotify_init(void)
{
GSource *source;
g_return_val_if_fail(gam_poll_init_full(FALSE), FALSE);
fd = open("/dev/inotify", O_RDONLY);
if (fd < 0) {
g_warning("Could not open /dev/inotify\n");
return FALSE;
}
inotify_read_ioc = g_io_channel_unix_new(fd);
/* For binary data */
g_io_channel_set_encoding (inotify_read_ioc, NULL, NULL);
/* Non blocking */
g_io_channel_set_flags(inotify_read_ioc, G_IO_FLAG_NONBLOCK, NULL);
#ifdef WITH_TREADING
loop_context = g_main_context_new();
#endif
source = g_io_create_watch(inotify_read_ioc,
G_IO_IN | G_IO_HUP | G_IO_ERR);
g_source_set_callback(source, gam_inotify_read_handler, NULL, NULL);
#ifdef WITH_TREADING
g_source_attach(source, loop_context);
#else
g_source_attach(source, NULL);
#endif
changes = g_queue_new();
#ifdef WITH_TREADING
g_thread_create(gam_inotify_scan_loop, NULL, TRUE, NULL);
#endif
path_hash = g_hash_table_new(g_str_hash, g_str_equal);
wd_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
gam_poll_set_directory_handler(gam_inotify_directory_handler);
gam_poll_set_file_handler(gam_inotify_file_handler);
gam_debug(DEBUG_INFO, "inotify initialized\n");
return TRUE;
}
/**
* Adds a subscription to be monitored.
*
* @param sub a #GamSubscription to be polled
* @returns TRUE if adding the subscription succeeded, FALSE otherwise
*/
gboolean
gam_inotify_add_subscription(GamSubscription * sub)
{
if (!gam_poll_add_subscription(sub)) {
return FALSE;
}
if (gam_subscription_is_dir(sub)) {
gam_inotify_consume_subscriptions();
}
return TRUE;
}
/**
* Removes a subscription which was being monitored.
*
* @param sub a #GamSubscription to remove
* @returns TRUE if removing the subscription succeeded, FALSE otherwise
*/
gboolean
gam_inotify_remove_subscription(GamSubscription * sub)
{
if (!gam_poll_remove_subscription(sub)) {
return FALSE;
}
if (gam_subscription_is_dir(sub)) {
gam_inotify_consume_subscriptions();
}
return TRUE;
}
/**
* Stop monitoring all subscriptions for a given listener.
*
* @param listener a #GamListener
* @returns TRUE if removing the subscriptions succeeded, FALSE otherwise
*/
gboolean
gam_inotify_remove_all_for(GamListener * listener)
{
if (!gam_poll_remove_all_for(listener)) {
return FALSE;
}
gam_inotify_consume_subscriptions();
return TRUE;
}
/** @} */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]