Add framework for processing faultd events
authorKrzysztof Opasiak <k.opasiak@samsung.com>
Tue, 9 May 2017 11:28:34 +0000 (13:28 +0200)
committerKrzysztof Opasiak <k.opasiak@samsung.com>
Wed, 10 May 2017 18:42:59 +0000 (20:42 +0200)
For now it's just a simple framework which has a list of
available event handlers each time when event arrives it
iterates through the list to find a volunteer to handle
this event.

Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
Makefile.am
src/core/event_processor.c [new file with mode: 0644]
src/core/event_processor.h [new file with mode: 0644]

index e848a5298e6457eddfc86ea545bf8684edca1c3e..34cdaa29b5e8f6411a8486609c65016536a72d49 100644 (file)
@@ -32,6 +32,7 @@ SED_PROCESS = \
 sbin_PROGRAMS = faultd
 faultd_SOURCES = \
     src/core/event.c \
+    src/core/event_processor.c \
     src/core/module.c \
     src/faultd.c \
     src/util/log.c \
diff --git a/src/core/event_processor.c b/src/core/event_processor.c
new file mode 100644 (file)
index 0000000..7fcf8af
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * faultd
+ *
+ * Copyright © 2017 Samsung Electronics
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+
+#include "event_processor.h"
+#include "log.h"
+
+struct event_processor {
+       struct faultd_module module;
+       struct nqueue_head pending_events;
+       struct sd_event_source *pending_events_sd_source;
+       struct list_head event_handlers;
+       sd_event *loop;
+};
+
+#define to_event_processor(MOD)                                                        \
+       container_of(MOD, struct event_processor, module)
+
+/* called each time when new event arrived */
+static int event_processor_callback(sd_event_source *s,
+                                    int fd, uint32_t revents, void *userdata)
+{
+       struct event_processor *eprocessor = userdata;
+       struct faultd_event *ev = nqueue_pop(&eprocessor->pending_events,
+                                                                                struct faultd_event, nq_node);
+       struct faultd_event_handler *handler;
+
+       /* TODO: Here is a good place to put our event into DB */
+       {
+               char *str = faultd_event_to_string(ev);
+               log_debug("New event arrived: %s", str);
+               free(str);
+       }
+
+       list_for_each_entry(handler, &eprocessor->event_handlers, node) {
+               if (handler->event_match(handler, ev)) {
+                       nqueue_append(&handler->event_queue, &ev->nq_node);
+                       ev = NULL;
+               }
+       }
+
+       if (ev) {
+               log_error("No handler for event found");
+               faultd_event_unref(ev);
+       }
+
+       return 0;
+}
+
+static int event_processor_init(struct faultd_module *module, sd_event *event)
+{
+       struct event_processor *eprocessor = to_event_processor(module);
+       int ret;
+
+       ret = init_notify_queue_head(&eprocessor->pending_events);
+       if (ret)
+               return ret;
+
+       ret = sd_event_add_io(event, &eprocessor->pending_events_sd_source,
+                                                 eprocessor->pending_events.fd, EPOLLIN,
+                                                 event_processor_callback, eprocessor);
+       if (ret)
+               goto cleanup_queue;
+
+       eprocessor->loop = event;
+       return 0;
+
+cleanup_queue:
+       cleanup_notify_queue_head(&eprocessor->pending_events);
+
+       return ret;
+}
+
+static void event_processor_cleanup(struct faultd_module *module)
+{
+       struct event_processor *eprocessor = to_event_processor(module);
+       int ret;
+
+       /* We log errors but go forward to cleanup everything we can */
+       ret = sd_event_source_set_enabled(eprocessor->pending_events_sd_source,
+                                                                         SD_EVENT_OFF);
+       if (ret < 0)
+               log_error("Could not disable queue event source %d", ret);
+
+       sd_event_source_unref(eprocessor->pending_events_sd_source);
+
+       /* TODO: What to do with unhandled events? */
+       while (!nqueue_empty(&eprocessor->pending_events)) {
+               struct faultd_event *ev = nqueue_pop(&eprocessor->pending_events,
+                                                                                        struct faultd_event,
+                                                                                        nq_node);
+               char *str = faultd_event_to_string(ev);
+               log_error("Unhandled event: %s", str);
+               free(str);
+               faultd_event_unref(ev);
+       }
+}
+
+struct event_processor event_processor = {
+       .module = {
+               .name = "event_processor",
+               .type = FAULTD_MODULE_TYPE_CORE,
+
+               .init = event_processor_init,
+               .cleanup = event_processor_cleanup,
+               .node = LIST_HEAD_INIT(event_processor.module.node),
+       },
+       /* pending_events will be initialized in init() */
+       .event_handlers = LIST_HEAD_INIT(event_processor.event_handlers),
+};
+
+FAULTD_MODULE_REGISTER(&event_processor.module);
+
+int event_processor_report_event(struct faultd_event *ev)
+{
+       return nqueue_append(&event_processor.pending_events,
+                                                &ev->nq_node);
+}
+
+static int event_processor_handler_callback(sd_event_source *s, int fd,
+                                            uint32_t revents, void *userdata)
+{
+       struct faultd_event_handler *handler = userdata;
+
+       return handler->handle_event(handler);
+}
+
+int event_processor_handler_register(struct faultd_event_handler *handler)
+{
+       int ret;
+
+       if (!handler->event_match || !handler->handle_event)
+               return -EINVAL;
+
+       ret = init_notify_queue_head(&handler->event_queue);
+       if (ret)
+               return ret;
+
+       ret = sd_event_add_io(event_processor.loop,
+                                                 &handler->event_queue_sd_source,
+                                                 handler->event_queue.fd, EPOLLIN,
+                                                 event_processor_handler_callback, handler);
+       if (ret)
+               goto cleanup_queue;
+
+       list_add_tail(&handler->node, &event_processor.event_handlers);
+
+       return 0;
+
+cleanup_queue:
+       cleanup_notify_queue_head(&handler->event_queue);
+
+       return ret;
+}
+
+void event_processor_handler_unregister(struct faultd_event_handler *handler)
+{
+       int ret;
+
+       /* We log errors but go forward to cleanup everything we can */
+       ret = sd_event_source_set_enabled(handler->event_queue_sd_source,
+                                                                         SD_EVENT_OFF);
+       if (ret < 0)
+               log_error("Could not disable queue event source %d", ret);
+
+       sd_event_source_unref(handler->event_queue_sd_source);
+
+       /* TODO: What to do with unhandled events? */
+       while (!nqueue_empty(&handler->event_queue)) {
+               struct faultd_event *ev = nqueue_pop(&event_processor.pending_events,
+                                                                                        struct faultd_event,
+                                                                                        nq_node);
+               char *str = faultd_event_to_string(ev);
+
+               log_error("Unhandled event: %s", str);
+               free(str);
+               faultd_event_unref(ev);
+       }
+
+       list_del(&handler->node);
+}
diff --git a/src/core/event_processor.h b/src/core/event_processor.h
new file mode 100644 (file)
index 0000000..8353b2c
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * faultd
+ *
+ * Copyright © 2017 Samsung Electronics
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FAULTD_EVENT_PROCESSOR_H
+#define FAULTD_EVENT_PROCESSOR_H
+
+#include "event.h"
+#include "notify_queue.h"
+#include "list.h"
+
+struct faultd_event_handler {
+       char *name;
+       /* Would you like to handle this? */
+       int (*event_match)(struct faultd_event_handler *handler,
+                                          struct faultd_event *ev);
+
+       /* Called each time when there is sth in a queue */
+       int (*handle_event)(struct faultd_event_handler *handler);
+
+       /* Initialized internally by FW */
+       struct nqueue_head event_queue;
+       struct sd_event_source *event_queue_sd_source;
+
+       /* has to be initialized */
+       struct list_head node;
+};
+
+int event_processor_report_event(struct faultd_event *ev);
+
+int event_processor_handler_register(struct faultd_event_handler *handler);
+void event_processor_handler_unregister(struct faultd_event_handler *handler);
+
+#define FAULTD_EVENT_HANDLER_REGISTER(EVENT_HANDLER, NAME, TYPE)           \
+static int event_handler_ ##NAME## _init(struct faultd_module *module,  \
+                                                                                sd_event *event_loop)                  \
+{                                                                                                                                              \
+    return event_processor_handler_register(&EVENT_HANDLER);                   \
+}                                                                                                                                              \
+                                                                                                                                               \
+static void event_handler_ ##NAME## _cleanup(struct faultd_module *module) \
+{                                                                                                                                              \
+    event_processor_handler_unregister(&EVENT_HANDLER);                                        \
+}                                                                                                                                              \
+                                                                                                                                               \
+static struct faultd_module event_handler_ ##NAME## _module = {                        \
+    .name = #NAME,                                                                                                             \
+    .type = TYPE,                                                                                                              \
+    .init = event_handler_ ##NAME## _init,                                                             \
+    .cleanup = event_handler_ ##NAME## _cleanup,                                               \
+    .node = LIST_HEAD_INIT(event_handler_ ##NAME## _module.node),              \
+};                                                                                                                                             \
+                                                                                                                                               \
+FAULTD_MODULE_REGISTER(&event_handler_ ##NAME## _module)
+
+#endif /* FAULTD_EVENT_PROCESSOR_H */