On 06/26/2012 10:37 AM, Jakub Filak wrote:
Signed-off-by: Jakub Filak<jfilak(a)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 function type
This does not make sense to me.
+ *
+ * @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.
For starters, what problem are you solving?
+/*
+ * 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?
+/*
+ * 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?
+/*
+ * 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.
+
+ 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?
--
vda