Bug 575708 - runaway inotify madness ...

2009-03-17  Colin Walters  <walters@redhat.com>

	Bug 575708 - runaway inotify madness ...

	* gfilemonitor.c: Queue up events in a local list and
	fire one idle, instead of queuing lots of individual
	idles which has bad performance behavior.


svn path=/trunk/; revision=8010
This commit is contained in:
Colin Walters 2009-03-17 21:59:18 +00:00 committed by Colin Walters
parent 044733e2a0
commit 1d1fba442f
2 changed files with 65 additions and 19 deletions

View File

@ -1,3 +1,11 @@
2009-03-17 Colin Walters <walters@redhat.com>
Bug 575708 - runaway inotify madness ...
* gfilemonitor.c: Queue up events in a local list and
fire one idle, instead of queuing lots of individual
idles which has bad performance behavior.
2009-03-17 Alexander Larsson <alexl@redhat.com> 2009-03-17 Alexander Larsson <alexl@redhat.com>
* glocalfileinputstream.c: * glocalfileinputstream.c:

View File

@ -32,6 +32,10 @@
#include "gioalias.h" #include "gioalias.h"
struct _FileChange;
typedef struct _FileChange FileChange;
static void file_change_free (FileChange *change);
/** /**
* SECTION:gfilemonitor * SECTION:gfilemonitor
* @short_description: File Monitor * @short_description: File Monitor
@ -73,6 +77,9 @@ struct _GFileMonitorPrivate {
/* Rate limiting change events */ /* Rate limiting change events */
GHashTable *rate_limiter; GHashTable *rate_limiter;
guint pending_file_change_id;
GSList *pending_file_changes; /* FileChange */
GSource *timeout; GSource *timeout;
guint32 timeout_fires_at; guint32 timeout_fires_at;
}; };
@ -169,8 +176,19 @@ static void
g_file_monitor_dispose (GObject *object) g_file_monitor_dispose (GObject *object)
{ {
GFileMonitor *monitor; GFileMonitor *monitor;
GFileMonitorPrivate *priv;
monitor = G_FILE_MONITOR (object); monitor = G_FILE_MONITOR (object);
priv = monitor->priv;
if (priv->pending_file_change_id)
{
g_source_remove (priv->pending_file_change_id);
priv->pending_file_change_id = 0;
}
g_slist_foreach (priv->pending_file_changes, (GFunc) file_change_free, NULL);
g_slist_free (priv->pending_file_changes);
priv->pending_file_changes = NULL;
/* Make sure we cancel on last unref */ /* Make sure we cancel on last unref */
g_file_monitor_cancel (monitor); g_file_monitor_cancel (monitor);
@ -320,26 +338,15 @@ g_file_monitor_set_rate_limit (GFileMonitor *monitor,
} }
} }
typedef struct { struct _FileChange {
GFileMonitor *monitor;
GFile *child; GFile *child;
GFile *other_file; GFile *other_file;
GFileMonitorEvent event_type; GFileMonitorEvent event_type;
} FileChange; };
static gboolean
emit_cb (gpointer data)
{
FileChange *change = data;
g_signal_emit (change->monitor, signals[CHANGED], 0,
change->child, change->other_file, change->event_type);
return FALSE;
}
static void static void
file_change_free (FileChange *change) file_change_free (FileChange *change)
{ {
g_object_unref (change->monitor);
g_object_unref (change->child); g_object_unref (change->child);
if (change->other_file) if (change->other_file)
g_object_unref (change->other_file); g_object_unref (change->other_file);
@ -347,6 +354,27 @@ file_change_free (FileChange *change)
g_slice_free (FileChange, change); g_slice_free (FileChange, change);
} }
static gboolean
emit_cb (gpointer data)
{
GFileMonitor *monitor = G_FILE_MONITOR (data);
GSList *pending, *iter;
pending = g_slist_reverse (monitor->priv->pending_file_changes);
monitor->priv->pending_file_changes = NULL;
monitor->priv->pending_file_change_id = 0;
for (iter = pending; iter; iter = iter->next)
{
FileChange *change = iter->data;
g_signal_emit (monitor, signals[CHANGED], 0,
change->child, change->other_file, change->event_type);
file_change_free (change);
}
g_slist_free (pending);
return FALSE;
}
static void static void
emit_in_idle (GFileMonitor *monitor, emit_in_idle (GFileMonitor *monitor,
GFile *child, GFile *child,
@ -355,10 +383,12 @@ emit_in_idle (GFileMonitor *monitor,
{ {
GSource *source; GSource *source;
FileChange *change; FileChange *change;
GFileMonitorPrivate *priv;
priv = monitor->priv;
change = g_slice_new (FileChange); change = g_slice_new (FileChange);
change->monitor = g_object_ref (monitor);
change->child = g_object_ref (child); change->child = g_object_ref (child);
if (other_file) if (other_file)
change->other_file = g_object_ref (other_file); change->other_file = g_object_ref (other_file);
@ -366,12 +396,20 @@ emit_in_idle (GFileMonitor *monitor,
change->other_file = NULL; change->other_file = NULL;
change->event_type = event_type; change->event_type = event_type;
source = g_idle_source_new (); if (!priv->pending_file_change_id)
g_source_set_priority (source, 0); {
source = g_idle_source_new ();
g_source_set_priority (source, 0);
g_source_set_callback (source, emit_cb, change, (GDestroyNotify)file_change_free); /* We don't ref here - instead dispose will free any
g_source_attach (source, NULL); * pending idles.
g_source_unref (source); */
g_source_set_callback (source, emit_cb, monitor, NULL);
priv->pending_file_change_id = g_source_attach (source, NULL);
g_source_unref (source);
}
/* We reverse this in the processor */
priv->pending_file_changes = g_slist_prepend (priv->pending_file_changes, change);
} }
static guint32 static guint32