XEN-ARM定时器管理算法简要总结

/*

XEN-ARM的定时器优先队列管理算法采用的是最小堆。关于最小堆的知识,请参考

《算法导论》第二版第6章堆。

下面是简要流程。欢迎讨论

*/

/*初始化定时器*/

void __init timer_init(void)

{

static struct timer *dummy_heap;

int i;

open_softirq(TIMER_SOFTIRQ, timer_softirq_action);

/*

* All CPUs initially share an empty dummy heap. Only those CPUs that

* are brought online will be dynamically allocated their own heap.

*/

SET_HEAP_SIZE(&dummy_heap, 0);

SET_HEAP_LIMIT(&dummy_heap, 0);

for ( i = 0; i < NR_CPUS; i++ )

{

spin_lock_init(&timers[i].lock);

timers[i].heap = &dummy_heap;

}

}

/*

当软中断发生时,函数执行

在定时器优先队列中查找满足expires的定时器,从队列中摘除,然后执行之

*/

static void timer_softirq_action(void)

{

int           cpu = smp_processor_id();

struct timer *t, **heap;

s_time_t      now;

void        (*fn)(void *);

void         *data;

DPRINTK(5, "%s:%d\n", __FUNCTION__, __LINE__);

spin_lock_irq(&timers[cpu].lock);

do {

heap = timers[cpu].heap;

now  = NOW();

//以此取定时器优先队列中最优先定时器

//然后执行其过程

while ( (GET_HEAP_SIZE(heap) != 0) && ( (t = heap[1])->expires < (now + (s_time_t)TIMER_SLOP) ) )

{

remove_entry(heap, t);

timers[cpu].running = t;

fn   = t->function;

data = t->data;

//printk("fn:%x", fn);

spin_unlock_irq(&timers[cpu].lock);

//执行定时器操作

(*fn)(data);

DPRINTK(5, "%s:%d\n", __FUNCTION__, __LINE__);

spin_lock_irq(&timers[cpu].lock);

/* Heap may have grown while the lock was released. */

heap = timers[cpu].heap;

}

timers[cpu].running = NULL;

}while ( !reprogram_timer(GET_HEAP_SIZE(heap) ? heap[1]->expires : 0) );//如果有定时器,小于now(),那么就继续loop

DPRINTK(5, "%s:%d\n", __FUNCTION__, __LINE__);

spin_unlock_irq(&timers[cpu].lock);

}

/*

Delete @t from @heap. Return TRUE if new top of heap.

摘除定时器会用到down_heap 和 up_heap来调整最小堆。

*/

static int remove_entry(struct timer **heap, struct timer *t)

{

int sz = GET_HEAP_SIZE(heap);

int pos = t->heap_offset;

//t->heap_offset

t->heap_offset = 0;

//--如果删除的元素是最后的,那么就不需要做调整啦~~,仅仅是heap-size减一就可以咯

if ( unlikely(pos == sz) )

{

SET_HEAP_SIZE(heap, sz-1);

goto out;

}

//--把最后一个元素填上来,这是最小堆的精髓!

heap[pos] = heap[sz];

heap[pos]->heap_offset = pos;

SET_HEAP_SIZE(heap, --sz);

//如果是中间节点,并且小于父母的,那么就需要up_heap

//如果是根结点,或者暂时不小于父母的,那么就是down_heap

if ( (pos > 1) && (heap[pos]->expires < heap[pos>>1]->expires) )

up_heap(heap, pos);

else

down_heap(heap, pos);

out:

return (pos == 1);

}

/* Float element @pos up @heap. */

static void up_heap(struct timer **heap, int pos)

{

struct timer *t = heap[pos];

//根节点的expires最小--

//具体算法是,自底向上,循环保证最小堆的性质

while ( (pos > 1) && (t->expires < heap[pos>>1]->expires) )

{

heap[pos] = heap[pos>>1];

heap[pos]->heap_offset = pos;

pos >>= 1;

}

heap[pos] = t;

t->heap_offset = pos;

}

/* Sink down element @pos of @heap. */

static void down_heap(struct timer **heap, int pos)

{

//自顶向下插入一个元素时的方法

int sz = GET_HEAP_SIZE(heap), nxt;

struct timer *t = heap[pos];

while ( (nxt = (pos << 1)) <= sz )

{

//nxt是left-subtree nxt+1是right-subtree

if ( ((nxt+1) <= sz) && (heap[nxt+1]->expires < heap[nxt]->expires) )

nxt++;//--better than the book of < the introduction of algorithm >

if ( heap[nxt]->expires > t->expires )//如果保证了最小堆,就是找到了~~

break;

heap[pos] = heap[nxt];

heap[pos]->heap_offset = pos;

pos = nxt;

}

heap[pos] = t;

t->heap_offset = pos;

}

/*下面附上相关的一些函数*/

/****************************************************************************

* HEAP OPERATIONS.

*/

#define GET_HEAP_SIZE(_h)     ((int)(((u16 *)(_h))[0]))

#define SET_HEAP_SIZE(_h,_v)  (((u16 *)(_h))[0] = (u16)(_v))

#define GET_HEAP_LIMIT(_h)    ((int)(((u16 *)(_h))[1]))

#define SET_HEAP_LIMIT(_h,_v) (((u16 *)(_h))[1] = (u16)(_v))

/****************************************************************************

* TIMER OPERATIONS.

*/

static inline void __add_timer(struct timer *timer)

{

static int tmp_count;

printk("__add_timer:%d\n",tmp_count++);

int cpu = timer->cpu;

if ( add_entry(&timers[cpu].heap, timer) ){//如果是在最高优先级,那么就需要调用一下softirq

cpu_raise_softirq(cpu, TIMER_SOFTIRQ);

}

}

static inline void __stop_timer(struct timer *timer)

{

int cpu = timer->cpu;

if ( remove_entry(timers[cpu].heap, timer) )//如果删除了最优先的timer,才需要

cpu_raise_softirq(cpu, TIMER_SOFTIRQ);

}

static inline void timer_lock(struct timer *timer)

void set_timer(struct timer *timer, s_time_t expires)

{

unsigned long flags;

timer_lock_irqsave(timer, flags);

//现检测timer是否在队列中

if ( active_timer(timer) )

__stop_timer(timer);//从队列中除去先

timer->expires = expires;//更新expires

if ( likely(!timer->killed) )

__add_timer(timer);

timer_unlock_irqrestore(timer, flags);

}

void stop_timer(struct timer *timer)

{

unsigned long flags;

timer_lock_irqsave(timer, flags);

if ( active_timer(timer) )

__stop_timer(timer);

timer_unlock_irqrestore(timer, flags);

}

int reprogram_timer(s_time_t timeout)

{

s_time_t    now;

s_time_t    expire;

if ( timeout == 0 )

return 1;

now = NOW();

expire = timeout - now; /* value from now */

if ( expire <= 0 )

return 0;

return 1;

}

评论

  1. 能否将xen-arm的旧版本(2008年)的发给我,我只能在网上搜到2011年的。我的邮箱:hust_gaoyi@163.com,谢谢!

    回复删除

发表评论

此博客中的热门博文

Linux/ARM Page Table Entry 属性设置分析

提交了30次才AC ---【附】POJ 2488解题报告

笔记