On 07/30/2012 09:43 AM, Jakub Filak wrote: > * 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);
Looks good to me.
