Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel'
[palacios-OLD.git] / kitten / kernel / timer.c
diff --git a/kitten/kernel/timer.c b/kitten/kernel/timer.c
new file mode 100644 (file)
index 0000000..bf4d304
--- /dev/null
@@ -0,0 +1,129 @@
+#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);
+}