--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */