Emit actual change signals in an idle handler. This avoids reentrance and

2008-02-25  Alexander Larsson  <alexl@redhat.com>

        * gfilemonitor.c:
	Emit actual change signals in an idle handler.
	This avoids reentrance and locking problems in
	the file notification backends.


svn path=/trunk/; revision=6584
This commit is contained in:
Alexander Larsson 2008-02-25 12:34:30 +00:00 committed by Alexander Larsson
parent 1f3dac3c63
commit ea678ee94c
2 changed files with 70 additions and 8 deletions

View File

@ -1,3 +1,10 @@
2008-02-25 Alexander Larsson <alexl@redhat.com>
* gfilemonitor.c:
Emit actual change signals in an idle handler.
This avoids reentrance and locking problems in
the file notification backends.
2008-02-25 Alexander Larsson <alexl@redhat.com>
* gunixmounts.c:

View File

@ -302,6 +302,60 @@ g_file_monitor_set_rate_limit (GFileMonitor *monitor,
}
}
typedef struct {
GFileMonitor *monitor;
GFile *child;
GFile *other_file;
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
file_change_free (FileChange *change)
{
g_object_unref (change->monitor);
g_object_unref (change->child);
if (change->other_file)
g_object_unref (change->other_file);
g_slice_free (FileChange, change);
}
static void
emit_in_idle (GFileMonitor *monitor,
GFile *child,
GFile *other_file,
GFileMonitorEvent event_type)
{
GSource *source;
FileChange *change;
change = g_slice_new (FileChange);
change->monitor = g_object_ref (monitor);
change->child = g_object_ref (child);
if (other_file)
change->other_file = g_object_ref (other_file);
else
change->other_file = NULL;
change->event_type = event_type;
source = g_idle_source_new ();
g_source_set_priority (source, 0);
g_source_set_callback (source, emit_cb, change, file_change_free);
g_source_attach (source, NULL);
g_source_unref (source);
}
static guint32
get_time_msecs (void)
{
@ -337,8 +391,7 @@ rate_limiter_send_virtual_changes_done_now (GFileMonitor *monitor,
{
if (limiter->send_virtual_changes_done_at != 0)
{
g_signal_emit (monitor, signals[CHANGED], 0,
limiter->file, NULL,
emit_in_idle (monitor, limiter->file, NULL,
G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT);
limiter->send_virtual_changes_done_at = 0;
}
@ -351,7 +404,7 @@ rate_limiter_send_delayed_change_now (GFileMonitor *monitor,
{
if (limiter->send_delayed_change_at != 0)
{
g_signal_emit (monitor, signals[CHANGED], 0,
emit_in_idle (monitor,
limiter->file, NULL,
G_FILE_MONITOR_EVENT_CHANGED);
limiter->send_delayed_change_at = 0;
@ -522,6 +575,8 @@ update_rate_limiter_timeout (GFileMonitor *monitor,
* Emits the #GFileMonitor::changed signal if a change
* has taken place. Should be called from file monitor
* implementations only.
*
* The signal will be emitted from an idle handler.
**/
void
g_file_monitor_emit_event (GFileMonitor *monitor,
@ -549,7 +604,7 @@ g_file_monitor_emit_event (GFileMonitor *monitor,
rate_limiter_send_virtual_changes_done_now (monitor, limiter);
update_rate_limiter_timeout (monitor, 0);
}
g_signal_emit (monitor, signals[CHANGED], 0, child, other_file, event_type);
emit_in_idle (monitor, child, other_file, event_type);
}
else
{
@ -578,7 +633,7 @@ g_file_monitor_emit_event (GFileMonitor *monitor,
if (emit_now)
{
g_signal_emit (monitor, signals[CHANGED], 0, child, other_file, event_type);
emit_in_idle (monitor, child, other_file, event_type);
limiter->last_sent_change_time = time_now;
limiter->send_delayed_change_at = 0;