--- /dev/null
+#include <lwk/kernel.h>
+#include <lwk/spinlock.h>
+#include <lwk/percpu.h>
+#include <lwk/time.h>
+#include <lwk/timer.h>
+#include <lwk/sched.h>
+
+struct timer_queue {
+ spinlock_t lock;
+ struct list_head timer_list;
+};
+
+static DEFINE_PER_CPU(struct timer_queue, timer_queue);
+
+int
+timer_subsys_init(void)
+{
+ id_t cpu;
+ struct timer_queue *timerq;
+
+ for_each_cpu_mask(cpu, cpu_present_map) {
+ timerq = &per_cpu(timer_queue, cpu);
+ spin_lock_init(&timerq->lock);
+ list_head_init(&timerq->timer_list);
+ }
+
+ return 0;
+}
+
+void
+timer_add(struct timer *timer)
+{
+ struct timer_queue *timerq;
+ struct list_head *pos;
+ unsigned long irqstate;
+
+ timerq = &per_cpu(timer_queue, this_cpu);
+ spin_lock_irqsave(&timerq->lock, irqstate);
+
+ /* Initialize fields we don't expect the caller to set */
+ list_head_init(&timer->link);
+ timer->cpu = this_cpu;
+
+ /* Insert the new timer into the CPU's sorted timer_list */
+ list_for_each(pos, &timerq->timer_list) {
+ struct timer *cur = list_entry(pos, struct timer, link);
+ if (cur->expires > timer->expires)
+ break;
+ }
+ list_add_tail(&timer->link, pos);
+
+ spin_unlock_irqrestore(&timerq->lock, irqstate);
+}
+
+void
+timer_del(struct timer *timer)
+{
+ struct timer_queue *timerq;
+ unsigned long irqstate;
+
+ timerq = &per_cpu(timer_queue, timer->cpu);
+ spin_lock_irqsave(&timerq->lock, irqstate);
+
+ /* Remove the timer, if it hasn't already expired */
+ if (!list_empty(&timer->link))
+ list_del(&timer->link);
+
+ spin_unlock_irqrestore(&timerq->lock, irqstate);
+}
+
+static void
+wakeup_task(uintptr_t task)
+{
+ sched_wakeup_task((struct task_struct *)task, TASKSTATE_INTERRUPTIBLE);
+}
+
+/* Returns the time remaining */
+uint64_t
+timer_sleep_until(uint64_t when)
+{
+ struct timer timer;
+ uint64_t now;
+
+ timer.expires = when;
+ timer.function = &wakeup_task;
+ timer.data = (uintptr_t)current;
+ timer_add(&timer);
+
+ /* Go to sleep */
+ set_mb(current->state, TASKSTATE_INTERRUPTIBLE);
+ schedule();
+
+ /* Return the time remaining */
+ now = get_time();
+ return (when > now) ? (when - now) : 0;
+}
+
+void
+expire_timers(void)
+{
+ struct timer_queue *timerq = &per_cpu(timer_queue, this_cpu);
+ struct timer *timer;
+ uint64_t now = get_time();
+ unsigned long irqstate;
+
+ do {
+ /* Pop the head entry off of the timer list */
+ spin_lock_irqsave(&timerq->lock, irqstate);
+ if (!list_empty(&timerq->timer_list)) {
+ timer = list_entry(timerq->timer_list.next,
+ struct timer,
+ link);
+ if (timer->expires <= now) {
+ list_del_init(&timer->link);
+ } else {
+ timer = NULL;
+ }
+ } else {
+ timer = NULL;
+ }
+ spin_unlock_irqrestore(&timerq->lock, irqstate);
+
+ /* Execute the timer's callback function.
+ * Note that we have released the timerq->lock, so the
+ * callback function is free to call timer_add(). */
+ if (timer)
+ (*timer->function)(timer->data);
+ } while (timer);
+}