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