1 /******************************************************************************
2 * timer.c
3 *
4 * Copyright (c) 2002-2003 Rolf Neugebauer
5 * Copyright (c) 2002-2005 K A Fraser
6 */
7
8 #include <xen/init.h>
9 #include <xen/types.h>
10 #include <xen/errno.h>
11 #include <xen/sched.h>
12 #include <xen/lib.h>
13 #include <xen/smp.h>
14 #include <xen/perfc.h>
15 #include <xen/time.h>
16 #include <xen/softirq.h>
17 #include <xen/timer.h>
18 #include <xen/keyhandler.h>
19 #include <xen/percpu.h>
20 #include <xen/cpu.h>
21 #include <xen/rcupdate.h>
22 #include <xen/symbols.h>
23 #include <asm/system.h>
24 #include <asm/desc.h>
25 #include <asm/atomic.h>
26
27 /* We program the time hardware this far behind the closest deadline. */
28 static unsigned int timer_slop __read_mostly = 50000; /* 50 us */
29 integer_param("timer_slop", timer_slop);
30
31 struct timers {
32 spinlock_t lock;
33 struct timer **heap;
34 struct timer *list;
35 struct timer *running;
36 struct list_head inactive;
37 } __cacheline_aligned;
38
39 static DEFINE_PER_CPU(struct timers, timers);
40
41 /* Protects lock-free access to per-timer cpu field against cpu offlining. */
42 static DEFINE_RCU_READ_LOCK(timer_cpu_read_lock);
43
44 DEFINE_PER_CPU(s_time_t, timer_deadline);
45
46 /****************************************************************************
47 * HEAP OPERATIONS.
48 */
49
50 #define GET_HEAP_SIZE(_h) ((int)(((u16 *)(_h))[0]))
51 #define SET_HEAP_SIZE(_h,_v) (((u16 *)(_h))[0] = (u16)(_v))
52
53 #define GET_HEAP_LIMIT(_h) ((int)(((u16 *)(_h))[1]))
54 #define SET_HEAP_LIMIT(_h,_v) (((u16 *)(_h))[1] = (u16)(_v))
55
56 /* Sink down element @pos of @heap. */
down_heap(struct timer ** heap,int pos)57 static void down_heap(struct timer **heap, int pos)
58 {
59 int sz = GET_HEAP_SIZE(heap), nxt;
60 struct timer *t = heap[pos];
61
62 while ( (nxt = (pos << 1)) <= sz )
63 {
64 if ( ((nxt+1) <= sz) && (heap[nxt+1]->expires < heap[nxt]->expires) )
65 nxt++;
66 if ( heap[nxt]->expires > t->expires )
67 break;
68 heap[pos] = heap[nxt];
69 heap[pos]->heap_offset = pos;
70 pos = nxt;
71 }
72
73 heap[pos] = t;
74 t->heap_offset = pos;
75 }
76
77 /* Float element @pos up @heap. */
up_heap(struct timer ** heap,int pos)78 static void up_heap(struct timer **heap, int pos)
79 {
80 struct timer *t = heap[pos];
81
82 while ( (pos > 1) && (t->expires < heap[pos>>1]->expires) )
83 {
84 heap[pos] = heap[pos>>1];
85 heap[pos]->heap_offset = pos;
86 pos >>= 1;
87 }
88
89 heap[pos] = t;
90 t->heap_offset = pos;
91 }
92
93
94 /* Delete @t from @heap. Return TRUE if new top of heap. */
remove_from_heap(struct timer ** heap,struct timer * t)95 static int remove_from_heap(struct timer **heap, struct timer *t)
96 {
97 int sz = GET_HEAP_SIZE(heap);
98 int pos = t->heap_offset;
99
100 if ( unlikely(pos == sz) )
101 {
102 SET_HEAP_SIZE(heap, sz-1);
103 goto out;
104 }
105
106 heap[pos] = heap[sz];
107 heap[pos]->heap_offset = pos;
108
109 SET_HEAP_SIZE(heap, --sz);
110
111 if ( (pos > 1) && (heap[pos]->expires < heap[pos>>1]->expires) )
112 up_heap(heap, pos);
113 else
114 down_heap(heap, pos);
115
116 out:
117 return (pos == 1);
118 }
119
120
121 /* Add new entry @t to @heap. Return TRUE if new top of heap. */
add_to_heap(struct timer ** heap,struct timer * t)122 static int add_to_heap(struct timer **heap, struct timer *t)
123 {
124 int sz = GET_HEAP_SIZE(heap);
125
126 /* Fail if the heap is full. */
127 if ( unlikely(sz == GET_HEAP_LIMIT(heap)) )
128 return 0;
129
130 SET_HEAP_SIZE(heap, ++sz);
131 heap[sz] = t;
132 t->heap_offset = sz;
133 up_heap(heap, sz);
134
135 return (t->heap_offset == 1);
136 }
137
138
139 /****************************************************************************
140 * LINKED LIST OPERATIONS.
141 */
142
remove_from_list(struct timer ** pprev,struct timer * t)143 static int remove_from_list(struct timer **pprev, struct timer *t)
144 {
145 struct timer *curr, **_pprev = pprev;
146
147 while ( (curr = *_pprev) != t )
148 _pprev = &curr->list_next;
149
150 *_pprev = t->list_next;
151
152 return (_pprev == pprev);
153 }
154
add_to_list(struct timer ** pprev,struct timer * t)155 static int add_to_list(struct timer **pprev, struct timer *t)
156 {
157 struct timer *curr, **_pprev = pprev;
158
159 while ( ((curr = *_pprev) != NULL) && (curr->expires <= t->expires) )
160 _pprev = &curr->list_next;
161
162 t->list_next = curr;
163 *_pprev = t;
164
165 return (_pprev == pprev);
166 }
167
168
169 /****************************************************************************
170 * TIMER OPERATIONS.
171 */
172
remove_entry(struct timer * t)173 static int remove_entry(struct timer *t)
174 {
175 struct timers *timers = &per_cpu(timers, t->cpu);
176 int rc;
177
178 switch ( t->status )
179 {
180 case TIMER_STATUS_in_heap:
181 rc = remove_from_heap(timers->heap, t);
182 break;
183 case TIMER_STATUS_in_list:
184 rc = remove_from_list(&timers->list, t);
185 break;
186 default:
187 rc = 0;
188 BUG();
189 }
190
191 t->status = TIMER_STATUS_invalid;
192 return rc;
193 }
194
add_entry(struct timer * t)195 static int add_entry(struct timer *t)
196 {
197 struct timers *timers = &per_cpu(timers, t->cpu);
198 int rc;
199
200 ASSERT(t->status == TIMER_STATUS_invalid);
201
202 /* Try to add to heap. t->heap_offset indicates whether we succeed. */
203 t->heap_offset = 0;
204 t->status = TIMER_STATUS_in_heap;
205 rc = add_to_heap(timers->heap, t);
206 if ( t->heap_offset != 0 )
207 return rc;
208
209 /* Fall back to adding to the slower linked list. */
210 t->status = TIMER_STATUS_in_list;
211 return add_to_list(&timers->list, t);
212 }
213
activate_timer(struct timer * timer)214 static inline void activate_timer(struct timer *timer)
215 {
216 ASSERT(timer->status == TIMER_STATUS_inactive);
217 timer->status = TIMER_STATUS_invalid;
218 list_del(&timer->inactive);
219
220 if ( add_entry(timer) )
221 cpu_raise_softirq(timer->cpu, TIMER_SOFTIRQ);
222 }
223
deactivate_timer(struct timer * timer)224 static inline void deactivate_timer(struct timer *timer)
225 {
226 if ( remove_entry(timer) )
227 cpu_raise_softirq(timer->cpu, TIMER_SOFTIRQ);
228
229 timer->status = TIMER_STATUS_inactive;
230 list_add(&timer->inactive, &per_cpu(timers, timer->cpu).inactive);
231 }
232
timer_lock(struct timer * timer)233 static inline bool_t timer_lock(struct timer *timer)
234 {
235 unsigned int cpu;
236
237 rcu_read_lock(&timer_cpu_read_lock);
238
239 for ( ; ; )
240 {
241 cpu = read_atomic(&timer->cpu);
242 if ( unlikely(cpu == TIMER_CPU_status_killed) )
243 {
244 rcu_read_unlock(&timer_cpu_read_lock);
245 return 0;
246 }
247 spin_lock(&per_cpu(timers, cpu).lock);
248 if ( likely(timer->cpu == cpu) )
249 break;
250 spin_unlock(&per_cpu(timers, cpu).lock);
251 }
252
253 rcu_read_unlock(&timer_cpu_read_lock);
254 return 1;
255 }
256
257 #define timer_lock_irqsave(t, flags) ({ \
258 bool_t __x; \
259 local_irq_save(flags); \
260 if ( !(__x = timer_lock(t)) ) \
261 local_irq_restore(flags); \
262 __x; \
263 })
264
timer_unlock(struct timer * timer)265 static inline void timer_unlock(struct timer *timer)
266 {
267 spin_unlock(&per_cpu(timers, timer->cpu).lock);
268 }
269
270 #define timer_unlock_irqrestore(t, flags) ({ \
271 timer_unlock(t); \
272 local_irq_restore(flags); \
273 })
274
275
active_timer(struct timer * timer)276 static bool_t active_timer(struct timer *timer)
277 {
278 ASSERT(timer->status >= TIMER_STATUS_inactive);
279 ASSERT(timer->status <= TIMER_STATUS_in_list);
280 return (timer->status >= TIMER_STATUS_in_heap);
281 }
282
283
init_timer(struct timer * timer,void (* function)(void *),void * data,unsigned int cpu)284 void init_timer(
285 struct timer *timer,
286 void (*function)(void *),
287 void *data,
288 unsigned int cpu)
289 {
290 unsigned long flags;
291 memset(timer, 0, sizeof(*timer));
292 timer->function = function;
293 timer->data = data;
294 write_atomic(&timer->cpu, cpu);
295 timer->status = TIMER_STATUS_inactive;
296 if ( !timer_lock_irqsave(timer, flags) )
297 BUG();
298 list_add(&timer->inactive, &per_cpu(timers, cpu).inactive);
299 timer_unlock_irqrestore(timer, flags);
300 }
301
302
set_timer(struct timer * timer,s_time_t expires)303 void set_timer(struct timer *timer, s_time_t expires)
304 {
305 unsigned long flags;
306
307 if ( !timer_lock_irqsave(timer, flags) )
308 return;
309
310 if ( active_timer(timer) )
311 deactivate_timer(timer);
312
313 timer->expires = expires;
314
315 activate_timer(timer);
316
317 timer_unlock_irqrestore(timer, flags);
318 }
319
320
stop_timer(struct timer * timer)321 void stop_timer(struct timer *timer)
322 {
323 unsigned long flags;
324
325 if ( !timer_lock_irqsave(timer, flags) )
326 return;
327
328 if ( active_timer(timer) )
329 deactivate_timer(timer);
330
331 timer_unlock_irqrestore(timer, flags);
332 }
333
timer_expires_before(struct timer * timer,s_time_t t)334 bool timer_expires_before(struct timer *timer, s_time_t t)
335 {
336 unsigned long flags;
337 bool ret;
338
339 if ( !timer_lock_irqsave(timer, flags) )
340 return false;
341
342 ret = active_timer(timer) && timer->expires <= t;
343
344 timer_unlock_irqrestore(timer, flags);
345
346 return ret;
347 }
348
migrate_timer(struct timer * timer,unsigned int new_cpu)349 void migrate_timer(struct timer *timer, unsigned int new_cpu)
350 {
351 unsigned int old_cpu;
352 bool_t active;
353 unsigned long flags;
354
355 rcu_read_lock(&timer_cpu_read_lock);
356
357 for ( ; ; )
358 {
359 old_cpu = read_atomic(&timer->cpu);
360 if ( (old_cpu == new_cpu) || (old_cpu == TIMER_CPU_status_killed) )
361 {
362 rcu_read_unlock(&timer_cpu_read_lock);
363 return;
364 }
365
366 if ( old_cpu < new_cpu )
367 {
368 spin_lock_irqsave(&per_cpu(timers, old_cpu).lock, flags);
369 spin_lock(&per_cpu(timers, new_cpu).lock);
370 }
371 else
372 {
373 spin_lock_irqsave(&per_cpu(timers, new_cpu).lock, flags);
374 spin_lock(&per_cpu(timers, old_cpu).lock);
375 }
376
377 if ( likely(timer->cpu == old_cpu) )
378 break;
379
380 spin_unlock(&per_cpu(timers, old_cpu).lock);
381 spin_unlock_irqrestore(&per_cpu(timers, new_cpu).lock, flags);
382 }
383
384 rcu_read_unlock(&timer_cpu_read_lock);
385
386 active = active_timer(timer);
387 if ( active )
388 deactivate_timer(timer);
389
390 list_del(&timer->inactive);
391 write_atomic(&timer->cpu, new_cpu);
392 list_add(&timer->inactive, &per_cpu(timers, new_cpu).inactive);
393
394 if ( active )
395 activate_timer(timer);
396
397 spin_unlock(&per_cpu(timers, old_cpu).lock);
398 spin_unlock_irqrestore(&per_cpu(timers, new_cpu).lock, flags);
399 }
400
401
kill_timer(struct timer * timer)402 void kill_timer(struct timer *timer)
403 {
404 unsigned int old_cpu, cpu;
405 unsigned long flags;
406
407 BUG_ON(this_cpu(timers).running == timer);
408
409 if ( !timer_lock_irqsave(timer, flags) )
410 return;
411
412 if ( active_timer(timer) )
413 deactivate_timer(timer);
414
415 list_del(&timer->inactive);
416 timer->status = TIMER_STATUS_killed;
417 old_cpu = timer->cpu;
418 write_atomic(&timer->cpu, TIMER_CPU_status_killed);
419
420 spin_unlock_irqrestore(&per_cpu(timers, old_cpu).lock, flags);
421
422 for_each_online_cpu ( cpu )
423 while ( per_cpu(timers, cpu).running == timer )
424 cpu_relax();
425 }
426
427
execute_timer(struct timers * ts,struct timer * t)428 static void execute_timer(struct timers *ts, struct timer *t)
429 {
430 void (*fn)(void *) = t->function;
431 void *data = t->data;
432
433 t->status = TIMER_STATUS_inactive;
434 list_add(&t->inactive, &ts->inactive);
435
436 ts->running = t;
437 spin_unlock_irq(&ts->lock);
438 (*fn)(data);
439 spin_lock_irq(&ts->lock);
440 ts->running = NULL;
441 }
442
443
timer_softirq_action(void)444 static void timer_softirq_action(void)
445 {
446 struct timer *t, **heap, *next;
447 struct timers *ts;
448 s_time_t now, deadline;
449
450 ts = &this_cpu(timers);
451 heap = ts->heap;
452
453 /* If we overflowed the heap, try to allocate a larger heap. */
454 if ( unlikely(ts->list != NULL) )
455 {
456 /* old_limit == (2^n)-1; new_limit == (2^(n+4))-1 */
457 int old_limit = GET_HEAP_LIMIT(heap);
458 int new_limit = ((old_limit + 1) << 4) - 1;
459 struct timer **newheap = xmalloc_array(struct timer *, new_limit + 1);
460 if ( newheap != NULL )
461 {
462 spin_lock_irq(&ts->lock);
463 memcpy(newheap, heap, (old_limit + 1) * sizeof(*heap));
464 SET_HEAP_LIMIT(newheap, new_limit);
465 ts->heap = newheap;
466 spin_unlock_irq(&ts->lock);
467 if ( old_limit != 0 )
468 xfree(heap);
469 heap = newheap;
470 }
471 }
472
473 spin_lock_irq(&ts->lock);
474
475 now = NOW();
476
477 /* Execute ready heap timers. */
478 while ( (GET_HEAP_SIZE(heap) != 0) &&
479 ((t = heap[1])->expires < now) )
480 {
481 remove_from_heap(heap, t);
482 execute_timer(ts, t);
483 }
484
485 /* Execute ready list timers. */
486 while ( ((t = ts->list) != NULL) && (t->expires < now) )
487 {
488 ts->list = t->list_next;
489 execute_timer(ts, t);
490 }
491
492 /* Try to move timers from linked list to more efficient heap. */
493 next = ts->list;
494 ts->list = NULL;
495 while ( unlikely((t = next) != NULL) )
496 {
497 next = t->list_next;
498 t->status = TIMER_STATUS_invalid;
499 add_entry(t);
500 }
501
502 /* Find earliest deadline from head of linked list and top of heap. */
503 deadline = STIME_MAX;
504 if ( GET_HEAP_SIZE(heap) != 0 )
505 deadline = heap[1]->expires;
506 if ( (ts->list != NULL) && (ts->list->expires < deadline) )
507 deadline = ts->list->expires;
508 now = NOW();
509 this_cpu(timer_deadline) =
510 (deadline == STIME_MAX) ? 0 : MAX(deadline, now + timer_slop);
511
512 if ( !reprogram_timer(this_cpu(timer_deadline)) )
513 raise_softirq(TIMER_SOFTIRQ);
514
515 spin_unlock_irq(&ts->lock);
516 }
517
align_timer(s_time_t firsttick,uint64_t period)518 s_time_t align_timer(s_time_t firsttick, uint64_t period)
519 {
520 if ( !period )
521 return firsttick;
522
523 return firsttick + (period - 1) - ((firsttick - 1) % period);
524 }
525
dump_timer(struct timer * t,s_time_t now)526 static void dump_timer(struct timer *t, s_time_t now)
527 {
528 printk(" ex=%12"PRId64"us timer=%p cb=%ps(%p)\n",
529 (t->expires - now) / 1000, t, t->function, t->data);
530 }
531
dump_timerq(unsigned char key)532 static void dump_timerq(unsigned char key)
533 {
534 struct timer *t;
535 struct timers *ts;
536 unsigned long flags;
537 s_time_t now = NOW();
538 int i, j;
539
540 printk("Dumping timer queues:\n");
541
542 for_each_online_cpu( i )
543 {
544 ts = &per_cpu(timers, i);
545
546 printk("CPU%02d:\n", i);
547 spin_lock_irqsave(&ts->lock, flags);
548 for ( j = 1; j <= GET_HEAP_SIZE(ts->heap); j++ )
549 dump_timer(ts->heap[j], now);
550 for ( t = ts->list, j = 0; t != NULL; t = t->list_next, j++ )
551 dump_timer(t, now);
552 spin_unlock_irqrestore(&ts->lock, flags);
553 }
554 }
555
migrate_timers_from_cpu(unsigned int old_cpu)556 static void migrate_timers_from_cpu(unsigned int old_cpu)
557 {
558 unsigned int new_cpu = cpumask_any(&cpu_online_map);
559 struct timers *old_ts, *new_ts;
560 struct timer *t;
561 bool_t notify = 0;
562
563 ASSERT(!cpu_online(old_cpu) && cpu_online(new_cpu));
564
565 old_ts = &per_cpu(timers, old_cpu);
566 new_ts = &per_cpu(timers, new_cpu);
567
568 if ( old_cpu < new_cpu )
569 {
570 spin_lock_irq(&old_ts->lock);
571 spin_lock(&new_ts->lock);
572 }
573 else
574 {
575 spin_lock_irq(&new_ts->lock);
576 spin_lock(&old_ts->lock);
577 }
578
579 while ( (t = GET_HEAP_SIZE(old_ts->heap)
580 ? old_ts->heap[1] : old_ts->list) != NULL )
581 {
582 remove_entry(t);
583 write_atomic(&t->cpu, new_cpu);
584 notify |= add_entry(t);
585 }
586
587 while ( !list_empty(&old_ts->inactive) )
588 {
589 t = list_entry(old_ts->inactive.next, struct timer, inactive);
590 list_del(&t->inactive);
591 write_atomic(&t->cpu, new_cpu);
592 list_add(&t->inactive, &new_ts->inactive);
593 }
594
595 spin_unlock(&old_ts->lock);
596 spin_unlock_irq(&new_ts->lock);
597
598 if ( notify )
599 cpu_raise_softirq(new_cpu, TIMER_SOFTIRQ);
600 }
601
602 static struct timer *dummy_heap;
603
cpu_callback(struct notifier_block * nfb,unsigned long action,void * hcpu)604 static int cpu_callback(
605 struct notifier_block *nfb, unsigned long action, void *hcpu)
606 {
607 unsigned int cpu = (unsigned long)hcpu;
608 struct timers *ts = &per_cpu(timers, cpu);
609
610 switch ( action )
611 {
612 case CPU_UP_PREPARE:
613 INIT_LIST_HEAD(&ts->inactive);
614 spin_lock_init(&ts->lock);
615 ts->heap = &dummy_heap;
616 break;
617 case CPU_UP_CANCELED:
618 case CPU_DEAD:
619 migrate_timers_from_cpu(cpu);
620 break;
621 default:
622 break;
623 }
624
625 return NOTIFY_DONE;
626 }
627
628 static struct notifier_block cpu_nfb = {
629 .notifier_call = cpu_callback,
630 .priority = 99
631 };
632
timer_init(void)633 void __init timer_init(void)
634 {
635 void *cpu = (void *)(long)smp_processor_id();
636
637 open_softirq(TIMER_SOFTIRQ, timer_softirq_action);
638
639 /*
640 * All CPUs initially share an empty dummy heap. Only those CPUs that
641 * are brought online will be dynamically allocated their own heap.
642 */
643 SET_HEAP_SIZE(&dummy_heap, 0);
644 SET_HEAP_LIMIT(&dummy_heap, 0);
645
646 cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
647 register_cpu_notifier(&cpu_nfb);
648
649 register_keyhandler('a', dump_timerq, "dump timer queues", 1);
650 }
651
652 /*
653 * Local variables:
654 * mode: C
655 * c-file-style: "BSD"
656 * c-basic-offset: 4
657 * tab-width: 4
658 * indent-tabs-mode: nil
659 * End:
660 */
661