summaryrefslogtreecommitdiff
path: root/src/libmowgli/eventloop/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmowgli/eventloop/timer.c')
-rw-r--r--src/libmowgli/eventloop/timer.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/libmowgli/eventloop/timer.c b/src/libmowgli/eventloop/timer.c
new file mode 100644
index 0000000..d8c5061
--- /dev/null
+++ b/src/libmowgli/eventloop/timer.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>
+ * Copyright (c) 2005-2007 Atheme Project (http://www.atheme.org)
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mowgli.h"
+
+static mowgli_heap_t *timer_heap = NULL;
+
+static mowgli_eventloop_timer_t *mowgli_timer_add_real(mowgli_eventloop_t *eventloop,
+ const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when, time_t frequency)
+{
+ mowgli_eventloop_timer_t *timer;
+
+ return_val_if_fail(eventloop != NULL, NULL);
+ return_val_if_fail(func != NULL, NULL);
+
+ if (timer_heap == NULL)
+ timer_heap = mowgli_heap_create(sizeof(mowgli_eventloop_timer_t), 16, BH_NOW);
+
+ timer = mowgli_heap_alloc(timer_heap);
+
+ timer->func = func;
+ timer->name = name;
+ timer->arg = arg;
+ timer->when = mowgli_eventloop_get_time(eventloop) + when;
+ timer->frequency = frequency;
+ timer->active = true;
+
+ if (eventloop->deadline <= mowgli_eventloop_get_time(eventloop) || timer->when <= eventloop->deadline)
+ eventloop->deadline = timer->when;
+
+ mowgli_node_add(timer, &timer->node, &eventloop->timer_list);
+
+#ifdef DEBUG
+ mowgli_log("[timer(%p) add when:%d active:%d] [eventloop deadline:%d]", timer, timer->when, timer->active, eventloop->deadline);
+#endif
+
+ return timer;
+}
+
+/* add an event to the table to be continually ran */
+mowgli_eventloop_timer_t *mowgli_timer_add(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when)
+{
+ return mowgli_timer_add_real(eventloop, name, func, arg, when, when);
+}
+
+/* adds an event to the table to be ran only once */
+mowgli_eventloop_timer_t *mowgli_timer_add_once(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when)
+{
+ return mowgli_timer_add_real(eventloop, name, func, arg, when, 0);
+}
+
+/* delete an event from the table */
+void mowgli_timer_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_timer_t *timer)
+{
+ return_if_fail(eventloop != NULL);
+ return_if_fail(timer != NULL);
+
+ if (eventloop->last_ran == timer->name)
+ eventloop->last_ran = "<removed>";
+
+ mowgli_node_delete(&timer->node, &eventloop->timer_list);
+ mowgli_heap_free(timer_heap, timer);
+}
+
+/* checks all pending events */
+void mowgli_eventloop_run_timers(mowgli_eventloop_t *eventloop)
+{
+ mowgli_node_t *n, *tn;
+ time_t currtime;
+
+ return_if_fail(eventloop != NULL);
+
+ currtime = mowgli_eventloop_get_time(eventloop);
+
+ MOWGLI_ITER_FOREACH_SAFE(n, tn, eventloop->timer_list.head)
+ {
+ mowgli_eventloop_timer_t *timer = n->data;
+
+ if (timer->active && timer->when <= currtime)
+ {
+ /* now we call it */
+ eventloop->last_ran = timer->name;
+ timer->func(timer->arg);
+
+ /* invalidate eventloop sleep-until time */
+ eventloop->deadline = -1;
+
+ /* event is scheduled more than once */
+ if (timer->frequency)
+ timer->when = currtime + timer->frequency;
+ else
+ {
+ /* XXX: yuck. find a better way to handle this. */
+ eventloop->last_ran = "<onceonly>";
+
+ mowgli_timer_destroy(eventloop, timer);
+ }
+ }
+ }
+}
+
+/* returns the time the next mowgli_timer_run() should happen */
+time_t mowgli_eventloop_next_timer(mowgli_eventloop_t *eventloop)
+{
+ mowgli_node_t *n;
+
+ return_val_if_fail(eventloop != NULL, 0);
+
+ if (eventloop->deadline == -1)
+ {
+ MOWGLI_ITER_FOREACH(n, eventloop->timer_list.head)
+ {
+ mowgli_eventloop_timer_t *timer = n->data;
+
+ if (timer->active && (timer->when < eventloop->deadline || eventloop->deadline == -1))
+ eventloop->deadline = timer->when;
+
+#ifdef DEBUG
+ mowgli_log("timer %p active:%d when:%ld deadline:%ld", timer, timer->active, timer->when, eventloop->deadline);
+#endif
+ }
+ }
+
+#ifdef DEBUG
+ mowgli_log("eventloop deadline:%ld", eventloop->deadline);
+#endif
+
+ return eventloop->deadline;
+}
+
+/* finds an event in the table */
+mowgli_eventloop_timer_t *mowgli_timer_find(mowgli_eventloop_t *eventloop, mowgli_event_dispatch_func_t *func, void *arg)
+{
+ mowgli_node_t *n;
+
+ return_val_if_fail(eventloop != NULL, NULL);
+ return_val_if_fail(func != NULL, NULL);
+
+ MOWGLI_ITER_FOREACH(n, eventloop->timer_list.head)
+ {
+ mowgli_eventloop_timer_t *timer = n->data;
+
+ if (timer->func == func && timer->arg == arg)
+ return timer;
+ }
+
+ return NULL;
+}
+
+/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
+ * vim:ts=8
+ * vim:sw=8
+ * vim:noexpandtab
+ */