aboutsummaryrefslogtreecommitdiff
path: root/kernel/util/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/util/timer.c')
-rw-r--r--kernel/util/timer.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/kernel/util/timer.c b/kernel/util/timer.c
new file mode 100644
index 0000000..f1be4a2
--- /dev/null
+++ b/kernel/util/timer.c
@@ -0,0 +1,121 @@
+#include "util/timer.h"
+#include "proc/spinlock.h"
+#include "util/time.h"
+
+static timer_t *timer_running = NULL;
+static uint64_t timer_next_expiry = -1;
+static list_t timers_primary = LIST_INITIALIZER(timers_primary);
+static list_t timers_secondary = LIST_INITIALIZER(timers_secondary);
+static int timers_firing = 0;
+
+void timer_init(timer_t *timer)
+{
+ timer->expires = -1;
+ list_link_init(&timer->link);
+}
+
+void timer_add(timer_t *timer) { timer_mod(timer, timer->expires); }
+
+int __timer_del(timer_t *timer)
+{
+ int ret = 0;
+ if (list_link_is_linked(&timer->link))
+ {
+ list_remove(&timer->link);
+ ret = 1;
+ }
+ return ret;
+}
+
+int timer_del(timer_t *timer)
+{
+ int ret = __timer_del(timer);
+
+ return ret;
+}
+
+void __timer_add(timer_t *timer)
+{
+ KASSERT(!list_link_is_linked(&timer->link));
+ list_t *list = timers_firing ? &timers_secondary : &timers_primary;
+ list_insert_head(list, &timer->link);
+}
+
+int timer_mod(timer_t *timer, int expires)
+{
+
+ timer->expires = expires;
+ int ret = __timer_del(timer);
+ __timer_add(timer);
+ timer_next_expiry = MIN(timer_next_expiry, timer->expires);
+
+ return ret;
+}
+
+int timer_pending(timer_t *timer)
+{
+ int ret = list_link_is_linked(&timer->link);
+ return ret;
+}
+
+int timer_del_sync(timer_t *timer)
+{
+ /* Not great performance wise... */
+ while (timer_running == timer)
+ {
+ sched_yield();
+ }
+
+ int ret = __timer_del(timer);
+
+ return ret;
+}
+
+/* Note: using a linked-list rather than some priority is terribly inefficient
+ * Also this implementation is just bad. Sorry.
+ */
+int ready = 0;
+void __timers_fire()
+{
+ if (curthr && !preemption_enabled())
+ {
+ return;
+ }
+
+ timers_firing = 1;
+
+ //dbg(DBG_PRINT, "next expiry: %d\n", timer_next_expiry);
+ if (jiffies < timer_next_expiry)
+ {
+ timers_firing = 0;
+ return;
+ }
+
+ uint64_t min_expiry = 0;
+
+ list_iterate(&timers_primary, timer, timer_t, link)
+ {
+ if (jiffies >= timer->expires)
+ {
+ list_remove(&timer->link);
+ timer_running = timer;
+ timer->function(timer->data);
+ timer_running = NULL;
+ }
+ else
+ {
+ min_expiry = MIN(min_expiry, timer->expires);
+ }
+ }
+
+ /* migrate from the backup list to the primary list */
+ list_iterate(&timers_secondary, timer, timer_t, link)
+ {
+ min_expiry = MIN(min_expiry, timer->expires);
+ list_remove(&timer->link);
+ list_insert_head(&timers_primary, &timer->link);
+ }
+
+ timer_next_expiry = min_expiry;
+ timers_firing = 0;
+}