From 6cd252666dafdded0f8cedd7d2e86709179dd4f9 Mon Sep 17 00:00:00 2001
From: Marek Vavrusa <marek@vavrusa.com>
Date: Thu, 28 Apr 2011 18:09:57 +0200
Subject: [PATCH] Event scheduler runnable in server, see server_t.

Example:
evsched_schedule_cb(server->sched, mycallback, data, 1000); // dt=1s

Commit refs #799.
---
 src/common/evqueue.h     |  1 +
 src/common/evsched.c     | 23 ++++++++++-----
 src/common/evsched.h     | 20 +++++++++++++-
 src/knot/server/server.c | 60 ++++++++++++++++++++++++++++++++++++++--
 src/knot/server/server.h |  4 +++
 5 files changed, 98 insertions(+), 10 deletions(-)

diff --git a/src/common/evqueue.h b/src/common/evqueue.h
index eb57ca7904..bbba5ac7de 100644
--- a/src/common/evqueue.h
+++ b/src/common/evqueue.h
@@ -45,6 +45,7 @@ typedef struct event_t {
 	struct timeval tv; /*!< Event scheduled time. */
 	void *data;        /*!< Usable data ptr. */
 	event_cb_t cb;     /*!< Event callback. */
+	void *caller;      /*!< Pointer to caller. */
 } event_t;
 
 /*!
diff --git a/src/common/evsched.c b/src/common/evsched.c
index cd0222c80b..9e9426350a 100644
--- a/src/common/evsched.c
+++ b/src/common/evsched.c
@@ -28,6 +28,9 @@ static void evsched_settimer(event_t *e, int dt)
 	}
 }
 
+/*! \brief Singleton application-wide event scheduler. */
+evsched_t *s_evsched = 0;
+
 evsched_t *evsched_new()
 {
 	evsched_t *s = malloc(sizeof(evsched_t));
@@ -143,12 +146,15 @@ event_t* evsched_next(evsched_t *s)
 
 }
 
