* concurrent run of post-create event may mark all processed problems as
  duplicates of each other and delete all of them
* abrtd accepts notifications and pushes a problem directory to a queue
* after processing of one problem abrtd pops a directory from the queue
  and continues of processing with next directory

Signed-off-by: Jakub Filak <[email protected]>
---
 src/daemon/abrtd.c |   66 ++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 54 insertions(+), 12 deletions(-)

diff --git a/src/daemon/abrtd.c b/src/daemon/abrtd.c
index 1112591..c664a66 100644
--- a/src/daemon/abrtd.c
+++ b/src/daemon/abrtd.c
@@ -74,6 +74,24 @@ static int child_count = 0;
  */
 static GList *s_pid_list;
 
+/*
+ * The post-create event cannot be run concurrently for more problem
+ * directories. The problem is in searching for duplicates process in case when
+ * two concurrently processed directories are duplicates of each other. Both of
+ * the directories are marked as duplicates of each other and are deleted.
+ *
+ * This queue is used for serialization of processing of created problem
+ * directories.
+ *
+ * The GIO notify handler pushes new directories to this queue and if the 
queue was
+ * empty before push then starts processing of the pushed directory.
+ *
+ * Directory processing code pops the processed directory from the queue at the
+ * end of processing. If the queue is not empty starts processing of the next
+ * directory which is on the top of the queue.
+ */
+static GList *s_dir_queue;
+
 enum {
     EVTYPE_POST_CREATE,
     EVTYPE_NOTIFY,
@@ -291,6 +309,25 @@ static gboolean handle_signal_cb(GIOChannel *gio, 
GIOCondition condition, gpoint
     return TRUE; /* "please don't remove this event" */
 }
 
+static gboolean handle_event_output_cb(GIOChannel *gio, GIOCondition 
condition, gpointer ptr);
+
+/* Runs post-create event asynchronously. Uses GIOChanel for communication 
with event process. */
+static void run_post_create_on_dir_async(const char *name)
+{
+    struct event_processing_state *state = new_event_processing_state();
+    state->event_type = EVTYPE_POST_CREATE;
+    state->dirname = concat_path_file(g_settings_dump_location, name);
+
+    state->child_pid = spawn_event_handler_child(state->dirname, 
"post-create", &state->child_stdout_fd);
+    s_pid_list = g_list_prepend(s_pid_list, state);
+    ndelay_on(state->child_stdout_fd);
+
+    GIOChannel *channel_event_output = 
my_io_channel_unix_new(state->child_stdout_fd);
+    /*uint channel_id_event_output =*/ g_io_add_watch(channel_event_output,
+            G_IO_IN | G_IO_PRI | G_IO_HUP,
+            handle_event_output_cb,
+            state);
+}
 
 /* Event-processing child output handler (such as "post-create" event) */
 static gboolean handle_event_output_cb(GIOChannel *gio, GIOCondition 
condition, gpointer ptr)
@@ -435,11 +472,21 @@ static gboolean handle_event_output_cb(GIOChannel *gio, 
GIOCondition condition,
 
     /* We stop using this channel */
     g_io_channel_unref(gio);
+
+    /* pop the currently processed directory from the incoming queue */
+    char *name = s_dir_queue->data;
+    s_dir_queue = g_list_remove(s_dir_queue, name);
+    free(name);
+
+    /* if the queue is not empty process directory from */
+    /* the top of the incoming queue */
+    if (s_dir_queue)
+        run_post_create_on_dir_async(s_dir_queue->data);
+
     return FALSE; /* "glib, please remove this events source!" */
     /* Removing will also drop the last ref to this gio, closing/freeing it */
 }
 
-
 /* Inotify handler */
 
 static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, 
gpointer ptr_unused)
@@ -550,19 +597,14 @@ static gboolean handle_inotify_cb(GIOChannel *gio, 
GIOCondition condition, gpoin
             }
         }
 
-        struct event_processing_state *state = new_event_processing_state();
-        state->event_type = EVTYPE_POST_CREATE;
-        state->dirname = concat_path_file(g_settings_dump_location, name);
+        const bool empty_queue = s_dir_queue == NULL;
+        /* push the new directory to the end of the incoming queue */
+        s_dir_queue = g_list_append(s_dir_queue, xstrdup(name));
 
-        state->child_pid = spawn_event_handler_child(state->dirname, 
"post-create", &state->child_stdout_fd);
-        s_pid_list = g_list_prepend(s_pid_list, state);
-        ndelay_on(state->child_stdout_fd);
+        /* if the queue was empty process the current directory */
+        if (empty_queue)
+            run_post_create_on_dir_async(name);
 
-        GIOChannel *channel_event_output = 
my_io_channel_unix_new(state->child_stdout_fd);
-        /*uint channel_id_event_output =*/ g_io_add_watch(channel_event_output,
-                                              G_IO_IN | G_IO_PRI | G_IO_HUP,
-                                              handle_event_output_cb,
-                                              state);
     } /* while */
 
     free(buf);
-- 
1.7.10.4

Reply via email to