[gamin] gamin patch
- From: John McCutchan <ttb tentacle dhs org>
- To: gamin-list gnome org
- Subject: [gamin] gamin patch
- Date: Wed, 04 Aug 2004 21:24:46 -0400
Yo,
Attached is a patch that contains:
-An updated inotify backend
This new backend does not need the poll backend.
-Change the retry delay from 100 to 1000 microseconds
At 100 I found it was retrying too fast
-Changes the failure code for gam_server when it can't load
the subscription backend or it can't start the server
This is a real bug. gam_server would call g_error()
when it couldn't start the server and dump core.
gam_server not starting is not an error [as seen
in the startup races]
Also the inotify backend could fail to startup
if more than 8 programs have opened /dev/inotify.
in this two cases, the g_error() turns in to gam_debug()
and we exit.
John
Index: libgamin/gam_api.c
===================================================================
RCS file: /cvs/gnome/gamin/libgamin/gam_api.c,v
retrieving revision 1.12
diff -u -r1.12 gam_api.c
--- libgamin/gam_api.c 3 Aug 2004 12:55:03 -0000 1.12
+++ libgamin/gam_api.c 5 Aug 2004 01:15:59 -0000
@@ -344,9 +344,9 @@
goto retry_start;
}
if (retries < MAX_RETRIES) {
- usleep(100);
- retries++;
close(fd);
+ usleep(1000);
+ retries++;
goto retry_start;
}
Index: server/gam_event.h
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_event.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 gam_event.h
--- server/gam_event.h 15 Jun 2004 19:30:49 -0000 1.1.1.1
+++ server/gam_event.h 5 Aug 2004 01:16:00 -0000
@@ -9,7 +9,8 @@
GAMIN_EVENT_DELETED = 1 << 6,
GAMIN_EVENT_MOVED = 1 << 7,
GAMIN_EVENT_EXISTS = 1 << 8,
- GAMIN_EVENT_ENDEXISTS = 1 << 9
+ GAMIN_EVENT_ENDEXISTS = 1 << 9,
+ GAMIN_EVENT_UNKNOWN = 1 << 10
} GaminEventType;
const char *gam_event_to_string (GaminEventType event);
Index: server/gam_inotify.c
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_inotify.c,v
retrieving revision 1.1
diff -u -r1.1 gam_inotify.c
--- server/gam_inotify.c 27 Jul 2004 10:24:43 -0000 1.1
+++ server/gam_inotify.c 5 Aug 2004 01:16:00 -0000
@@ -28,36 +28,33 @@
#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;
+ GList *subs;
} INotifyData;
static GHashTable *path_hash = NULL;
static GHashTable *wd_hash = NULL;
-G_LOCK_DEFINE_STATIC(inotify);
-
-static GQueue *changes = NULL;
+static GList *new_subs = NULL;
+G_LOCK_DEFINE_STATIC(new_subs);
+static GList *removed_subs = NULL;
+G_LOCK_DEFINE_STATIC(removed_subs);
-#ifdef WITH_TREADING
-static GMainContext *loop_context;
-#endif
+G_LOCK_DEFINE_STATIC(inotify);
static GIOChannel *inotify_read_ioc = NULL;
static gboolean have_consume_idler = FALSE;
+
int fd = -1; // the device fd
static INotifyData *
@@ -69,6 +66,7 @@
data->path = g_strdup(path);
data->wd = wd;
data->refcount = 1;
+ data->subs = NULL;
return data;
}
@@ -81,7 +79,7 @@
}
static void
-gam_inotify_directory_handler(const char *path, gboolean added)
+gam_inotify_add_rm_handler(const char *path, GamSubscription *sub, gboolean added)
{
INotifyData *data;
struct inotify_watch_request iwr;
@@ -90,15 +88,20 @@
G_LOCK(inotify);
if (added) {
+ GList *subs;
+
+ subs = NULL;
if ((data = g_hash_table_lookup(path_hash, path)) != NULL) {
data->refcount++;
+ data->subs = g_list_prepend(data->subs, sub);
G_UNLOCK(inotify);
+ gam_debug(DEBUG_INFO, "inotify updated refcount\n");
return;
}
iwr.dirname = g_strdup(path);
- iwr.mask = IN_MODIFY|IN_CREATE|IN_DELETE|IN_RENAME|IN_ATTRIB|IN_UNMOUNT|IN_IGNORED;
+ iwr.mask = 0xffffffff; // all events
wd = ioctl(fd, INOTIFY_WATCH,&iwr);
g_free(iwr.dirname);
@@ -110,10 +113,16 @@
data = gam_inotify_data_new(path, wd);
+ data->subs = g_list_prepend(data->subs, sub);
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);
+
+ subs = g_list_append(subs, sub);
+
+ gam_server_emit_event (path, GAMIN_EVENT_EXISTS, subs);
+ gam_server_emit_event (path, GAMIN_EVENT_ENDEXISTS, subs);
} else {
data = g_hash_table_lookup(path_hash, path);
@@ -122,7 +131,11 @@
return;
}
+ if (g_list_find (data->subs, sub)) {
+ data->subs = g_list_remove_all (data->subs, sub);
+ }
data->refcount--;
+ gam_debug(DEBUG_INFO, "inotify decremeneted refcount\n");
if (data->refcount == 0) {
r = ioctl (fd, INOTIFY_IGNORE, &data->wd);
@@ -140,24 +153,61 @@
G_UNLOCK(inotify);
}
-static void
-gam_inotify_file_handler(const char *path, gboolean added)
+
+static GaminEventType inotify_event_to_gamin_event (int mask)
{
- char *dir;
+ switch (mask)
+ {
+ case IN_ATTRIB:
+ case IN_MODIFY:
+ return GAMIN_EVENT_CHANGED;
+ break;
+ case IN_CREATE:
+ return GAMIN_EVENT_CREATED;
+ break;
+ case IN_DELETE:
+ return GAMIN_EVENT_DELETED;
+ break;
+ case IN_RENAME:
+ case IN_MOVE:
+ return GAMIN_EVENT_MOVED;
+ break;
+ default:
+ return GAMIN_EVENT_UNKNOWN;
+ }
+}
+static void gam_inotify_emit_event (INotifyData *data, struct inotify_event *event)
+{
+ GaminEventType gevent;
+ char *event_path;
+
+ if (!data||!event)
+ return;
+
+ gevent = inotify_event_to_gamin_event (event->mask);
+ // we got some event that GAMIN doesn't understand
+ if (gevent == GAMIN_EVENT_UNKNOWN) {
+ gam_debug(DEBUG_INFO, "inotify_emit_event got unknown event %x\n", event->mask);
+ return;
+ }
+
+ if (event->filename[0] != '\0') {
+ int pathlen = strlen(data->path);
+ gam_debug(DEBUG_INFO, "Got filename with event\n");
+ if (data->path[pathlen-1] == '/') {
+ event_path = g_strconcat (data->path, event->filename, NULL);
+ } else {
+ event_path = g_strconcat (data->path, "/", event->filename, NULL);
+ }
+ } else {
+ gam_debug(DEBUG_INFO, "Got not filename with event\n");
+ event_path = g_strdup (data->path);
+ }
- dir = g_path_get_dirname(path);
- gam_inotify_directory_handler(dir, added);
- g_free(dir);
-}
+ gam_debug(DEBUG_INFO, "gam_inotify_emit_event() %s\n", event_path);
-#ifdef WITH_TREADING
-static gpointer
-gam_inotify_scan_loop(gpointer data)
-{
- g_main_loop_run(g_main_loop_new(loop_context, TRUE));
- return (NULL);
+ gam_server_emit_event (event_path, gevent, data->subs);
}
-#endif
static gboolean
gam_inotify_read_handler(gpointer user_data)
@@ -169,11 +219,29 @@
G_LOCK(inotify);
if (g_io_channel_read_chars(inotify_read_ioc, (char *)&event, sizeof(struct inotify_event), NULL, NULL) != G_IO_STATUS_NORMAL) {
+ G_UNLOCK(inotify);
gam_debug(DEBUG_INFO, "gam_inotify_read_handler failed\n");
return FALSE;
}
+ /* Need to walk data->subs list and remove this from each subscription
+ if (event.mask == IN_IGNORE) {
+ data = g_hash_table_lookup (wd_hash, GINT_TO_POINTER(event.wd));
+
+ if (!data) {
+ G_UNLOCK(inotify);
+ return TRUE;
+ }
+
+ 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);
+ return TRUE;
+ }
+ */
+
data = g_hash_table_lookup (wd_hash, GINT_TO_POINTER(event.wd));
if (!data) {
@@ -182,20 +250,9 @@
return TRUE;
}
- /* TODO: Handle IGNORED events (they come after UMOUNT events!) */
- /*
- if (event.mask & IN_IGNORED) {
- gam_debug(DEBUG_INFO, "Removing wd %d from hash after IN_IGNORED\n", event.wd);
- 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);
- return TRUE;
- }
- */
+ gam_inotify_emit_event (data, &event);
- 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 event for %s (%x) %s\n", data->path, event.mask, event.filename);
gam_debug(DEBUG_INFO, "gam_inotify_read_handler() done\n");
@@ -207,28 +264,59 @@
static gboolean
gam_inotify_consume_subscriptions_real(gpointer data)
{
- gam_poll_consume_subscriptions();
- have_consume_idler = FALSE;
- return FALSE;
+ GList *subs, *l;
+
+ G_LOCK(new_subs);
+ if (new_subs) {
+ subs = new_subs;
+ new_subs = NULL;
+ G_UNLOCK(new_subs);
+
+ for (l = subs; l; l = l->next) {
+ GamSubscription *sub = l->data;
+ gam_debug(DEBUG_INFO, "called gam_inotify_add_handler()\n");
+ gam_inotify_add_rm_handler (gam_subscription_get_path (sub), sub, TRUE);
+ }
+
+ } else {
+ G_UNLOCK(new_subs);
+ }
+
+ G_LOCK(removed_subs);
+ if (removed_subs) {
+ subs = removed_subs;
+ removed_subs = NULL;
+ G_UNLOCK(removed_subs);
+
+ for (l = subs; l; l = l->next) {
+ GamSubscription *sub = l->data;
+ gam_debug(DEBUG_INFO, "called gam_inotify_rm_handler()\n");
+ gam_inotify_add_rm_handler (gam_subscription_get_path (sub), sub, FALSE);
+ }
+ } else {
+ G_UNLOCK(removed_subs);
+ }
+
+ gam_debug(DEBUG_INFO, "gam_inotify_consume_subscriptions()\n");
+
+ have_consume_idler = FALSE;
+ return FALSE;
}
static void
gam_inotify_consume_subscriptions(void)
{
- GSource *source;
+ GSource *source;
- if (have_consume_idler)
- return;
+ 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
+ have_consume_idler = TRUE;
+
+ source = g_idle_source_new ();
+ g_source_set_callback (source, gam_inotify_consume_subscriptions_real, NULL, NULL);
+
+ g_source_attach (source, NULL);
}
/**
@@ -236,12 +324,9 @@
* @ingroup Backends
* @brief INotify backend API
*
- * Since version 2.X, Linux kernels have included the Linux Inode
+ * Since version 2.6.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.
+ * files are changed/created/deleted.
*
* @{
*/
@@ -258,8 +343,6 @@
{
GSource *source;
- g_return_val_if_fail(gam_poll_init_full(FALSE), FALSE);
-
fd = open("/dev/inotify", O_RDONLY);
if (fd < 0) {
@@ -274,34 +357,18 @@
/* 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");
- int i = INOTIFY_DEBUG_INODE|INOTIFY_DEBUG_ERRORS|INOTIFY_DEBUG_EVENTS;
+ int i = 0; // INOTIFY_DEBUG_INODE|INOTIFY_DEBUG_ERRORS|INOTIFY_DEBUG_EVENTS;
ioctl(fd, INOTIFY_SETDEBUG, &i);
return TRUE;
@@ -316,14 +383,15 @@
gboolean
gam_inotify_add_subscription(GamSubscription * sub)
{
- if (!gam_poll_add_subscription(sub)) {
- return FALSE;
- }
+ gam_listener_add_subscription(gam_subscription_get_listener(sub), sub);
- if (gam_subscription_is_dir(sub)) {
- gam_inotify_consume_subscriptions();
- }
+ G_LOCK(new_subs);
+ new_subs = g_list_prepend(new_subs, sub);
+ G_UNLOCK(new_subs);
+ gam_debug(DEBUG_INFO, "inotify_add_sub\n");
+
+ gam_inotify_consume_subscriptions();
return TRUE;
}
@@ -336,13 +404,24 @@
gboolean
gam_inotify_remove_subscription(GamSubscription * sub)
{
- if (!gam_poll_remove_subscription(sub)) {
- return FALSE;
- }
+ G_LOCK(new_subs);
+ if (g_list_find(new_subs, sub)) {
+ gam_debug(DEBUG_INFO, "removed sub found on new_subs\n");
+ new_subs = g_list_remove_all (new_subs, sub);
+ G_UNLOCK(new_subs);
+ return TRUE;
+ }
+ G_UNLOCK(new_subs);
+
+ gam_subscription_cancel (sub);
+ gam_listener_remove_subscription(gam_subscription_get_listener(sub), sub);
+
+ G_LOCK(removed_subs);
+ removed_subs = g_list_prepend (removed_subs, sub);
+ G_UNLOCK(removed_subs);
- if (gam_subscription_is_dir(sub)) {
- gam_inotify_consume_subscriptions();
- }
+ gam_debug(DEBUG_INFO, "inotify_remove_sub\n");
+ gam_inotify_consume_subscriptions();
return TRUE;
}
@@ -356,15 +435,27 @@
gboolean
gam_inotify_remove_all_for(GamListener * listener)
{
- if (!gam_poll_remove_all_for(listener)) {
- return FALSE;
- }
+ GList *subs, *l = NULL;
- gam_inotify_consume_subscriptions();
+ subs = gam_listener_get_subscriptions (listener);
- return TRUE;
+ for (l = subs; l; l = l->next) {
+ GamSubscription *sub = l->data;
+
+ g_assert (sub != NULL);
+
+ gam_inotify_remove_subscription (sub);
+
+ }
+
+ if (subs) {
+ g_list_free (subs);
+ gam_inotify_consume_subscriptions();
+ return TRUE;
+ } else {
+ return FALSE;
+ }
}
/** @} */
-
#endif /* USE_INOTIFY */
Index: server/gam_server.c
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_server.c,v
retrieving revision 1.4
diff -u -r1.4 gam_server.c
--- server/gam_server.c 29 Jul 2004 14:32:48 -0000 1.4
+++ server/gam_server.c 5 Aug 2004 01:16:00 -0000
@@ -32,6 +32,9 @@
#include "gam_channel.h"
#include "gam_subscription.h"
#include "gam_poll.h"
+#ifdef USE_INOTIFY
+#include "gam_inotify.h"
+#endif
#ifdef linux
#include "gam_dnotify.h"
#endif
@@ -79,7 +82,9 @@
gboolean
gam_add_subscription(GamSubscription * sub)
{
-#ifdef linux
+#ifdef USE_INOTIFY
+ return (gam_inotify_add_subscription(sub));
+#elif linux
return (gam_dnotify_add_subscription(sub));
#else
return (gam_poll_add_subscription(sub));
@@ -96,7 +101,9 @@
gboolean
gam_remove_subscription(GamSubscription * sub)
{
-#ifdef linux
+#ifdef USE_INOTIFY
+ return (gam_inotify_remove_subscription(sub));
+#elif linux
return (gam_dnotify_remove_subscription(sub));
#else
return (gam_poll_remove_subscription(sub));
@@ -247,8 +254,8 @@
#endif
if (!gam_init_subscriptions()) {
- g_error("Could not initialize the subscription system.\n");
- exit(1);
+ gam_debug(DEBUG_INFO, "Could not initialize the subscription system.\n");
+ exit(0);
}
loop = g_main_loop_new(NULL, FALSE);
@@ -258,8 +265,8 @@
}
if (!gam_server_init(loop, session)) {
- g_error("Couldn't initialize the server.\n");
- exit(1);
+ gam_debug(DEBUG_INFO, "Couldn't initialize the server.\n");
+ exit(0);
}
g_main_loop_run(loop);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]