On Tuesday 26 of June 2012 17:09:48 you wrote:
> On 06/26/2012 10:37 AM, Jakub Filak wrote:
> > Signed-off-by: Jakub Filak<jfilak@redhat.com>
> > ---
> >
> > libreport.spec.in | 1 +
> > src/include/Makefile.am | 3 +-
> > src/include/run_event_list.h | 209 ++++++++++++++
> > src/lib/Makefile.am | 3 +-
> > src/lib/run_event_list.c | 618
> > ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 832
> > insertions(+), 2 deletions(-)
> > create mode 100644 src/include/run_event_list.h
> > create mode 100644 src/lib/run_event_list.c
> >
> > diff --git a/libreport.spec.in b/libreport.spec.in
> > index 3f730e3..ea51431 100644
> > --- a/libreport.spec.in
> > +++ b/libreport.spec.in
> >
> > @@ -297,6 +297,7 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor&>/dev/null || :
> > %{_includedir}/libreport/report.h
> > %{_includedir}/libreport/run_event.h
> > %{_includedir}/libreport/event_usability.h
> >
> > +%{_includedir}/libreport/run_event_list.h
> >
> > # Private api headers:
> > %{_includedir}/libreport/internal_abrt_dbus.h
> > %{_includedir}/libreport/internal_libreport.h
> >
> > diff --git a/src/include/Makefile.am b/src/include/Makefile.am
> > index 7aa5f78..bca63dd 100644
> > --- a/src/include/Makefile.am
> > +++ b/src/include/Makefile.am
> > @@ -10,4 +10,5 @@ libreport_include_HEADERS = \
> >
> > \
> > internal_libreport.h \
> > internal_abrt_dbus.h \
> >
> > - event_usability.h
> > + event_usability.h \
> > + run_event_list.h
> > diff --git a/src/include/run_event_list.h b/src/include/run_event_list.h
> > new file mode 100644
> > index 0000000..f5fa11f
> > --- /dev/null
> > +++ b/src/include/run_event_list.h
> > @@ -0,0 +1,209 @@
> > +/*
> > + Copyright (C) 2012 ABRT team.
> > + Copyright (C) 2012 RedHat inc.
> > +
> > + This program is free software; you can redistribute it and/or modify
> > + it under the terms of the GNU General Public License as published by
> > + the Free Software Foundation; either version 2 of the License, or
> > + (at your option) any later version.
> > +
> > + This program is distributed in the hope that it will be useful,
> > + but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + GNU General Public License for more details.
> > +
> > + You should have received a copy of the GNU General Public License
> > along + with this program; if not, write to the Free Software
> > Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA
> > 02110-1301 USA.
> > +*/
> > +#ifndef LIBREPORT_RUN_EVENT_LIST_H_
> > +#define LIBREPORT_RUN_EVENT_LIST_H_
> > +
> > +#include<glib.h>
> > +#include "run_event.h"
> > +#include "event_usability.h"
> > +
> > +/* Forward declartion */
> > +struct event_list_process;
> > +
> > +/*
> > + * Return value from event list process signal.
> > + * Signal handler returns these values in order to adjust process
> > + * flow according to current state.
> > + */
> > +enum elp_signal_ret
> > +{
> > + ELPSR_CONTINUE, ///< A process should continue with next step.
> > + ELPSR_NEXT_EVENT, ///< A process should skip all remaining steps a
> > continue with next event. + ELPSR_FINISH, ///< A process should
> > skip all remaining events and finis itself. +};
>
> What is elp[sr]?
event list process signal return
>
> > +/*
> > + * Event list process signal function type
>
> This does not make sense to me.
pull approach, all functions have the same declaration and read required data from a passed process pointer
>
> > + *
> > + * @param process A process that emits a signal.
> > + * @return A value that adjusts process flow.
> > + */
> > +typedef enum elp_signal_ret (* elp_signal)(struct event_list_process
> > *process); +
> > +/*
> > + * All signals used by event list process
> > + */
> > +struct elp_signals_impl
> > +{
> > + /*
> > + * Next event was successfully selected and process is about to
> > process it + */
> > + elp_signal next_event_selected;
> > +
> > + /*
> > + * Currently selected event requires review.
> > + */
> > + elp_signal review_data;
> > +
> > + /*
> > + * Currently selected event is about to be run.
> > + */
> > + elp_signal run_event;
> > +
> > + /*
> > + * Currently selected event has finished.
> > + */
> > + elp_signal event_done;
> > +
> > + /*
> > + * No more events to be processed
> > + */
> > + elp_signal finished;
> > +
> > + /*
> > + * Event has some problem with configuration
> > + */
> > + elp_signal configuration_issue;
> > +};
>
> This looks like a TON of added complexity for no apparent reason.
I can use only one signal functions with two arguments.
1. process
2. type of signal
But it forces me to define a new enum with type of signals.
And on the client side it requires more complex logic.
>
> For starters, what problem are you solving?
(report-gtk|report-cli) -e report_uReport -e analyze_LocalGDB -e report_Bugzilla
I tried to unify the implementation.
Each event from list must be reviewed if it is required. After review the event must be run. And finally a result of run is sent to back to caller.
>
> > +/*
> > + * Types of event run result
> > + */
> > +enum elp_event_run_status
> > +{
> > + ELP_ERS_NONE, ///< No run was performed
> > + ELP_ERS_SUCCESSFUL, ///< Event finished successfully
> > + ELP_ERS_FAILED, ///< Event failed
> > + ELP_ERS_NOT_FOUND, ///< No processing was found
> > +};
>
> ELP ERS?
:) event list process event run status
>
> > +/*
> > + * Structure holds an configuration issue info
> > + */
> > +struct elp_configuration_issue
> > +{
> > + const char *event_name; ///< Event with problems
> > + enum event_usability_status usability; ///< Event usability
> > + const GList *issues; ///< All known configuration
> > issues for an event +};
> > +
> > +/*
> > + * Initializes event list process signal functions.
> > + *
> > + * @param impl A not NULL pointer to signals
> > + */
> > +void event_list_process_impl_init(struct elp_signals_impl *impl);
>
> I am totally lost by now. What are we doing here?
convenient way how to initialize a structure with signals
I can use memset() instead of this function
>
> > +/*
> > + * Creates an initializes an event list process
> > + *
> > + * @param events A list of events to be processed, do not take an
> > ownership + * @param signals A signal implementation, do not take an
> > ownership + * @param run_impl A call backs for event run, do not take an
> > ownership + * @param run_obs An observer for event run, do not take an
> > ownership + * @param dump_dir_name A dump dir name, do not take an
> > ownership + * @param signal_args A custom data available by
> > elp_get_signal_args() + * @return An initialized event list process,
> > never returns NULL
> > + */
> > +struct event_list_process *new_event_list_process(const GList *events,
> > + const struct
> > elp_signals_impl *impl, +
> > const struct run_event_impl *run_impl, +
> > const struct run_event_observer *run_obs, +
> > const char *dump_dir_name, +
> > void *signal_args); +
> > +/*
> > + * Frees all used memory by an event list process
> > + *
> > + * @param process A pointer to process
> > + */
> > +void free_event_list_process(struct event_list_process *process);
> > +
> > +/*
> > + * Gets an currently selected event.
> > + *
> > + * @param process A not NULL pointer to process
> > + * @return A pointer to event name if some event was selected, otherwise
> > returns NULL + */
> > +const char *elp_get_current_event(const struct event_list_process
> > *process); +
> > +/*
> > + * Gets an currently selected event.
> > + *
> > + * @param process A not NULL pointer to process
> > + * @return A data passed in new_event_list_process()
> > + */
> > +void *elp_get_signal_args(const struct event_list_process *process);
> > +
> > +/*
> > + * Gets the last event run result.
> > + *
> > + * @param process A not NULL pointer to process
> > + * @return the last event run result.
> > + */
> > +enum elp_event_run_status elp_get_last_event_status(const struct
> > event_list_process *process); +
> > +/*
> > + * Gets the last configuraton issue. This function must be called
> > + * only from handler of configuration_issue signal.
> > + *
> > + * @param process A not NULL pointer to process
> > + * @return the last configuration issue.
> > + */
> > +const struct elp_configuration_issue
> > *elp_get_last_configuration_issue(const struct event_list_process
> > *process); +
> > +/*
> > + * Sets a post run callback for run_event_state.
> > + *
> > + * The method is provided only for backward compatibility
> > + *
> > + * @param process A not NULL pointer to process
> > + * @param post_run_callback A pointer to function
> > + * @param post_run_param A custom data passed to callback
> > + */
> > +void elp_set_post_run_callback(struct event_list_process *process,
> > res_post_run_callback post_run_callback, void *post_run_param); +
> > +/*
> > + * Sets a logging callback for run_event_state.
> > + *
> > + * The method is provided only for backward compatibility
> > + *
> > + * @param process A not NULL pointer to process
> > + * @param loggin_callback A pointer to function
> > + * @param loggin_param A custom data passed to callback
> > + */
> > +void elp_set_logging_callback(struct event_list_process *process,
> > res_logging_callback logging_callback, void *logging_param); +
> > +/*
> > + * Forces a process to perform next step.
> > + *
> > + * @param process A not NULL pointer to process
> > + * @return 0 if last step was performed; otherwise returns non 0
> > + */
> > +int elp_next_step(struct event_list_process *process);
> > +
> > +/*
> > + * Kills an event command process
> > + *
> > + * @param process A not NULL pointer to process
> > + */
> > +void elp_kill_run(struct event_list_process *process);
> > +
> > +#endif /* LIBREPORT_RUN_EVENT_LIST_H_ */
> > +
> > diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
> > index cd1f164..fd406ce 100644
> > --- a/src/lib/Makefile.am
> > +++ b/src/lib/Makefile.am
> > @@ -48,7 +48,8 @@ libreport_la_SOURCES = \
> >
> > user_settings.c \
> > client.c \
> > utf8.c \
> >
> > - event_usability.c
> > + event_usability.c \
> > + run_event_list.c
> >
> > libreport_la_CPPFLAGS = \
> >
> > -Wall -Wwrite-strings -Werror \
> >
> > diff --git a/src/lib/run_event_list.c b/src/lib/run_event_list.c
> > new file mode 100644
> > index 0000000..559772d
> > --- /dev/null
> > +++ b/src/lib/run_event_list.c
> > @@ -0,0 +1,618 @@
> > +/*
> > + Copyright (C) 2012 ABRT Team
> > + Copyright (C) 2012 RedHat inc.
> > +
> > + This program is free software; you can redistribute it and/or modify
> > + it under the terms of the GNU General Public License as published by
> > + the Free Software Foundation; either version 2 of the License, or
> > + (at your option) any later version.
> > +
> > + This program is distributed in the hope that it will be useful,
> > + but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + GNU General Public License for more details.
> > +
> > + You should have received a copy of the GNU General Public License
> > along + with this program; if not, write to the Free Software
> > Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA
> > 02110-1301 USA.
> > +*/
> > +#include<pthread.h>
> > +#include<glob.h>
> > +#include<regex.h>
> > +#include "run_event.h"
> > +#include "run_event_list.h"
> > +#include "event_usability.h"
> > +#include "internal_libreport.h"
> > +
> > +enum elp_process_states
> > +{
> > + __MIN_PROC_STATE__ = 0,
>
> __names are reserved for compiler / libc.
Thus I have to use better name.
>
> > +
> > + ELP_INIT = __MIN_PROC_STATE__,
> > + ELP_START,
> > + ELP_REVIEW_DATA,
> > + ELP_RUN_EVENT,
> > + ELP_END,
> > +
> > + __MAX_PROC_STATE__ = ELP_END,
> > +};
> > +
> > +struct event_list_process
> > +{
> > + const struct elp_signals_impl *impl;
> > + const struct run_event_impl *run_impl;
> > + const struct run_event_observer *run_obs;
> > + const char *dump_dir_name;
> > + void *args;
> > +
> > + enum elp_process_states current;
> > + const GList *events;
> > + GList *internal_events;
> > + GList *next;
> > + GList *processed;
> > +
> > + struct run_event_state *run_state;
> > +
> > + res_post_run_callback post_run_callback;
> > + void *post_run_param;
> > + res_logging_callback logging_callback;
> > + void *logging_param;
> > +
> > + pthread_mutex_t run_mut;
> > + enum elp_event_run_status last_run;
> > +
> > + struct elp_configuration_issue last_configuration_issue;
> > +};
> > +
> > +void event_list_process_impl_init(struct elp_signals_impl *impl)
> > +{
> > + memset(impl, 0, sizeof(*impl));
> > +}
> > +
> > +struct event_list_process *new_event_list_process(const GList *events,
> > + const struct
> > elp_signals_impl *impl, +
> > const struct run_event_impl *run_impl, +
> > const struct run_event_observer *run_obs, +
> > const char *dump_dir_name, +
> > void *signal_args) +{
> > + assert(impl || !"NULL argument");
> > + assert(run_impl || !"NULL argument");
> > +
> > + struct event_list_process *process = xmalloc(sizeof(*process));
> > +
> > + process->impl = impl;
> > + process->run_impl = run_impl;
> > + process->run_obs = run_obs;
> > + process->dump_dir_name = dump_dir_name;
> > + process->args = signal_args;
> > + process->current = __MIN_PROC_STATE__;
> > + process->events = events;
> > + process->next = NULL;
> > + process->internal_events = NULL;
> > + process->processed = NULL;
> > + process->run_state = NULL;
> > +
> > + pthread_mutex_init(&(process->run_mut), NULL);
> > +
> > + process->last_run = ELP_ERS_NONE;
> > +
> > + process->post_run_callback = NULL;
> > + process->post_run_param = NULL;
> > + process->logging_callback = NULL;
> > + process->logging_param = NULL;
> > +
> > + return process;
> > +}
> > +
> > +void free_event_list_process(struct event_list_process *process)
> > +{
> > + assert(process || !"NULL argument");
> > +
> > + g_list_free(process->internal_events);
> > +
> > + pthread_mutex_destroy(&(process->run_mut));
> > +
> > + free(process);
> > +}
> > +
> > +const char* elp_get_current_event(const struct event_list_process
> > *process) +{
> > + assert(process || !"NULL argument");
> > +
> > + return process->processed ? process->processed->data : NULL;
> > +}
> > +
> > +void *elp_get_signal_args(const struct event_list_process *process)
> > +{
> > + assert(process || !"NULL argument");
> > +
> > + return process->args;
> > +}
> > +
> > +enum elp_event_run_status elp_get_last_event_status(const struct
> > event_list_process *process) +{
> > + assert(process || !"NULL argument");
> > +
> > + return process->last_run;
> > +}
> > +
> > +void elp_kill_run(struct event_list_process *process)
> > +{
> > + assert(process || !"NULL argument");
> > +
> > + pthread_mutex_lock(&(process->run_mut));
> > +
> > + if (process->run_state)
> > + run_event_state_kill_command(process->run_state);
> > +
> > + pthread_mutex_unlock(&(process->run_mut));
> > +}
> > +
> > +void elp_set_post_run_callback(struct event_list_process *process,
> > + res_post_run_callback post_run_callback,
> > + void *post_run_param)
> > +{
> > + assert(process || !"NULL argument");
> > +
> > + pthread_mutex_lock(&(process->run_mut));
> > +
> > + process->post_run_callback = post_run_callback;
> > + process->post_run_param = post_run_param;
> > +
> > + pthread_mutex_unlock(&(process->run_mut));
> > +}
> > +
> > +void elp_set_logging_callback(struct event_list_process *process,
> > + res_logging_callback logging_callback,
> > + void *logging_param)
> > +{
> > + assert(process || !"NULL argument");
> > +
> > + pthread_mutex_lock(&(process->run_mut));
> > +
> > + process->logging_callback = logging_callback;
> > + process->logging_param = logging_param;
> > +
> > + pthread_mutex_unlock(&(process->run_mut));
> > +}
> > +
> > +const struct elp_configuration_issue
> > *elp_get_last_configuration_issue(const struct event_list_process
> > *process) +{
> > + return&(process->last_configuration_issue);
> > +}
> > +
> > +static const struct run_event_impl *elp_get_run_impl(struct
> > event_list_process *process) +{
> > + assert(process || !"NULL argument");
> > +
> > + return process->run_impl;
> > +}
> > +
> > +static const struct run_event_observer *elp_get_run_obs(struct
> > event_list_process *process) +{
> > + assert(process || !"NULL argument");
> > +
> > + return process->run_obs;
> > +}
> > +
> > +static problem_data_t *elp_create_problem_data(const struct
> > event_list_process *process) +{
> > +
> > + struct dump_dir *dd = dd_opendir(process->dump_dir_name, 0);
> > + if (!dd)
> > + return NULL;
> > +
> > + problem_data_t *pd = create_problem_data_from_dump_dir(dd);
> > + dd_close(dd);
> > +
> > + return pd;
> > +}
> > +
> > +static bool elp_do_need_review(const struct event_list_process *process,
> > const char *event_name) +{
> > + const event_config_t *const cfg = get_event_config(event_name);
> > + if (cfg&& !cfg->ec_skip_review)
> > + return true;
> > +
> > + problem_data_t *const pd = elp_create_problem_data(process);
> > + if (pd)
> > + return check_event_usability(cfg, pd, NULL, NULL, EUS_LOW) !=
> > EUS_GOOD; +
> > + return true;
> > +}
> > +
> > +static void elp_set_last_configuration_issues(struct event_list_process
> > *process, + const char
> > *event_name, + enum
> > event_usability_status status, +
> > const GList *issues) +{
> > + pthread_mutex_lock(&(process->run_mut));
> > +
> > + process->last_configuration_issue.event_name = event_name;
> > + process->last_configuration_issue.usability = status;
> > + process->last_configuration_issue.issues = issues;
> > +
> > + pthread_mutex_unlock(&(process->run_mut));
> > +}
> > +
> > +static enum elp_signal_ret elp_event_configuration_issue(struct
> > event_list_process *process, +
> > const char *event_name, +
> > enum event_usability_status status, +
> > const GList *issues) +{
> > + enum elp_signal_ret ret = ELPSR_FINISH;
> > +
> > + if (process->impl->configuration_issue)
> > + {
> > + elp_set_last_configuration_issues(process, event_name, status,
> > issues); +
> > + ret = process->impl->configuration_issue(process);
> > +
> > + elp_set_last_configuration_issues(process, NULL, EUS_GOOD, NULL);
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +typedef enum event_usability_status (*validator_fn)(const event_config_t
> > *, const problem_data_t *, +
> > const GList *, GList **, enum event_usability_status); +
> > +static enum elp_signal_ret elp_validate_event_config(struct
> > event_list_process *process, +
> > const event_config_t *cfg, +
> > const char *event_name, +
> > const problem_data_t *pd, +
> > const GList *not_loaded_items, +
> > enum event_usability_status
> > min_level, +
> > validator_fn *validators) +{
> > + enum elp_signal_ret resp = ELPSR_CONTINUE;
> > +
> > + if (!cfg)
> > + return resp;
> > +
> > + enum event_usability_status status = EUS_GOOD;
> > + validator_fn *validator = validators;
> > + GList* issues = NULL;
> > + while(*validator)
> > + {
> > + status = worst_usability(status, (*validator)(cfg, pd,
> > not_loaded_items,&issues, min_level)); + ++validator;
> > + }
> > +
> > + if (status == EUS_UNUSABLE)
> > + {
> > + resp = elp_event_configuration_issue(process, event_name, status,
> > issues); + g_list_free_full(issues, (GDestroyNotify)free);
> > +
> > + if (resp == ELPSR_CONTINUE)
> > + error_msg_and_die("Cannot continue with unusable event '%s'",
> > event_name); + }
> > +
> > + return resp;
> > +}
> > +
> > +static enum elp_signal_ret elp_validate_event(struct event_list_process
> > *process, + const char
> > *event_name, + const
> > problem_data_t *pd, + const
> > GList *not_loaded_items, +
> > enum event_usability_status min_level, +
> > validator_fn *validators) +{
> > + return elp_validate_event_config(process,
> > get_event_config(event_name), event_name, pd, +
> > not_loaded_items, min_level, validators); +}
> > +
> > +static const GList* elp_select_next_event(struct event_list_process
> > *process, const GList **event_list, const GList *not_loaded_items, enum
> > elp_signal_ret *ret) +{
> > + assert(process || !"NULL argument");
> > + assert(event_list || !"NULL argument");
> > +
> > + static validator_fn validators[] = {
> > + check_event_usability,
> > + NULL,
> > + };
> > +
> > + const GList *tmp;
> > + tmp = *event_list;
> > + *event_list = g_list_next(tmp);
> > +
> > + problem_data_t *pd = elp_create_problem_data(process);
> > + if (!pd)
> > + return tmp;
> > +
> > + while(tmp)
> > + {
> > + const enum elp_signal_ret resp = elp_validate_event(process,
> > tmp->data, pd, +
> > not_loaded_items, EUS_UNUSABLE, validators); +
> > + if (ret)
> > + *ret = resp;
> > +
> > + if (resp == ELPSR_CONTINUE)
> > + break;
> > + else if (resp == ELPSR_FINISH)
> > + {
> > + tmp = *event_list = NULL;
> > + break;
> > + }
> > + else if (resp != ELPSR_NEXT_EVENT)
> > + {
> > + assert(!"unexpected return value");
> > + }
> > +
> > + tmp = *event_list;
> > + *event_list = g_list_next(tmp);
> > + }
> > +
> > + free_problem_data(pd);
> > + return tmp;
> > +}
> > +
> > +static GList* elp_revise_event_list(struct event_list_process *process,
> > const GList *event_list) +{
> > + GList *revised_list = NULL;
> > + GList *created_items = NULL;
> > + enum elp_signal_ret ret;
> > +
> > + const GList *event;
> > + while ((event = elp_select_next_event(process,&event_list,
> > created_items,&ret))) + {
> > + const event_config_t *const cfg = get_event_config(event->data);
> > + if (cfg&& cfg->ec_creates_items)
> > + {
> > + /* have to create a copy because of threads */
> > + /* TODO : find a better place for following lines */
> > + char *item_list = xstrdup(cfg->ec_creates_items);
> > + char *bck = item_list;
> > + while (item_list[0])
> > + {
> > + char *end = strchr(item_list, ',');
> > + if (end) *end = '\0';
> > + created_items = g_list_prepend(created_items,
> > xstrdup(item_list)); + if (!end)
> > + break;
> > + item_list = end + 1;
> > + }
> > + free(bck);
> > + }
> > +
> > + revised_list = g_list_prepend(revised_list, event->data);
> > + }
> > +
> > + g_list_free_full(created_items, (GDestroyNotify)free);
> > +
> > + if (ret != ELPSR_FINISH)
> > + return g_list_reverse(revised_list);
> > +
> > + g_list_free(revised_list);
> > + return NULL;
> > +}
> > +
> > +static GList *elp_next_event(struct event_list_process *process)
> > +{
> > + assert(process || !"NULL argument");
> > +
> > + return (GList *)elp_select_next_event(process, (const GList
> > **)&process->next, NULL, NULL); +}
> > +
> > +static bool event_list_process_call(struct event_list_process *process,
> > + elp_signal cb,
> > + enum elp_process_states ok_state,
> > + enum elp_signal_ret default_ret)
> > +{
> > + assert(process || !"NULL argument");
> > + assert((ok_state>= __MIN_PROC_STATE__&& ok_state<=
> > __MAX_PROC_STATE__) || !"out of range argument"); +
> > + const enum elp_signal_ret ret = cb ? cb(process) : default_ret;
> > +
> > + switch (ret)
> > + {
> > + case ELPSR_CONTINUE:
> > + process->current = ok_state;
> > + break;
> > + case ELPSR_NEXT_EVENT:
> > + process->current = ELP_START;
> > + break;
> > + case ELPSR_FINISH:
> > + process->current = ELP_END;
> > + break;
> > + default:
> > + assert(!"unexpected signal return value");
> > + error_msg_and_die("unexpected signal return value %d", ret);
> > + break;
> > + }
> > +
> > + return ret == ELPSR_CONTINUE;
> > +}
> > +
> > +struct process_run_event_watcher
> > +{
> > + const struct run_event_observer *wrapped_obs;
> > + bool failed;
> > + bool stopper;
> > +};
> > +
> > +static void process_command_started(pid_t pid, void *args)
> > +{
> > + struct process_run_event_watcher *pre = (struct
> > process_run_event_watcher *)args; +
> > + if (pre->wrapped_obs&& pre->wrapped_obs->command_started)
> > + pre->wrapped_obs->command_started(pid, pre->wrapped_obs->args);
> > +}
> > +
> > +static void process_command_msg_processed(const char *msg, const char
> > *raw_input, const char *rsp, void *args) +{
> > + struct process_run_event_watcher *pre = (struct
> > process_run_event_watcher *)args; +
> > + /* TODO : should I move it to client.h ? */
> > + if (!pre->stopper)
> > + pre->stopper = !strncmp(msg, "THANK_YOU", sizeof("THANK_YOU")
> > -1);
> > +
> > + if (pre->wrapped_obs&& pre->wrapped_obs->command_msg_processed)
> > + pre->wrapped_obs->command_msg_processed(msg, raw_input, rsp,
> > pre->wrapped_obs->args); +}
> > +
> > +static void process_command_finished(int retval, int status, const char
> > *err_msg, void *args) +{
> > + struct process_run_event_watcher *pre = (struct
> > process_run_event_watcher *)args; +
> > + pre->failed = retval != 0;
> > +
> > + if (pre->wrapped_obs&& pre->wrapped_obs->command_finished)
> > + pre->wrapped_obs->command_finished(retval, status, err_msg,
> > pre->wrapped_obs->args); +}
> > +
> > +int elp_next_step(struct event_list_process *process)
> > +{
> > + /* before process start, revise event list and remove not configured
> > and */ + /* unusable events */
> > + if (process->current == ELP_INIT)
> > + {
> > + process->current = ELP_START;
> > +
> > + /* create internal event list from origin event list */
> > + /* it is a copy of original list without unusable events */
> > + process->internal_events = process->next =
> > elp_revise_event_list(process, process->events); + }
> > +
> > + /* Process all event from list until reaches event that needs review,
> > event run failure */ + /* or the end of the event list */
> > + while (1)
> > + {
> > + if (process->current == ELP_START)
> > + {
> > + /* selects next event from internal list */
> > + process->processed = elp_next_event(process);
> > +
> > + if (!process->processed)
> > + { /* Event list is empty now */
> > + process->current = ELP_END;
> > + }
> > + else
> > + {
> > + /* If callback next_event_selected is not set the process
> > expects that */ + /* there is no problem to continue thus
> > default response is CONTINUE */ + /* It callback returns a
> > positive response process state is set to START */ + if
> > (!event_list_process_call(process, process->impl->next_event_selected,
> > ELP_START, ELPSR_CONTINUE)) + return true;
> > +
> > + if (elp_do_need_review(process,
> > elp_get_current_event(process))) + process->current =
> > ELP_REVIEW_DATA;
> > + else
> > + process->current = ELP_RUN_EVENT;
> > + }
> > +
> > + /* return is not here because we want to continue with next
> > state */ + /* use case : next_step with start state causes
> > beginning to review */ + /* or immediate run of
> > event commands */
> > + }
> > +
> > + if (process->current == ELP_REVIEW_DATA)
> > + {
> > + /* review_data signal has high priority thus if call back is
> > not set, */ + /* then we expect that data are not reviewed and
> > event is skipped */ +
> > + /* return pauses the processing of events because process has
> > to wait on next */ + /* step signaling that review is
> > finished, thus return if positive answer */ + /* was returned
> > from review_data callback */
> > +
> > + /* if negative answer was returned we want to select next
> > event immediately */ + /* or finish the process */
> > + if(event_list_process_call(process,
> > process->impl->review_data, ELP_RUN_EVENT, ELPSR_NEXT_EVENT)) +
> > return true;
> > + }
> > +
> > + if (process->current == ELP_RUN_EVENT)
> > + {
> > + /* If callback run_event is not set the process expects that
> > */ + /* there is no problem to continue thus default response
> > is CONTINUE */ +
> > + /* if negative answer was returned we want to select next
> > event immediately */ + /* or finish the process */
> > + if (!event_list_process_call(process,
> > process->impl->run_event, ELP_RUN_EVENT, ELPSR_CONTINUE)) +
> > return true;
> > +
> > + const char *event_name = elp_get_current_event(process);
> > +
> > + struct process_run_event_watcher process_watcher = {
> > + .failed = false,
> > + .stopper = false,
> > + };
> > +
> > + process_watcher.wrapped_obs = elp_get_run_obs(process);
> > +
> > + struct run_event_observer process_obs = {
> > + .command_started = process_command_started,
> > + .command_msg_processed = process_command_msg_processed,
> > + .command_finished = process_command_finished,
> > + };
> > +
> > + process_obs.args =&process_watcher;
> > +
> > + const char *dump_dir_name = process->dump_dir_name;
> > +
> > + pthread_mutex_lock(&(process->run_mut));
> > +
> > + struct run_event_state *run_state = new_run_event_state();
> > + process->run_state = run_state;
> > + run_state->post_run_callback = process->post_run_callback;
> > + run_state->post_run_param = process->post_run_param;
> > + run_state->logging_callback = process->logging_callback;
> > + run_state->logging_param = process->logging_param;
> > +
> > + pthread_mutex_unlock(&(process->run_mut));
> > +
> > + prepare_commands(run_state, dump_dir_name, event_name);
> > + run_event_state_on_dir_name(run_state, dump_dir_name,
> > event_name, +
> > elp_get_run_impl(process),&process_obs); +
> > + /* take care about stopper occurrence only if event was
> > successful */ + /* thus default value is not stopper
> > occurrence */
> > + bool stopper = false;
> > +
> > + process->last_run = ELP_ERS_FAILED;
> > + if (!process_watcher.failed)
> > + {
> > + if (run_state->children_count == 0)
> > + {
> > + process->last_run = ELP_ERS_NOT_FOUND;
> > +
> > + /* run_event do not provide any callback for not
> > event found notification */ + /* and no event is
> > considered as fail thus setting failed var to TRUE */ +
> > process_watcher.failed = true;
> > + }
> > + else
> > + {
> > + process->last_run = ELP_ERS_SUCCESSFUL;
> > + stopper = process_watcher.stopper;
> > + }
> > + }
> > +
> > + /* stopper means that event decided to stop all further
> > processing the */ + /* thus successful state is ELP_END and
> > default response is ELPSR_FINISH */ +
> > event_list_process_call(process, process->impl->event_done, +
> > stopper ? ELP_END : ELP_START, +
> > stopper ? ELPSR_FINISH : ELPSR_CONTINUE); +
> > + pthread_mutex_lock(&(process->run_mut));
> > + free_run_event_state(run_state);
> > + process->run_state = NULL;
> > + pthread_mutex_unlock(&(process->run_mut));
> > +
> > + /* do not forward to next step if event failed */
> > + if (process_watcher.failed)
> > + return true;
> > + }
> > +
> > + if (process->current == ELP_END)
> > + {
> > + /* Don't care about result, result can't change anything */
> > + event_list_process_call(process, process->impl->finished,
> > ELP_END, ELPSR_FINISH); + return false;
> > + }
> > + }
> > +
> > + assert(!"cannot get here");
> > + return false;
> > +}
>
> Before these patches:
>
> # grep -r thread .
> ./src/gui-wizard-gtk/Makefile.am:# -lgthread-2.0
> ./src/lib/json.c:#include <btparser/thread.h>
> ./src/lib/json.c: struct btp_thread *core_bt =
> btp_load_core_backtrace(pd_item); ./src/lib/json.c:
> ureport_add_int(item, "thread", 0);
> ./src/lib/json.c: btp_thread_free(core_bt);
> ./src/lib/json.c: * ureport_add_item_int(ureport, pd, "crash_thread",
> NULL); ./src/lib/json.c: ureport_add_int(ureport, "crash_thread", 0);
> ./src/plugins/rhbz.c:#include <btparser/thread.h>
> ./src/plugins/rhbz.c: * - otherwise preview of crashed thread stack
> trace is created ./src/plugins/rhbz.c: /* Get optimized thread stack
> trace for 10 top most frames */ ./src/plugins/rhbz.c: struct
> btp_thread *thread = btp_backtrace_get_optimized_thread(backtrace, 10);
> ./src/plugins/rhbz.c: if (!thread)
> ./src/plugins/rhbz.c: log(_("Can't find crash thread"));
> ./src/plugins/rhbz.c: btp_thread_append_to_str(thread, bt, true);
> ./src/plugins/rhbz.c: btp_thread_free(thread);
>
>
> After these patches:
>
> # grep -r thread .
> ./libreport.spec.in:%{_includedir}/libreport/run_event_list_thread.h
> ./src/gui-wizard-gtk/wizard.c:#include "run_event_list_thread.h"
> ./src/gui-wizard-gtk/wizard.c:static pthread_t g_gui_thread_id;
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: show_error_as_msgbox_mts(msg,
> !pthread_equal(g_gui_thread_id, pthread_self()));
> ./src/gui-wizard-gtk/wizard.c:static void
> process_step_done_callback_fn(struct elp_thread_args *args)
> ./src/gui-wizard-gtk/wizard.c:static void process_start_callback_fn(struct
> elp_thread_args *args) ./src/gui-wizard-gtk/wizard.c:
> gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c:static void process_finish_callback_fn(struct
> elp_thread_args *args) ./src/gui-wizard-gtk/wizard.c:
> free_event_list_process(elp_thread_args_get_process(args));
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c:
> elp_thread_loop_kill_command(g_event_process);
> ./src/gui-wizard-gtk/wizard.c: if (g_reviewing_data ||
> !elp_thread_is_runnig(g_event_process)) ./src/gui-wizard-gtk/wizard.c:
> elp_thread_loop_next_step(g_event_process);
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c: elp_thread_run(g_event_process, proc);
> ./src/gui-wizard-gtk/wizard.c:
> elp_thread_loop_next_step(g_event_process); ./src/gui-wizard-gtk/wizard.c:
> gdk_threads_enter();
> ./src/gui-wizard-gtk/wizard.c: gdk_threads_leave();
> ./src/gui-wizard-gtk/wizard.c:
> elp_thread_loop_next_step(g_event_process); ./src/gui-wizard-gtk/wizard.c:
> elp_thread_args_set_on_step_done(g_event_process,
> process_step_done_callback_fn); ./src/gui-wizard-gtk/wizard.c:
> elp_thread_args_set_on_start(g_event_process, process_start_callback_fn);
> ./src/gui-wizard-gtk/wizard.c:
> elp_thread_args_set_on_finish(g_event_process, process_finish_callback_fn);
> ./src/gui-wizard-gtk/wizard.c: g_gui_thread_id = pthread_self();
> ./src/gui-wizard-gtk/wizard.c:
> g_source_attach((GSource*)gtk_assistant_source,
> g_main_context_get_thread_default()); ./src/gui-wizard-gtk/main.c:#include
> "run_event_list_thread.h"
> ./src/gui-wizard-gtk/main.c:struct elp_thread_args *g_event_process;
> ./src/gui-wizard-gtk/main.c: g_event_process = new_elp_thread_args();
> ./src/gui-wizard-gtk/main.c: gdk_threads_init ();
> ./src/gui-wizard-gtk/main.c: gdk_threads_enter ();
> ./src/gui-wizard-gtk/main.c: if (elp_thread_init(g_event_process))
> ./src/gui-wizard-gtk/main.c: perror_msg_and_die("initializatoin of
> event process thread failed"); ./src/gui-wizard-gtk/main.c:
> gdk_threads_leave();
> ./src/gui-wizard-gtk/main.c: free_elp_thread_args(g_event_process);
> ./src/gui-wizard-gtk/wizard.h:struct elp_thread_args;
> ./src/gui-wizard-gtk/wizard.h:extern struct elp_thread_args
> *g_event_process; ./src/gui-wizard-gtk/Makefile.am:# -lgthread-2.0
> ./src/include/run_event_list_thread.h: * struct elp_thread_args *thread_proc
> = new_elp_thread_args(); ./src/include/run_event_list_thread.h: * if
> (elp_thread_init(thread_proc)) ./src/include/run_event_list_thread.h: *
> elp_thread_run(thread_proc, event_proc);
> ./src/include/run_event_list_thread.h: *
> elp_thread_loop_next_step(thread_proc);
> ./src/include/run_event_list_thread.h: *
> free_event_list_process(elp_thread_get_process(thread_proc));
> ./src/include/run_event_list_thread.h: * free_elp_thread(thread_proc);
> ./src/include/run_event_list_thread.h: * Structure that holds state of
> thread process. ./src/include/run_event_list_thread.h:struct
> elp_thread_args;
> ./src/include/run_event_list_thread.h: * Callback used by thread process to
> send signals about process state
> ./src/include/run_event_list_thread.h:typedef void(*
> elp_thread_args_callback)(struct elp_thread_args *args);
> ./src/include/run_event_list_thread.h: * Creates a new thread process state
> ./src/include/run_event_list_thread.h:struct elp_thread_args
> *new_elp_thread_args(); ./src/include/run_event_list_thread.h: * @param
> args Not NULL pointer to thread process state
> ./src/include/run_event_list_thread.h:void
> elp_thread_args_set_on_start(struct elp_thread_args *args,
> ./src/include/run_event_list_thread.h:
> elp_thread_args_callback cb); ./src/include/run_event_list_thread.h: *
> @param args Not NULL pointer to thread process state
> ./src/include/run_event_list_thread.h:void
> elp_thread_args_set_on_step_done(struct elp_thread_args *args,
> ./src/include/run_event_list_thread.h:
> elp_thread_args_callback cb); ./src/include/run_event_list_thread.h: *
> @param args Not NULL pointer to thread process state
> ./src/include/run_event_list_thread.h:void
> elp_thread_args_set_on_finish(struct elp_thread_args *args,
> ./src/include/run_event_list_thread.h:
> elp_thread_args_callback cb); ./src/include/run_event_list_thread.h: *
> @param args Not NULL pointer to thread process state
> ./src/include/run_event_list_thread.h:struct event_list_process
> *elp_thread_args_get_process(const struct elp_thread_args *args);
> ./src/include/run_event_list_thread.h: * Destroy thread process
> ./src/include/run_event_list_thread.h: * @param args A pointer to thread
> process ./src/include/run_event_list_thread.h:void
> free_elp_thread_args(struct elp_thread_args *args);
> ./src/include/run_event_list_thread.h: * Creates a thread used by a process
> ./src/include/run_event_list_thread.h: * @param args Not NULL pointer to
> thread process state ./src/include/run_event_list_thread.h:int
> elp_thread_init(struct elp_thread_args *args);
> ./src/include/run_event_list_thread.h: * Interrupts an event list process
> and kills a process thread. ./src/include/run_event_list_thread.h: * A
> thread process cannot be used after this function call.
> ./src/include/run_event_list_thread.h: * @param args Not NULL pointer to
> thread process state ./src/include/run_event_list_thread.h:void
> elp_thread_kill(struct elp_thread_args *args);
> ./src/include/run_event_list_thread.h: * Interrupts an event list process
> and leaves a process thread untouched.
> ./src/include/run_event_list_thread.h: * @param args Not NULL pointer to
> thread process state ./src/include/run_event_list_thread.h:void
> elp_thread_interrupt(struct elp_thread_args *args);
> ./src/include/run_event_list_thread.h: * @param args Not NULL pointer to
> thread process state ./src/include/run_event_list_thread.h:void
> elp_thread_run(struct elp_thread_args *args, struct event_list_process
> *process); ./src/include/run_event_list_thread.h: * @param args Not NULL
> pointer to thread process state ./src/include/run_event_list_thread.h:int
> elp_thread_is_runnig(struct elp_thread_args *args);
> ./src/include/run_event_list_thread.h: * Notify a thread process to perform
> next event list process step. ./src/include/run_event_list_thread.h: *
> @param args Not NULL pointer to thread process state
> ./src/include/run_event_list_thread.h:void elp_thread_loop_next_step(struct
> elp_thread_args *args); ./src/include/run_event_list_thread.h: * @param
> args Not NULL pointer to thread process state
> ./src/include/run_event_list_thread.h:void
> elp_thread_loop_kill_command(struct elp_thread_args *args);
> ./src/include/Makefile.am: run_event_list_thread.h
> ./src/lib/run_event_list.c:#include <pthread.h>
> ./src/lib/run_event_list.c: pthread_mutex_t run_mut;
> ./src/lib/run_event_list.c: pthread_mutex_init(&(process->run_mut),
> NULL); ./src/lib/run_event_list.c:
> pthread_mutex_destroy(&(process->run_mut)); ./src/lib/run_event_list.c:
> pthread_mutex_lock(&(process->run_mut)); ./src/lib/run_event_list.c:
> pthread_mutex_unlock(&(process->run_mut)); ./src/lib/run_event_list.c:
> pthread_mutex_lock(&(process->run_mut)); ./src/lib/run_event_list.c:
> pthread_mutex_unlock(&(process->run_mut)); ./src/lib/run_event_list.c:
> pthread_mutex_lock(&(process->run_mut)); ./src/lib/run_event_list.c:
> pthread_mutex_unlock(&(process->run_mut)); ./src/lib/run_event_list.c:
> pthread_mutex_lock(&(process->run_mut)); ./src/lib/run_event_list.c:
> pthread_mutex_unlock(&(process->run_mut)); ./src/lib/run_event_list.c:
> /* have to create a copy because of threads */
> ./src/lib/run_event_list.c:
> pthread_mutex_lock(&(process->run_mut)); ./src/lib/run_event_list.c:
> pthread_mutex_unlock(&(process->run_mut)); ./src/lib/run_event_list.c:
> pthread_mutex_lock(&(process->run_mut));
> ./src/lib/run_event_list.c:
> pthread_mutex_unlock(&(process->run_mut));
> ./src/lib/run_event_list_thread.c:#include <pthread.h>
> ./src/lib/run_event_list_thread.c:#include "run_event_list_thread.h"
> ./src/lib/run_event_list_thread.c:struct elp_thread_args
> ./src/lib/run_event_list_thread.c: pthread_t process_tid;
> ./src/lib/run_event_list_thread.c: pthread_mutex_t sync_mut;
> ./src/lib/run_event_list_thread.c: pthread_cond_t proc_cond;
> ./src/lib/run_event_list_thread.c: pthread_cond_t step_cond;
> ./src/lib/run_event_list_thread.c: elp_thread_args_callback start_cb;
> ./src/lib/run_event_list_thread.c: elp_thread_args_callback step_done_cb;
> ./src/lib/run_event_list_thread.c: elp_thread_args_callback finish_cb;
> ./src/lib/run_event_list_thread.c:struct elp_thread_args
> *new_elp_thread_args() ./src/lib/run_event_list_thread.c: struct
> elp_thread_args *args = xzalloc(sizeof(*args));
> ./src/lib/run_event_list_thread.c: pthread_mutex_init(&(args->sync_mut),
> NULL); ./src/lib/run_event_list_thread.c:
> pthread_cond_init(&(args->proc_cond), NULL);
> ./src/lib/run_event_list_thread.c: pthread_cond_init(&(args->step_cond),
> NULL); ./src/lib/run_event_list_thread.c:void
> elp_thread_args_set_on_start(struct elp_thread_args *args,
> ./src/lib/run_event_list_thread.c:
> elp_thread_args_callback cb) ./src/lib/run_event_list_thread.c:void
> elp_thread_args_set_on_step_done(struct elp_thread_args *args,
> ./src/lib/run_event_list_thread.c:
> elp_thread_args_callback cb) ./src/lib/run_event_list_thread.c:void
> elp_thread_args_set_on_finish(struct elp_thread_args *args,
> ./src/lib/run_event_list_thread.c:
> elp_thread_args_callback cb) ./src/lib/run_event_list_thread.c:static void
> elp_thread_args_set_process(struct elp_thread_args *args,
> ./src/lib/run_event_list_thread.c:struct event_list_process
> *elp_thread_args_get_process(const struct elp_thread_args *args)
> ./src/lib/run_event_list_thread.c:static void
> elp_thread_args_on_start(struct elp_thread_args *args)
> ./src/lib/run_event_list_thread.c:static void
> elp_thread_args_on_step_done(struct elp_thread_args *args)
> ./src/lib/run_event_list_thread.c:static void
> elp_thread_args_on_finish(struct elp_thread_args *args)
> ./src/lib/run_event_list_thread.c:void elp_thread_interrupt_internal(struct
> elp_thread_args *args) ./src/lib/run_event_list_thread.c:static void
> elp_thread_kill_internal(struct elp_thread_args *args)
> ./src/lib/run_event_list_thread.c: elp_thread_interrupt_internal(args);
> ./src/lib/run_event_list_thread.c:static int
> elp_thread_wait_on_process(struct elp_thread_args *args)
> ./src/lib/run_event_list_thread.c:
> pthread_mutex_lock(&(args->sync_mut)); ./src/lib/run_event_list_thread.c:
> const int error = pthread_cond_wait(&(args->proc_cond),
> &(args->sync_mut)); ./src/lib/run_event_list_thread.c:
> elp_thread_kill_internal(args); ./src/lib/run_event_list_thread.c:
> pthread_mutex_unlock(&(args->sync_mut));
> ./src/lib/run_event_list_thread.c:static int elp_thread_wait_on_step(struct
> elp_thread_args *args) ./src/lib/run_event_list_thread.c:
> pthread_mutex_lock(&(args->sync_mut)); ./src/lib/run_event_list_thread.c:
> const int error = pthread_cond_wait(&(args->step_cond),
> &(args->sync_mut)); ./src/lib/run_event_list_thread.c:
> elp_thread_kill_internal(args); ./src/lib/run_event_list_thread.c:
> pthread_mutex_unlock(&(args->sync_mut));
> ./src/lib/run_event_list_thread.c:void free_elp_thread_args(struct
> elp_thread_args *args) ./src/lib/run_event_list_thread.c:
> pthread_cond_destroy(&(args->step_cond));
> ./src/lib/run_event_list_thread.c:
> pthread_cond_destroy(&(args->proc_cond));
> ./src/lib/run_event_list_thread.c:
> pthread_mutex_destroy(&(args->sync_mut));
> ./src/lib/run_event_list_thread.c:void elp_thread_run(struct
> elp_thread_args *args, struct event_list_process *process)
> ./src/lib/run_event_list_thread.c:
> pthread_mutex_lock(&(args->sync_mut)); ./src/lib/run_event_list_thread.c:
> if (elp_thread_is_runnig(args)) ./src/lib/run_event_list_thread.c:
> error_msg_and_die("event list process thread is already runnig");
> ./src/lib/run_event_list_thread.c: elp_thread_args_set_process(args,
> process); ./src/lib/run_event_list_thread.c:
> pthread_cond_signal(&(args->proc_cond)); ./src/lib/run_event_list_thread.c:
> pthread_mutex_unlock(&(args->sync_mut));
> ./src/lib/run_event_list_thread.c:int elp_thread_is_runnig(struct
> elp_thread_args *args) ./src/lib/run_event_list_thread.c:void
> elp_thread_loop_next_step(struct elp_thread_args *args)
> ./src/lib/run_event_list_thread.c:
> pthread_mutex_lock(&(args->sync_mut)); ./src/lib/run_event_list_thread.c:
> pthread_cond_signal(&(args->step_cond));
> ./src/lib/run_event_list_thread.c:
> pthread_mutex_unlock(&(args->sync_mut));
> ./src/lib/run_event_list_thread.c:static void *elp_thread(void *args)
> ./src/lib/run_event_list_thread.c: struct elp_thread_args *p = (struct
> elp_thread_args *)args; ./src/lib/run_event_list_thread.c: while
> (elp_thread_wait_on_process(p)) ./src/lib/run_event_list_thread.c:
> elp_thread_args_on_start(p); ./src/lib/run_event_list_thread.c:
> pthread_mutex_lock(&(p->sync_mut)); ./src/lib/run_event_list_thread.c:
> pthread_mutex_unlock(&(p->sync_mut));
> ./src/lib/run_event_list_thread.c: elp_thread_wait_on_step(p);
> ./src/lib/run_event_list_thread.c: while
> (elp_thread_wait_on_step(p) && cont) ./src/lib/run_event_list_thread.c:
> elp_thread_args_on_step_done(p);
> ./src/lib/run_event_list_thread.c:
> pthread_mutex_lock(&(p->sync_mut)); ./src/lib/run_event_list_thread.c:
> pthread_mutex_unlock(&(p->sync_mut)); ./src/lib/run_event_list_thread.c:
> elp_thread_args_on_finish(p); ./src/lib/run_event_list_thread.c:int
> elp_thread_init(struct elp_thread_args *args)
> ./src/lib/run_event_list_thread.c: return
> pthread_create(&(args->process_tid), NULL, elp_thread, args);
> ./src/lib/run_event_list_thread.c:void elp_thread_loop_kill_command(struct
> elp_thread_args *args) ./src/lib/run_event_list_thread.c:
> pthread_mutex_lock(&(args->sync_mut)); ./src/lib/run_event_list_thread.c:
> pthread_mutex_unlock(&(args->sync_mut));
> ./src/lib/run_event_list_thread.c:void elp_thread_interrupt(struct
> elp_thread_args *args) ./src/lib/run_event_list_thread.c:
> pthread_mutex_lock(&(args->sync_mut)); ./src/lib/run_event_list_thread.c:
> elp_thread_interrupt_internal(args); ./src/lib/run_event_list_thread.c:
> pthread_cond_signal(&(args->step_cond)); ./src/lib/run_event_list_thread.c:
> pthread_mutex_unlock(&(args->sync_mut));
> ./src/lib/run_event_list_thread.c:void elp_thread_kill(struct
> elp_thread_args *args) ./src/lib/run_event_list_thread.c:
> pthread_mutex_lock(&(args->sync_mut)); ./src/lib/run_event_list_thread.c:
> elp_thread_kill_internal(args); ./src/lib/run_event_list_thread.c:
> pthread_cond_signal(&(args->proc_cond)); ./src/lib/run_event_list_thread.c:
> pthread_mutex_unlock(&(args->sync_mut)); ./src/lib/json.c:#include
> <btparser/thread.h>
> ./src/lib/json.c: struct btp_thread *core_bt =
> btp_load_core_backtrace(pd_item); ./src/lib/json.c:
> ureport_add_int(item, "thread", 0);
> ./src/lib/json.c: btp_thread_free(core_bt);
> ./src/lib/json.c: * ureport_add_item_int(ureport, pd, "crash_thread",
> NULL); ./src/lib/json.c: ureport_add_int(ureport, "crash_thread", 0);
> ./src/lib/Makefile.am: run_event_list_thread.c
> ./src/plugins/rhbz.c:#include <btparser/thread.h>
> ./src/plugins/rhbz.c: * - otherwise preview of crashed thread stack
> trace is created ./src/plugins/rhbz.c: /* Get optimized thread stack
> trace for 10 top most frames */ ./src/plugins/rhbz.c: struct
> btp_thread *thread = btp_backtrace_get_optimized_thread(backtrace, 10);
> ./src/plugins/rhbz.c: if (!thread)
> ./src/plugins/rhbz.c: log(_("Can't find crash thread"));
> ./src/plugins/rhbz.c: btp_thread_append_to_str(thread, bt, true);
> ./src/plugins/rhbz.c: btp_thread_free(thread);
>
>
> I don't think this is an improvement.
> Who will debug the next nightmage threading bug?
I use only two threads :( All nightmare stuff is hidden in run_event_list_thread.
From my point of view, this approach is better than running event processes from GUI
* it allows me to use callbacks in run_event_on_dir().
* it is not necessary to implement run_event_on_dir in GUI again
* implementation of run event list can be shared between reporters
* reporters are much more simple