|
@@ -0,0 +1,316 @@
|
|
|
+/** @file eloop.c
|
|
|
+ * @brief Class for
|
|
|
+ */
|
|
|
+
|
|
|
+#ifdef HAVE_CONFIG_H
|
|
|
+#include "config.h"
|
|
|
+#endif /* HAVE_CONFIG_H */
|
|
|
+
|
|
|
+#include <stdlib.h>
|
|
|
+#include <stdint.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <string.h>
|
|
|
+#include <assert.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <errno.h>
|
|
|
+#include <sys/types.h>
|
|
|
+#include <sys/stat.h>
|
|
|
+#include <fcntl.h>
|
|
|
+#include <time.h>
|
|
|
+#include <signal.h>
|
|
|
+#include <poll.h>
|
|
|
+
|
|
|
+#include "faux/faux.h"
|
|
|
+#include "faux/str.h"
|
|
|
+#include "faux/net.h"
|
|
|
+#include "faux/sched.h"
|
|
|
+#include "faux/eloop.h"
|
|
|
+
|
|
|
+#include "private.h"
|
|
|
+
|
|
|
+
|
|
|
+static int faux_eloop_sched_compare(const void *first, const void *second)
|
|
|
+{
|
|
|
+ const faux_eloop_sched_t *f = (const faux_eloop_sched_t *)first;
|
|
|
+ const faux_eloop_sched_t *s = (const faux_eloop_sched_t *)second;
|
|
|
+
|
|
|
+ return (f->ev_id - s->ev_id);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int faux_eloop_sched_kcompare(const void *key, const void *list_item)
|
|
|
+{
|
|
|
+ int *f = (int *)key;
|
|
|
+ const faux_eloop_sched_t *s = (const faux_eloop_sched_t *)list_item;
|
|
|
+
|
|
|
+ return (*f - s->ev_id);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int faux_eloop_fd_compare(const void *first, const void *second)
|
|
|
+{
|
|
|
+ const faux_eloop_fd_t *f = (const faux_eloop_fd_t *)first;
|
|
|
+ const faux_eloop_fd_t *s = (const faux_eloop_fd_t *)second;
|
|
|
+
|
|
|
+ return (f->fd - s->fd);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int faux_eloop_fd_kcompare(const void *key, const void *list_item)
|
|
|
+{
|
|
|
+ int *f = (int *)key;
|
|
|
+ const faux_eloop_fd_t *s = (const faux_eloop_fd_t *)list_item;
|
|
|
+
|
|
|
+ return (*f - s->fd);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int faux_eloop_signal_compare(const void *first, const void *second)
|
|
|
+{
|
|
|
+ const faux_eloop_signal_t *f = (const faux_eloop_signal_t *)first;
|
|
|
+ const faux_eloop_signal_t *s = (const faux_eloop_signal_t *)second;
|
|
|
+
|
|
|
+ return (f->signo - s->signo);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int faux_eloop_signal_kcompare(const void *key, const void *list_item)
|
|
|
+{
|
|
|
+ int *f = (int *)key;
|
|
|
+ const faux_eloop_signal_t *s = (const faux_eloop_signal_t *)list_item;
|
|
|
+
|
|
|
+ return (*f - s->signo);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+faux_eloop_t *faux_eloop_new(faux_eloop_cb_f *default_event_cb)
|
|
|
+{
|
|
|
+ faux_eloop_t *eloop = NULL;
|
|
|
+
|
|
|
+ eloop = faux_zmalloc(sizeof(*eloop));
|
|
|
+ assert(eloop);
|
|
|
+ if (!eloop)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ // Init
|
|
|
+ eloop->default_event_cb = default_event_cb;
|
|
|
+
|
|
|
+ // Sched
|
|
|
+ eloop->scheds = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
|
|
|
+ faux_eloop_sched_compare, faux_eloop_sched_kcompare, faux_free);
|
|
|
+ assert(eloop->scheds);
|
|
|
+ eloop->faux_sched = faux_sched_new();
|
|
|
+ assert(eloop->faux_sched);
|
|
|
+
|
|
|
+ // FD
|
|
|
+ eloop->fds = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
|
|
|
+ faux_eloop_fd_compare, faux_eloop_fd_kcompare, faux_free);
|
|
|
+ assert(eloop->fds);
|
|
|
+ eloop->pollfds = faux_pollfd_new();
|
|
|
+ assert(eloop->pollfds);
|
|
|
+
|
|
|
+ // Signal
|
|
|
+ eloop->signals = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
|
|
|
+ faux_eloop_signal_compare, faux_eloop_signal_kcompare, faux_free);
|
|
|
+ assert(eloop->signals);
|
|
|
+ sigemptyset(&eloop->sig_set);
|
|
|
+
|
|
|
+ return eloop;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void faux_eloop_free(faux_eloop_t *eloop)
|
|
|
+{
|
|
|
+ if (!eloop)
|
|
|
+ return;
|
|
|
+
|
|
|
+ faux_list_free(eloop->signals);
|
|
|
+ faux_pollfd_free(eloop->pollfds);
|
|
|
+ faux_list_free(eloop->fds);
|
|
|
+ faux_sched_free(eloop->faux_sched);
|
|
|
+ faux_list_free(eloop->scheds);
|
|
|
+
|
|
|
+ faux_free(eloop);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+bool_t faux_eloop_loop(faux_eloop_t *eloop)
|
|
|
+{
|
|
|
+ bool_t retval = BOOL_TRUE;
|
|
|
+ bool_t stop = BOOL_FALSE;
|
|
|
+
|
|
|
+/*
|
|
|
+ // Set signal handler
|
|
|
+ syslog(LOG_DEBUG, "Set signal handlers\n");
|
|
|
+ sigemptyset(&sig_set);
|
|
|
+ sigaddset(&sig_set, SIGTERM);
|
|
|
+ sigaddset(&sig_set, SIGINT);
|
|
|
+ sigaddset(&sig_set, SIGQUIT);
|
|
|
+
|
|
|
+ sig_act.sa_flags = 0;
|
|
|
+ sig_act.sa_mask = sig_set;
|
|
|
+ sig_act.sa_handler = &sighandler;
|
|
|
+ sigaction(SIGTERM, &sig_act, NULL);
|
|
|
+ sigaction(SIGINT, &sig_act, NULL);
|
|
|
+ sigaction(SIGQUIT, &sig_act, NULL);
|
|
|
+
|
|
|
+ // SIGHUP handler
|
|
|
+ sigemptyset(&sig_set);
|
|
|
+ sigaddset(&sig_set, SIGHUP);
|
|
|
+
|
|
|
+ sig_act.sa_flags = 0;
|
|
|
+ sig_act.sa_mask = sig_set;
|
|
|
+ sig_act.sa_handler = &sighup_handler;
|
|
|
+ sigaction(SIGHUP, &sig_act, NULL);
|
|
|
+
|
|
|
+ // SIGCHLD handler
|
|
|
+ sigemptyset(&sig_set);
|
|
|
+ sigaddset(&sig_set, SIGCHLD);
|
|
|
+
|
|
|
+ sig_act.sa_flags = 0;
|
|
|
+ sig_act.sa_mask = sig_set;
|
|
|
+ sig_act.sa_handler = &sigchld_handler;
|
|
|
+ sigaction(SIGCHLD, &sig_act, NULL);
|
|
|
+
|
|
|
+ // Block signals to prevent race conditions while loop and ppoll()
|
|
|
+ // Catch signals while ppoll() only
|
|
|
+ sigemptyset(&sig_set);
|
|
|
+ sigaddset(&sig_set, SIGTERM);
|
|
|
+ sigaddset(&sig_set, SIGINT);
|
|
|
+ sigaddset(&sig_set, SIGQUIT);
|
|
|
+ sigaddset(&sig_set, SIGHUP);
|
|
|
+ sigaddset(&sig_set, SIGCHLD);
|
|
|
+ sigprocmask(SIG_BLOCK, &sig_set, &orig_sig_set);
|
|
|
+*/
|
|
|
+ // Main loop
|
|
|
+ while (!stop) {
|
|
|
+ int sn = 0;
|
|
|
+ struct timespec *timeout = NULL;
|
|
|
+// struct timespec next_interval = {};
|
|
|
+ faux_pollfd_iterator_t pollfd_iter;
|
|
|
+ struct pollfd *pollfd = NULL;
|
|
|
+// pid_t pid = -1;
|
|
|
+
|
|
|
+ // Re-read config file on SIGHUP
|
|
|
+/* if (sighup) {
|
|
|
+ if (access(opts->cfgfile, R_OK) == 0) {
|
|
|
+ syslog(LOG_INFO, "Re-reading config file \"%s\"\n", opts->cfgfile);
|
|
|
+ if (config_parse(opts->cfgfile, opts) < 0)
|
|
|
+ syslog(LOG_ERR, "Error while config file parsing.\n");
|
|
|
+ } else if (opts->cfgfile_userdefined) {
|
|
|
+ syslog(LOG_ERR, "Can't find config file \"%s\"\n", opts->cfgfile);
|
|
|
+ }
|
|
|
+ sighup = 0;
|
|
|
+ }
|
|
|
+*/
|
|
|
+ // Find out next scheduled interval
|
|
|
+/* if (faux_sched_next_interval(eloop->sched, &next_interval) < 0)
|
|
|
+ timeout = NULL;
|
|
|
+ else
|
|
|
+ timeout = &next_interval;
|
|
|
+*/
|
|
|
+ // Wait for events
|
|
|
+// sn = ppoll(faux_pollfd_vector(fds), faux_pollfd_len(fds), timeout, &orig_sig_set);
|
|
|
+ sn = ppoll(faux_pollfd_vector(eloop->pollfds), faux_pollfd_len(eloop->pollfds), timeout, NULL);
|
|
|
+ if (sn < 0) {
|
|
|
+ if ((EAGAIN == errno) || (EINTR == errno))
|
|
|
+ continue;
|
|
|
+ retval = BOOL_FALSE;
|
|
|
+printf("ppoll() error\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Scheduled event
|
|
|
+ if (0 == sn) {
|
|
|
+// int id = 0; // Event idenftifier
|
|
|
+// void *data = NULL; // Event data
|
|
|
+// faux_eloop_info_sched_t info = {};
|
|
|
+
|
|
|
+printf("Sheduled event\n");
|
|
|
+ // Some scheduled events
|
|
|
+/* while(faux_sched_pop(sched, &id, &data) == 0) {
|
|
|
+ syslog(LOG_DEBUG, "sched: Update event\n");
|
|
|
+ }
|
|
|
+*/ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // File descriptor
|
|
|
+ faux_pollfd_init_iterator(eloop->pollfds, &pollfd_iter);
|
|
|
+ while ((pollfd = faux_pollfd_each_active(eloop->pollfds, &pollfd_iter))) {
|
|
|
+ int fd = pollfd->fd;
|
|
|
+ faux_eloop_info_fd_t info = {};
|
|
|
+ faux_eloop_cb_f *event_cb = NULL;
|
|
|
+ faux_eloop_fd_t *entry = NULL;
|
|
|
+ bool_t r = BOOL_TRUE;
|
|
|
+
|
|
|
+ // Prepare event data
|
|
|
+ entry = (faux_eloop_fd_t *)faux_list_kfind(eloop->fds, &fd);
|
|
|
+ assert(entry);
|
|
|
+ if (!entry) // Something went wrong
|
|
|
+ continue;
|
|
|
+ event_cb = entry->context.event_cb;
|
|
|
+ if (!event_cb)
|
|
|
+ event_cb = eloop->default_event_cb;
|
|
|
+ if (!event_cb) // Callback function is not defined for this event
|
|
|
+ continue;
|
|
|
+ info.fd = fd;
|
|
|
+ info.revents = pollfd->revents;
|
|
|
+
|
|
|
+ // Execute callback
|
|
|
+ r = event_cb(eloop, FAUX_ELOOP_FD, &info, entry->context.user_data);
|
|
|
+ // BOOL_FALSE return value means "break the loop"
|
|
|
+ if (!r)
|
|
|
+ stop = BOOL_TRUE;
|
|
|
+ }
|
|
|
+
|
|
|
+ } // Loop end
|
|
|
+
|
|
|
+ return retval;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+bool_t faux_eloop_add_fd(faux_eloop_t *eloop, int fd, short events,
|
|
|
+ faux_eloop_cb_f *event_cb, void *user_data)
|
|
|
+{
|
|
|
+ faux_eloop_fd_t *entry = NULL;
|
|
|
+ faux_list_node_t *new_node = NULL;
|
|
|
+
|
|
|
+ if (!eloop || (fd < 0))
|
|
|
+ return BOOL_FALSE;
|
|
|
+
|
|
|
+ entry = faux_zmalloc(sizeof(*entry));
|
|
|
+ if (!entry)
|
|
|
+ return BOOL_FALSE;
|
|
|
+ entry->fd = fd;
|
|
|
+ entry->events = events;
|
|
|
+ entry->context.event_cb = event_cb;
|
|
|
+ entry->context.user_data = user_data;
|
|
|
+
|
|
|
+ if (!(new_node = faux_list_add(eloop->fds, entry))) {
|
|
|
+ faux_free(entry);
|
|
|
+ return BOOL_FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!faux_pollfd_add(eloop->pollfds, entry->fd, entry->events)) {
|
|
|
+ faux_list_del(eloop->fds, new_node);
|
|
|
+ faux_free(entry);
|
|
|
+ return BOOL_FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ return BOOL_TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+bool_t faux_eloop_del_fd(faux_eloop_t *eloop, int fd)
|
|
|
+{
|
|
|
+ if (!eloop || (fd < 0))
|
|
|
+ return BOOL_FALSE;
|
|
|
+
|
|
|
+ if (faux_list_kdel(eloop->fds, &fd) < 0)
|
|
|
+ return BOOL_FALSE;
|
|
|
+
|
|
|
+ if (faux_pollfd_del_by_fd(eloop->pollfds, fd) < 0)
|
|
|
+ return BOOL_FALSE;
|
|
|
+
|
|
|
+ return BOOL_TRUE;
|
|
|
+}
|