# Description: Fix common crash when trying to remove a NULL watch # Ubuntu: https://launchpad.net/bugs/269651 # Upstream: http://bugs.freedesktop.org/show_bug.cgi?id=18046 Index: consolekit-0.2.10/src/ck-file-monitor-inotify.c =================================================================== --- consolekit-0.2.10.orig/src/ck-file-monitor-inotify.c 2008-10-19 03:25:32.000000000 +0100 +++ consolekit-0.2.10/src/ck-file-monitor-inotify.c 2008-10-19 12:59:52.000000000 +0100 @@ -80,7 +80,9 @@ guchar *buffer; guint events_idle_id; + guint remove_idle_id; GQueue *notify_events; + GQueue *remove_events; }; enum { @@ -242,6 +244,10 @@ file_monitor_remove_watch (CkFileMonitor *monitor, FileInotifyWatch *watch) { + if (watch->wd == -1) { + return; + } + g_hash_table_remove (monitor->priv->path_to_watch, watch->path); g_hash_table_remove (monitor->priv->wd_to_watch, @@ -334,6 +340,21 @@ return FALSE; } +static gboolean +emit_removals_in_idle (CkFileMonitor *monitor) +{ + FileInotifyWatch *watch; + + monitor->priv->remove_idle_id = 0; + + while ((watch = g_queue_pop_head (monitor->priv->remove_events)) != NULL) { + file_monitor_remove_watch (monitor, watch); + g_free (watch); + } + + return FALSE; +} + static void file_monitor_queue_event (CkFileMonitor *monitor, FileMonitorEventInfo *event_info) @@ -363,6 +384,17 @@ } static void +queue_remove_event (CkFileMonitor *monitor, + FileInotifyWatch *watch) +{ + g_queue_push_tail (monitor->priv->remove_events, watch); + + if (monitor->priv->remove_idle_id == 0) { + monitor->priv->remove_idle_id = g_idle_add ((GSourceFunc) emit_removals_in_idle, monitor); + } +} + +static void handle_inotify_event (CkFileMonitor *monitor, FileInotifyWatch *watch, struct inotify_event *ievent) @@ -401,7 +433,7 @@ } if (ievent->mask & IN_IGNORED) { - file_monitor_remove_watch (monitor, watch); + queue_remove_event (monitor, watch); } } @@ -523,11 +555,13 @@ g_hash_table_steal (monitor->priv->notifies, GUINT_TO_POINTER (id)); - notify->watch->notifies = g_slist_remove (notify->watch->notifies, GUINT_TO_POINTER (id)); + if (notify->watch->notifies) { + notify->watch->notifies = g_slist_remove (notify->watch->notifies, GUINT_TO_POINTER (id)); - if (g_slist_length (notify->watch->notifies) == 0) { - file_monitor_remove_watch (monitor, notify->watch); - g_free (notify->watch); + if (g_slist_length (notify->watch->notifies) == 0) { + file_monitor_remove_watch (monitor, notify->watch); + g_free (notify->watch); + } } g_free (notify); @@ -629,6 +663,7 @@ monitor->priv->serial = 1; monitor->priv->notify_events = g_queue_new (); + monitor->priv->remove_events = g_queue_new (); setup_inotify (monitor); } @@ -649,6 +684,7 @@ g_hash_table_destroy (monitor->priv->notifies); g_queue_free (monitor->priv->notify_events); + g_queue_free (monitor->priv->remove_events); G_OBJECT_CLASS (ck_file_monitor_parent_class)->finalize (object); }