Browse Source

faux.eloop: Add unfinished implementation of Event Loop

Serj Kalichev 3 years ago
parent
commit
6fa43755de
6 changed files with 408 additions and 0 deletions
  1. 3 0
      faux/Makefile.am
  2. 1 0
      faux/all.h
  3. 47 0
      faux/eloop.h
  4. 3 0
      faux/eloop/Makefile.am
  5. 316 0
      faux/eloop/eloop.c
  6. 38 0
      faux/eloop/private.h

+ 3 - 0
faux/Makefile.am

@@ -24,6 +24,7 @@ nobase_include_HEADERS += \
 	faux/sched.h \
 	faux/net.h \
 	faux/msg.h \
+	faux/eloop.h \
 	faux/testc_helpers.h
 
 EXTRA_DIST += \
@@ -42,6 +43,7 @@ EXTRA_DIST += \
 	faux/sched/Makefile.am \
 	faux/net/Makefile.am \
 	faux/msg/Makefile.am \
+	faux/eloop/Makefile.am \
 	faux/testc_helpers/Makefile.am
 
 include $(top_srcdir)/faux/base/Makefile.am
@@ -59,6 +61,7 @@ include $(top_srcdir)/faux/time/Makefile.am
 include $(top_srcdir)/faux/sched/Makefile.am
 include $(top_srcdir)/faux/net/Makefile.am
 include $(top_srcdir)/faux/msg/Makefile.am
+include $(top_srcdir)/faux/eloop/Makefile.am
 include $(top_srcdir)/faux/testc_helpers/Makefile.am
 
 if TESTC

+ 1 - 0
faux/all.h

@@ -19,4 +19,5 @@
 #include <faux/ini.h>
 #include <faux/sched.h>
 #include <faux/msg.h>
+#include <faux/eloop.h>
 #include <faux/testc_helpers.h>

+ 47 - 0
faux/eloop.h

@@ -0,0 +1,47 @@
+/** @file eloop.h
+ * @brief Public interface for Event Loop.
+ */
+
+#ifndef _faux_eloop_h
+#define _faux_eloop_h
+
+#include <faux/faux.h>
+
+typedef struct faux_eloop_s faux_eloop_t;
+
+typedef enum {
+	FAUX_ELOOP_NULL = 0,
+	FAUX_ELOOP_SIGNAL = 1,
+	FAUX_ELOOP_SCHED = 2,
+	FAUX_ELOOP_FD = 3
+} faux_eloop_type_e;
+
+typedef bool_t faux_eloop_cb_f(faux_eloop_t *eloop, faux_eloop_type_e type,
+	void *associated_data, void *user_data);
+
+typedef struct {
+	int ev_id;
+} faux_eloop_info_sched_t;
+
+typedef struct {
+	int fd;
+	short revents;
+} faux_eloop_info_fd_t;
+
+typedef struct {
+	int signo;
+} faux_eloop_info_signal_t;
+
+
+C_DECL_BEGIN
+
+faux_eloop_t *faux_eloop_new(faux_eloop_cb_f *default_event_cb);
+void faux_eloop_free(faux_eloop_t *eloop);
+bool_t faux_eloop_loop(faux_eloop_t *eloop);
+bool_t faux_eloop_add_fd(faux_eloop_t *eloop, int fd, short events,
+	faux_eloop_cb_f *event_cb, void *user_data);
+bool_t faux_eloop_del_fd(faux_eloop_t *eloop, int fd);
+
+C_DECL_END
+
+#endif

+ 3 - 0
faux/eloop/Makefile.am

@@ -0,0 +1,3 @@
+libfaux_la_SOURCES += \
+	faux/eloop/eloop.c \
+	faux/eloop/private.h

+ 316 - 0
faux/eloop/eloop.c

@@ -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;
+}

+ 38 - 0
faux/eloop/private.h

@@ -0,0 +1,38 @@
+#include "faux/faux.h"
+#include "faux/list.h"
+#include "faux/net.h"
+#include "faux/vec.h"
+#include "faux/sched.h"
+
+
+struct faux_eloop_s {
+	faux_eloop_cb_f *default_event_cb;
+	faux_list_t *scheds;
+	faux_sched_t *faux_sched;
+	faux_list_t *fds;
+	faux_pollfd_t *pollfds;
+	faux_list_t *signals;
+	sigset_t sig_set;
+};
+
+
+typedef struct faux_eloop_context_s {
+	faux_eloop_cb_f *event_cb;
+	void *user_data;
+} faux_eloop_context_t;
+
+typedef struct faux_eloop_shed_s {
+	int ev_id;
+	faux_eloop_context_t context;
+} faux_eloop_sched_t;
+
+typedef struct faux_eloop_fd_s {
+	int fd;
+	short events;
+	faux_eloop_context_t context;
+} faux_eloop_fd_t;
+
+typedef struct faux_eloop_signal_s {
+	int signo;
+	faux_eloop_context_t context;
+} faux_eloop_signal_t;