-int evsched_schedule(evsched_t *s, event_t *ev)
+int evsched_schedule(evsched_t *s, event_t *ev, int dt)
 {
-	if (!s || !ev) {
+	if (!s || !ev || dt < 0) {
 		return -1;
 	}
 
+	/* Update event timer. */
+	evsched_settimer(ev, dt);
+
 	/* Lock calendar. */
 	pthread_mutex_lock(&s->mx);
 
@@ -184,15 +190,16 @@ event_t* evsched_schedule_cb(evsched_t *s, event_cb_t cb, void *data, int dt)
 		return 0;
 	}
 
+	/* Create event. */
 	event_t *e = evsched_event_new(s, EVSCHED_CB);
 	if (!e) {
 		return 0;
 	}
-
 	e->cb = cb;
 	e->data = data;
-	evsched_settimer(e, dt);
-	if (evsched_schedule(s, e) != 0) {
+
+	/* Schedule. */
+	if (evsched_schedule(s, e, dt) != 0) {
 		evsched_event_free(s, e);
 		e = 0;
 	}
@@ -206,13 +213,14 @@ event_t* evsched_schedule_term(evsched_t *s, int dt)
 		return 0;
 	}
 
+	/* Create event. */
 	event_t *e = evsched_event_new(s, EVSCHED_TERM);
 	if (!e) {
 		return 0;
 	}
 
-	evsched_settimer(e, dt);
-	if (evsched_schedule(s, e) != 0) {
+	/* Schedule. */
+	if (evsched_schedule(s, e, dt) != 0) {
 		evsched_event_free(s, e);
 		e = 0;
 	}
@@ -238,3 +246,4 @@ int evsched_cancel(evsched_t *s, event_t *ev)
 
 	return 0;
 }
+
diff --git a/src/common/evsched.h b/src/common/evsched.h
index 967ac1d86f..3f6cef82d0 100644
--- a/src/common/evsched.h
+++ b/src/common/evsched.h
@@ -134,11 +134,12 @@ event_t* evsched_next(evsched_t *s);
  *
  * \param s Event scheduler.
  * \param ev Prepared event.
+ * \param dt Time difference in milliseconds from now (dt is relative).
  *
  * \retval 0 on success.
  * \retval <0 on error.
  */
-int evsched_schedule(evsched_t *s, event_t *ev);
+int evsched_schedule(evsched_t *s, event_t *ev, int dt);
 
 /*!
  * \brief Schedule callback event.
@@ -179,6 +180,23 @@ event_t* evsched_schedule_term(evsched_t *s, int dt);
  */
 int evsched_cancel(evsched_t *s, event_t *ev);
 
+/* Singleton event scheduler pointer. */
+extern evsched_t *s_evsched;
+
+/*!
+ * \brief Event scheduler singleton.
+ */
+static inline evsched_t *evsched() {
+	return s_evsched;
+}
+
+/*!
+ * \brief Set event scheduler singleton.
+ */
+static inline void evsched_set(evsched_t *s) {
+	s_evsched = s;
+}
+
 
 #endif /* _KNOT_COMMON_EVSCHED_H_ */
 
diff --git a/src/knot/server/server.c b/src/knot/server/server.c
index 0046f96e44..4913414d1d 100644
--- a/src/knot/server/server.c
+++ b/src/knot/server/server.c
@@ -22,6 +22,47 @@
 #include "knot/conf/conf.h"
 #include "knot/server/zones.h"
 
+/*! \brief Event scheduler loop. */
+static int evsched_run(dthread_t *thread)
+{
+	iohandler_t *sched_h = (iohandler_t *)thread->data;
+	evsched_t *s = (evsched_t*)sched_h->data;
+	if (!s) {
+		return KNOT_EINVAL;
+	}
+
+	/* Run event loop. */
+	event_t *ev = 0;
+	while((ev = evsched_next(s))) {
+
+		/* Error. */
+		if (!ev) {
+			return KNOT_ERROR;
+		}
+
+		/* Process termination event. */
+		if (ev->type == EVSCHED_TERM) {
+			evsched_event_free(s, ev);
+			break;
+		}
+
+		/* Process event. */
+		if (ev->type == EVSCHED_CB && ev->cb) {
+			ev->caller = s;
+			ev->cb(ev);
+		} else {
+			evsched_event_free(s, ev);
+		}
+
+		/* Check for thread cancellation. */
+		if (dt_is_cancelled(thread)) {
+			break;
+		}
+	}
+
+	return KNOT_EOK;
+}
+
 /*! \brief List item for generic pointers. */
 typedef struct pnode_t {
 	struct node *next, *prev; /* Keep the ordering for lib/lists.h */
@@ -330,6 +371,13 @@ server_t *server_create()
 	server->ifaces = malloc(sizeof(list));
 	init_list(server->ifaces);
 
+	// Create event scheduler
+	debug_server("Creating event scheduler...\n");
+	server->sched = evsched_new();
+	dt_unit_t *unit = dt_create_coherent(1, evsched_run, 0);
+	iohandler_t *h = server_create_handler(server, -1, unit);
+	h->data = server->sched;
+
 	// Create name server
 	debug_server("Creating Name Server structure...\n");
 	server->nameserver = ns_create();
@@ -413,8 +461,10 @@ int server_remove_handler(server_t *server, iohandler_t *h)
 	}
 
 	// Close socket
-	socket_close(h->fd);
-	h->fd = -1;
+	if (h->fd >= 0) {
+		socket_close(h->fd);
+		h->fd = -1;
+	}
 
 	// Update interface
 	if (h->iface) {
@@ -520,6 +570,9 @@ int server_wait(server_t *server)
 
 void server_stop(server_t *server)
 {
+	/* Send termination event. */
+	evsched_schedule_term(server->sched, 0);
+
 	/* Lock RCU. */
 	rcu_read_lock();
 
@@ -559,6 +612,9 @@ void server_destroy(server_t **server)
 	// Free XFR master
 	xfr_free((*server)->xfr_h);
 
+	// Delete event scheduler
+	evsched_delete(&(*server)->sched);
+
 	stat_static_gath_free();
 	ns_destroy(&(*server)->nameserver);
 
diff --git a/src/knot/server/server.h b/src/knot/server/server.h
index 2da017c1b7..2c8ed139b7 100644
--- a/src/knot/server/server.h
+++ b/src/knot/server/server.h
@@ -27,6 +27,7 @@
 #include "knot/server/socket.h"
 #include "knot/server/dthreads.h"
 #include "dnslib/zonedb.h"
+#include "common/evsched.h"
 #include "common/lists.h"
 
 /* Forwad declarations. */
@@ -93,6 +94,9 @@ typedef struct server_t {
 	/*! \brief XFR handler. */
 	xfrhandler_t *xfr_h;
 
+	/*! \brief Event scheduler. */
+	evsched_t *sched;
+
 	/*! \brief I/O handlers list. */
 	list handlers;
 
-- 
GitLab