From 104efd92c5474245cbcb192fd3bd130af724e50c Mon Sep 17 00:00:00 2001
From: Marek Vavrusa <marek.vavrusa@nic.cz>
Date: Thu, 5 Dec 2013 16:37:57 +0100
Subject: [PATCH] evsched now cancells even self-scheduling events

* evsched now uses common errcodes instead of magic values
* updated tests
---
 src/common/evsched.c    | 69 +++++++++++++++++++++--------------------
 src/common/evsched.h    | 33 +++++---------------
 src/knot/server/zones.c |  2 +-
 tests/events.c          |  3 +-
 4 files changed, 46 insertions(+), 61 deletions(-)

diff --git a/src/common/evsched.c b/src/common/evsched.c
index be8e621a59..6fa0fa8c6f 100644
--- a/src/common/evsched.c
+++ b/src/common/evsched.c
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#include "common/errcode.h"
 #include "common/evsched.h"
 
 /*! \todo Fix properly (issue #1581). */
@@ -64,13 +65,13 @@ static void evsched_settimer(event_t *e, uint32_t dt)
 }
 
 /*! \brief Singleton application-wide event scheduler. */
-evsched_t *s_evsched = 0;
+evsched_t *s_evsched = NULL;
 
 evsched_t *evsched_new()
 {
 	evsched_t *s = malloc(sizeof(evsched_t));
 	if (!s) {
-		return 0;
+		return NULL;
 	}
 	memset(s, 0, sizeof(evsched_t));
 
@@ -88,10 +89,7 @@ evsched_t *evsched_new()
 
 void evsched_delete(evsched_t **s)
 {
-	if (!s) {
-		return;
-	}
-	if (!*s) {
+	if (s == NULL || *s == NULL) {
 		return;
 	}
 
@@ -119,13 +117,13 @@ void evsched_delete(evsched_t **s)
 
 	/* Free scheduler. */
 	free(*s);
-	*s = 0;
+	*s = NULL;
 }
 
 event_t *evsched_event_new(evsched_t *s, int type)
 {
 	if (!s) {
-		return 0;
+		return NULL;
 	}
 
 	/* Allocate. */
@@ -165,7 +163,7 @@ event_t* evsched_next(evsched_t *s)
 {
 	/* Check. */
 	if (!s) {
-		return 0;
+		return NULL;
 	}
 
 	/* Lock calendar. */
@@ -214,31 +212,31 @@ event_t* evsched_next(evsched_t *s)
 
 	/* Unlock calendar, this shouldn't happen. */
 	pthread_mutex_unlock(&s->mx);
-	return 0;
+	return NULL;
 
 }
 
 int evsched_event_finished(evsched_t *s)
 {
 	if (!s) {
-		return -1;
+		return KNOT_EINVAL;
 	}
 
 	/* Mark as finished. */
 	if (s->cur) {
 		s->cur = NULL;
 		pthread_mutex_unlock(&s->rl);
-		return 0;
+		return KNOT_EOK;
 	}
 
-	/* Finished event is not current. */
-	return -1;
+	/* No event running. */
+	return KNOT_ENOTRUNNING;
 }
 
 int evsched_schedule(evsched_t *s, event_t *ev, uint32_t dt)
 {
 	if (!s || !ev) {
-		return -1;
+		return KNOT_EINVAL;
 	}
 
 	/* Update event timer. */
@@ -254,19 +252,19 @@ int evsched_schedule(evsched_t *s, event_t *ev, uint32_t dt)
 	pthread_cond_broadcast(&s->notify);
 	pthread_mutex_unlock(&s->mx);
 
-	return 0;
+	return KNOT_EOK;
 }
 
 event_t* evsched_schedule_cb(evsched_t *s, event_cb_t cb, void *data, uint32_t dt)
 {
 	if (!s) {
-		return 0;
+		return NULL;
 	}
 
 	/* Create event. */
 	event_t *e = evsched_event_new(s, EVSCHED_CB);
 	if (!e) {
-		return 0;
+		return NULL;
 	}
 	e->cb = cb;
 	e->data = data;
@@ -274,7 +272,7 @@ event_t* evsched_schedule_cb(evsched_t *s, event_cb_t cb, void *data, uint32_t d
 	/* Schedule. */
 	if (evsched_schedule(s, e, dt) != 0) {
 		evsched_event_free(s, e);
-		e = 0;
+		e = NULL;
 	}
 
 	return e;
@@ -283,30 +281,30 @@ event_t* evsched_schedule_cb(evsched_t *s, event_cb_t cb, void *data, uint32_t d
 event_t* evsched_schedule_term(evsched_t *s, uint32_t dt)
 {
 	if (!s) {
-		return 0;
+		return NULL;
 	}
 
 	/* Create event. */
 	event_t *e = evsched_event_new(s, EVSCHED_TERM);
 	if (!e) {
-		return 0;
+		return NULL;
 	}
 
 	/* Schedule. */
 	if (evsched_schedule(s, e, dt) != 0) {
 		evsched_event_free(s, e);
-		e = 0;
+		e = NULL;
 	}
 
 	return e;
 }
 
-int evsched_cancel(evsched_t *s, event_t *ev)
+static int evsched_try_cancel(evsched_t *s, event_t *ev)
 {
-	int found;
+	int found = 0;
 
 	if (!s || !ev) {
-		return -1;
+		return KNOT_EINVAL;
 	}
 
 	/* Make sure not running. */
@@ -325,7 +323,7 @@ int evsched_cancel(evsched_t *s, event_t *ev)
 	 */
 	if (s->cur == ev) {
 		s->cur = NULL; /* Invalidate */
-		found = -1; /* Return error, since the event is running again */
+		found = KNOT_EAGAIN; /* Already ran, try again. */
 	}
 
 	/* Unlock calendar. */
@@ -334,20 +332,25 @@ int evsched_cancel(evsched_t *s, event_t *ev)
 
 	/* Enable running events. */
 	pthread_mutex_unlock(&s->rl);
+	if (found) {
+		return KNOT_EOK;
+	}
 
-	return found;
+	return KNOT_ENOENT;
 }
 
-int evsched_cancel_child(evsched_t *s, event_t *ev)
+int evsched_cancel(evsched_t *s, event_t *ev)
 {
 	if (!s || !ev) {
-		return -1;
+		return KNOT_EINVAL;
 	}
 
-	int ret = 0;
-	while (((ret = evsched_cancel(s, ev)) < 0) && s && ev) {
-		;
+	/* Event may have already run, try again. */
+	int ret = KNOT_EAGAIN;
+	while (ret == KNOT_EAGAIN) {
+		ret = evsched_try_cancel(s, ev);
 	}
 
-	return ret;
+	/* Now we're sure event is cancelled or finished. */
+	return KNOT_EOK;
 }
diff --git a/src/common/evsched.h b/src/common/evsched.h
index be0297aead..4e710a59b8 100644
--- a/src/common/evsched.h
+++ b/src/common/evsched.h
@@ -155,8 +155,9 @@ event_t* evsched_next(evsched_t *s);
  *
  * \param s Event scheduler.
  *
- * \retval 0 if successful.
- * \retval -1 on errors.
+ * \retval KNOT_EOK if successful.
+ * \retval KNOT_EINVAL
+ * \retval KNOT_ENOTRUNNING
  */
 int evsched_event_finished(evsched_t *s);
 
@@ -167,8 +168,8 @@ int evsched_event_finished(evsched_t *s);
  * \param ev Prepared event.
  * \param dt Time difference in milliseconds from now (dt is relative).
  *
- * \retval 0 on success.
- * \retval <0 on error.
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL
  */
 int evsched_schedule(evsched_t *s, event_t *ev, uint32_t dt);
 
@@ -212,31 +213,11 @@ event_t* evsched_schedule_term(evsched_t *s, uint32_t dt);
  * \param s Event scheduler.
  * \param ev Scheduled event.
  *
- * \retval 0 if already ran.
- * \retval 1 if found and cancelled.
- * \retval <0 on error.
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
  */
 int evsched_cancel(evsched_t *s, event_t *ev);
 
-/*!
- * \brief Cancel a scheduled event. Same as 'evsched_cancel' but also cancels
- *        event that might have been scheduled by the cancelled event.
- *
- * \warning May block until current running event is finished (as it cannot
- *          interrupt running event).
- *
- * \warning Never cancel event in it's callback. As it never finishes,
- *          it deadlocks.
- *
- * \param s Event scheduler.
- * \param ev Scheduled event.
- *
- * \retval 0 if already ran.
- * \retval 1 if found and cancelled.
- * \retval <0 on error.
- */
-int evsched_cancel_child(evsched_t *s, event_t *ev);
-
 /* Singleton event scheduler pointer. */
 extern evsched_t *s_evsched;
 
diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
index 90a799d76f..f95cdab070 100644
--- a/src/knot/server/zones.c
+++ b/src/knot/server/zones.c
@@ -2613,7 +2613,7 @@ int zones_cancel_dnssec(knot_zone_t *zone)
 	evsched_t *scheduler = zd->server->sched;
 
 	if (zd->dnssec_timer) {
-		evsched_cancel_child(scheduler, zd->dnssec_timer);
+		evsched_cancel(scheduler, zd->dnssec_timer);
 	}
 
 	return KNOT_EOK;
diff --git a/tests/events.c b/tests/events.c
index 664409d302..2ba8177c19 100644
--- a/tests/events.c
+++ b/tests/events.c
@@ -22,6 +22,7 @@
 
 #include "common/evqueue.h"
 #include "common/evsched.h"
+#include "common/errcode.h"
 
 void* term_thr(void *arg)
 {
@@ -146,7 +147,7 @@ int main(int argc, char *argv[])
 	// 7. Insert and immediately cancel an event
 	e = evsched_schedule_cb(s, 0, (void*)0xdead, 1000);
 	ret = evsched_cancel(s, e);
-	ok(ret >= 0, "evsched: inserted and cancelled an event");
+	ok(ret == KNOT_EOK, "evsched: inserted and cancelled an event");
 	if (e) {
 		evsched_event_free(s, e);
 	}
-- 
GitLab