📄 2.html
字号:
jmp 9f<p>ALIGN<br>reschedule:<br>pushl $ret_from_sys_call<br> jmp SYMBOL_NAME(schedule) # test<p>另外,一些与时钟中断及bottom half机制有关的数据结构介绍如下:<br>#define HZ 100<br>unsigned long volatile jiffies=0;<br>系统每隔10ms自动把它加1,它是核心系统计时的单位。<br>enum {<br> TIMER_BH = 0,<br> CONSOLE_BH,<br> TQUEUE_BH,<br> DIGI_BH,<br> SERIAL_BH,<br> RISCOM8_BH,<br>SPECIALIX_BH,<br> BAYCOM_BH,<br> NET_BH,<br> IMMEDIATE_BH,<br> KEYBOARD_BH,<br> CYCLADES_BH,<br> CM206_BH<br>};<br>现在只定义了13个bottom half队列,将来可扩充到32个队列。<br>unsigned long intr_count = 0;<br>相当于信号量的作用。只有其等于0,才可以do_bottom_half。<br>int bh_mask_count[32];<br>用来计算bottom half队列被屏蔽的次数。只有某队列的bh_mask_count数为0,才能enable该队列。<br>unsigned long bh_active = 0;<br>bh_active是32位长整数,每一位表示一个bottom half队列,该位置1,表示该队列处于激活状态,随时准备在CPU认为合适的时候执行该队列的服务,置0则相反。<br>unsigned long bh_mask = 0;<br>bh_mask也是32位长整数,每一位对应一个bottom half队列,该位置1,表示该队列可用,并把处理函数的入口地址赋给bh_base,置0则相反。<br>void (*bh_base[32])(void);<br>bottom half服务函数入口地址数组。定时器处理函数拥有最高的优先级,它的地址存放在bh_base[0],总是最先执行它所指向的函数。<p>我们注意到,在IRQ#_interrupt和fast_IRQ#_interrupt中断函数处理返回前,都通过语句jmp ret_from_sys_call,跳到系统调用的返回处(见irq.h),如果bottom half队列不为空,则在那里做类似:<br> if (bh_active & bh_mask) {<br> intr_count = 1;<br> do_bottom_half();<br> intr_count = 0;<br> }(该判断的汇编代码见Entry.S)<br>的判断,调用do_bottom_half()函数。<br>在CPU调度时,通过schedule函数执行上述的判断,再调用do_bottom_half()函数。<br>总而言之,在下列三种时机:<br>CPU调度时<br>系统调用返回前<br>中断处理返回前<br>都会作判断调用do_bottom_half函数。Do_bottom_half函数依次扫描32个队列,找出需要服务的队列,执行服务后把对应该队列的bh_active的相应位置0。由于bh_active标志中TIMER_BH对应的bit为1,因而系统根据服务函数入口地址数组bh_base找到函数timer_bh()的入口地址,并马上执行该函数,在函数timer_bh中,调用函数run_timer_list()和函数run_old_timers()函数,定时执行服务。<p>TVECS结构及其实现<br>有关TVECS结构的一些数据结构定义如下:<p>#define TVN_BITS 6<br>#define TVR_BITS 8<br>#define TVN_SIZE (1 << TVN_BITS)<br>#define TVR_SIZE (1 << TVR_BITS)<br>#define TVN_MASK (TVN_SIZE - 1)<br>#define TVR_MASK (TVR_SIZE - 1)<p>#define SLOW_BUT_DEBUGGING_TIMERS 0<p>struct timer_vec {<br> int index;<br> struct timer_list *vec[TVN_SIZE];<br>};<br>struct timer_vec_root {<br> int index;<br> struct timer_list *vec[TVR_SIZE];<br>};<p>static struct timer_vec tv5 = { 0 };<br>static struct timer_vec tv4 = { 0 };<br>static struct timer_vec tv3 = { 0 };<br>static struct timer_vec tv2 = { 0 };<br>static struct timer_vec_root tv1 = { 0 };<p>static struct timer_vec * const tvecs[] = {<br> (struct timer_vec *)&tv1, &tv2, &tv3, &tv4, &tv5<br>};<br>#define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))<br>static unsigned long timer_jiffies = 0;<p>TVECS结构是一个元素个数为5的数组,分别指向tv1,tv2,tv3,tv4,tv5的地址。其中,tv1是结构timer_vec_root的变量,它有一个index域和有256个元素的指针数组,该数组的每个元素都是一条类型为timer_list的链表。其余四个元素都是结构timer_vec的变量,它们各有一个index域和64个元素的指针数组,这些数组的每个元素也都是一条链表。<p>函数internal_add_timer(struct timer_list *timer)<p>函数代码如下:<br>static inline void internal_add_timer(struct timer_list *timer)<br>{<br> /*<br> * must be cli-ed when calling this<br> */<br> unsigned long expires = timer->expires;<br> unsigned long idx = expires - timer_jiffies;<p> if (idx < TVR_SIZE) {<br> int i = expires & TVR_MASK;<br> insert_timer(timer, tv1.vec, i);<br> } else if (idx < 1 << (TVR_BITS + TVN_BITS)) {<br> int i = (expires >> TVR_BITS) & TVN_MASK;<br> insert_timer(timer, tv2.vec, i);<br> } else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {<br> int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;<br> insert_timer(timer, tv3.vec, i);<br> } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {<br> int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;<br> insert_timer(timer, tv4.vec, i);<br> } else if (expires < timer_jiffies) {<br> /* can happen if you add a timer with expires == jiffies,<br> * or you set a timer to go off in the past<br> */<br> insert_timer(timer, tv1.vec, tv1.index);<br> } else if (idx < 0xffffffffUL) {<br> int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;<br> insert_timer(timer, tv5.vec, i);<br> } else {<br> /* Can only get here on architectures with 64-bit jiffies */<br> timer->next = timer->prev = timer;<br> }<br>}<p> expires<p><br>在调用该函数之前,必须关中。对该函数的说明如下:<br>取出要加进TVECS的timer的激发时间(expires),算出expires与timer_jiffies的差值idx,用来决定该插到哪个队列中去。<br>若idx小于2^8,则取expires的第0位到第7位的值I,把timer加到tv1.vec中第I个链表的第一个表项之前。<br>若idx小于2^14,则取expires的第8位到第13位的值I,把timer加到tv2.vec中第I个链表的第一个表项之前。<br>若idx小于2^20,则取expires的第14位到第19位的值I,把timer加到tv3.vec中第I个链表的第一个表项之前。<br>若idx小于2^26,则取expires的第20位到第25位的值I,把timer加到tv4.vec中第I个链表的第一个表项之前。<br>若expires小于timer_jiffies,即idx小于0,则表明该timer到期,应该把timer放入tv1.vec中tv1.index指定的链表的第一个表项之前。<br>若idx小于2^32,则取expires的第26位到第32位的值I,把timer加到tv5.vec中第I个链表的第一个表项之前。<br>若idx大等于2^32,该情况只有在64位的机器上才有可能发生,在这种情况下,不把timer加入TVECS结构。<p>函数cascade_timers(struct timer_vec *tv)<p>该函数只是把tv->index指定的那条链表上的所有timer调用internal_add_timer()函数进行重新调整,这些timer将放入TVECS结构中比原来位置往前移一级,比如说,tv4上的timer将放到tv3上去,tv2上的timer将放到tv1上。这种前移是由run_timer_list函数里调用cascade_timers函数的时机来保证的。然后把该条链表置空,tv->index加1,若tv->index等于64,则重新置为0。<p>函数run_timer_list()<p>函数代码如下:<br>static inline void run_timer_list(void)<br>{<br>cli();<br>while ((long)(jiffies - timer_jiffies) >= 0) {<br> struct timer_list *timer;<br> if (!tv1.index) {<br> int n = 1;<br> do {<br> cascade_timers(tvecs[n]);<br> } while (tvecs[n]->index == 1 && ++n < NOOF_TVECS);<br> }<br> while ((timer = tv1.vec[tv1.index])) {<br> void (*fn)(unsigned long) = timer->function;<br> unsigned long data = timer->data;<br> detach_timer(timer);<br> timer->next = timer->prev = NULL;<br> sti();<br> fn(data);<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -