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.git] / kitten / kernel / timer.c
1 #include <lwk/kernel.h>
2 #include <lwk/spinlock.h>
3 #include <lwk/percpu.h>
4 #include <lwk/time.h>
5 #include <lwk/timer.h>
6 #include <lwk/sched.h>
7
8 struct timer_queue {
9         spinlock_t       lock;
10         struct list_head timer_list;
11 };
12
13 static DEFINE_PER_CPU(struct timer_queue, timer_queue);
14
15 int
16 timer_subsys_init(void)
17 {
18         id_t cpu;
19         struct timer_queue *timerq;
20
21         for_each_cpu_mask(cpu, cpu_present_map) {
22                 timerq = &per_cpu(timer_queue, cpu);
23                 spin_lock_init(&timerq->lock);
24                 list_head_init(&timerq->timer_list);
25         }
26
27         return 0;
28 }
29
30 void
31 timer_add(struct timer *timer)
32 {
33         struct timer_queue *timerq;
34         struct list_head *pos;
35         unsigned long irqstate;
36
37         timerq = &per_cpu(timer_queue, this_cpu);
38         spin_lock_irqsave(&timerq->lock, irqstate);
39
40         /* Initialize fields we don't expect the caller to set */
41         list_head_init(&timer->link);
42         timer->cpu = this_cpu;
43
44         /* Insert the new timer into the CPU's sorted timer_list */
45         list_for_each(pos, &timerq->timer_list) {
46                 struct timer *cur = list_entry(pos, struct timer, link);
47                 if (cur->expires > timer->expires)
48                         break;
49         }
50         list_add_tail(&timer->link, pos);
51
52         spin_unlock_irqrestore(&timerq->lock, irqstate);
53 }
54
55 void
56 timer_del(struct timer *timer)
57 {
58         struct timer_queue *timerq;
59         unsigned long irqstate;
60
61         timerq = &per_cpu(timer_queue, timer->cpu);
62         spin_lock_irqsave(&timerq->lock, irqstate);
63
64         /* Remove the timer, if it hasn't already expired */
65         if (!list_empty(&timer->link))
66                 list_del(&timer->link);
67
68         spin_unlock_irqrestore(&timerq->lock, irqstate);
69 }
70
71 static void
72 wakeup_task(uintptr_t task)
73 {
74         sched_wakeup_task((struct task_struct *)task, TASKSTATE_INTERRUPTIBLE);
75 }
76
77 /* Returns the time remaining */
78 uint64_t
79 timer_sleep_until(uint64_t when)
80 {
81         struct timer timer;
82         uint64_t now;
83
84         timer.expires  = when;
85         timer.function = &wakeup_task;
86         timer.data     = (uintptr_t)current;
87         timer_add(&timer);
88
89         /* Go to sleep */
90         set_mb(current->state, TASKSTATE_INTERRUPTIBLE);
91         schedule();
92
93         /* Return the time remaining */
94         now = get_time();
95         return (when > now) ? (when - now) : 0;
96 }
97
98 void
99 expire_timers(void)
100 {
101         struct timer_queue *timerq = &per_cpu(timer_queue, this_cpu);
102         struct timer *timer;
103         uint64_t now = get_time();
104         unsigned long irqstate;
105
106         do {
107                 /* Pop the head entry off of the timer list */
108                 spin_lock_irqsave(&timerq->lock, irqstate);
109                 if (!list_empty(&timerq->timer_list)) {
110                         timer = list_entry(timerq->timer_list.next,
111                                            struct timer,
112                                            link);
113                         if (timer->expires <= now) {
114                                 list_del_init(&timer->link);
115                         } else {
116                                 timer = NULL;
117                         }
118                 } else {
119                         timer = NULL;
120                 }
121                 spin_unlock_irqrestore(&timerq->lock, irqstate);
122
123                 /* Execute the timer's callback function.
124                  * Note that we have released the timerq->lock, so the
125                  * callback function is free to call timer_add(). */
126                 if (timer)
127                         (*timer->function)(timer->data);
128         } while (timer);
129 }