tasklet的实现【2】

 2.调度tasklet

     已触发的tasklet存放在两个单处理器结构中:tasklet_vec(普通tasklet)和tasklet_hi_vec(高优先级的tasklet)。这两个数据结构都是有tasklet_struct结构体构成的链表,链表中的每个tasklet_struct代表一个不同的tasklet。

     tasklet由tasklet_schedule()和tasklet_hi_schedule()函数进行调度,它们接受一个指向tasklet_struct结构的指针作为参数。

  1. 在<Interrupt.h(include/linux)>中
  2. static inline void tasklet_schedule(struct tasklet_struct *t)
  3. {
  4.     if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))/*检查tasklet的状态是否为TASKLET_STATE_SCHED,如果是,说明tasklet已经被调度过了(有可能是一个tasklet已经被调度过但还没有来得及执行,而该tasklet又被唤起了一次),函数立即返回。*/
  5.         __tasklet_schedule(t);
  6. }
  7. static inline void tasklet_hi_schedule(struct tasklet_struct *t)
  8. {
  9.     if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
  10.         __tasklet_hi_schedule(t);
  11. }
  12. 在<Softirq.c(Kernel)>中
  13. void fastcall __tasklet_schedule(struct tasklet_struct *t)
  14. {
  15.     unsigned long flags;
  16.     local_irq_save(flags);//保存中断状态,然后禁止本地中断。
  17.     /*把需要调度的tasklet加到每个处理器一个的tasklet_vec链表的表头上*/
  18.     t->next = __get_cpu_var(tasklet_vec).list;
  19.     __get_cpu_var(tasklet_vec).list = t;
  20.    /*唤起TASKLET_SOFTIRQ软中断,下次调用do_softirq()时就会执行该tasklet*/
  21.     raise_softirq_irqoff(TASKLET_SOFTIRQ);
  22.     local_irq_restore(flags);/*恢复中断到原状态并返回*/
  23. }
  24. void fastcall __tasklet_hi_schedule(struct tasklet_struct *t)
  25. {
  26.     unsigned long flags;
  27.     local_irq_save(flags);
  28.     t->next = __get_cpu_var(tasklet_hi_vec).list;
  29.     __get_cpu_var(tasklet_hi_vec).list = t;
  30.     raise_softirq_irqoff(HI_SOFTIRQ);
  31.     local_irq_restore(flags);
  32. }
  33. 在<Bitops.h(include/asm-i386)>
  34. /**
  35.  * __test_and_set_bit - Set a bit and return its old value
  36.  * @nr: Bit to set
  37.  * @addr: Address to count from
  38.  *
  39.  * This operation is non-atomic and can be reordered.  
  40.  * If two examples of this operation race, one can appear to succeed
  41.  * but actually fail.  You must protect multiple accesses with a lock.
  42.  */
  43. static inline int __test_and_set_bit(int nr, volatile unsigned long * addr)
  44. {
  45.     int oldbit;
  46.     __asm__(
  47.         "btsl %2,%1/n/tsbbl %0,%0"
  48.         :"=r" (oldbit),"+m" (ADDR)
  49.         :"Ir" (nr));
  50.     return oldbit;
  51. }
  1. /**
  2.  * test_and_set_bit - Set a bit and return its old value
  3.  * @nr: Bit to set
  4.  * @addr: Address to count from
  5.  *
  6.  * This operation is atomic and cannot be reordered.  
  7.  * It may be reordered on other architectures than x86.
  8.  * It also implies a memory barrier.
  9.  */
  10. static inline int test_and_set_bit(int nr, volatile unsigned long * addr)
  11. {
  12.     int oldbit;
  13.     __asm__ __volatile__( LOCK_PREFIX
  14.         "btsl %2,%1/n/tsbbl %0,%0"
  15.         :"=r" (oldbit),"+m" (ADDR)
  16.         :"Ir" (nr) : "memory");
  17.     return oldbit;
  18. }   

 由于大部分tasklet和软中断都是在中断处理程序中被设置成待处理状态,所以最近一个中断返回的时候看起来就是执行do_softirq()的最佳时期。因为TASKLET_SOFTIRQ和HI_SOFTIRQ已经被触发了,所以do_softirq()会执行相应的软中断处理程序。tasklet_action()和tasklet_hi_action(),就是tasklet处理的核心。

  1. 在<Softirq.c(kernel)>中
  2. static void tasklet_action(struct softirq_action *a)
  3. {
  4.     struct tasklet_struct *list;
  5.     local_irq_disable();/*禁止中断*/
  6.     list = __get_cpu_var(tasklet_vec).list;
  7.     __get_cpu_var(tasklet_vec).list = NULL;/*将当前处理器上的该链表设置为NULL,达到清空的效果*/
  8.     local_irq_enable();/*恢复响应中断*/
  9.     /*循环遍历获得链表上的每一个待处理的tasklet*/
  10.     while (list) {
  11.         struct tasklet_struct *t = list;
  12.         list = list->next;
  13. /* 如果是多处理器系统,通过检查TASKLET_STATE_RUN状态标志来判断这个tasklet是否正在其他处理器上运行。如果它正在运行,那么现在就不要执行,跳到下一个待处理的tasklet去 。如果当前这个tasklet没有执行,将其状态标志设置为TASKLET_STATE_RUN,这样别的处理器就不会再去执行它了,它就执行tasklet的处理程序,即if{}内的语句。*/
  14.         if (tasklet_trylock(t)) {
  15. /*检查count值是否为0,确保tasklet没有被禁止。如果tasklet被禁止了则跳到下一个挂起的tasklet去。*/
  16.             if (!atomic_read(&t->count)) {
  17.                 if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
  18.                     BUG();
  19.                 t->func(t->data);/*执行tasklet的处理程序*/
  20.                 tasklet_unlock(t);
  21.                 continue;
  22.             }
  23.             tasklet_unlock(t);
  24.         }
  25.     /*如果TASKLET_STATE_RUN标志被设置,同一类型的tasklet已经在其他CPU上运行,因此该函数将该tasklet描述符重新插入tasklet_vec链表中,这样,直到其他CPU上没有同一类型的tasklet运行该tasklet才执行。*/
  26.         local_irq_disable();
  27.         t->next = __get_cpu_var(tasklet_vec).list;
  28.         __get_cpu_var(tasklet_vec).list = t;
  29.         __raise_softirq_irqoff(TASKLET_SOFTIRQ);/*重新激活TASKLET_SOFTIRQ*/
  30.         local_irq_enable();
  31.     }
  32. }
  33. static void tasklet_hi_action(struct softirq_action *a)
  34. {
  35.     struct tasklet_struct *list;
  36.     local_irq_disable();
  37.     list = __get_cpu_var(tasklet_hi_vec).list;
  38.     __get_cpu_var(tasklet_hi_vec).list = NULL;
  39.     local_irq_enable();
  40.     while (list) {
  41.         struct tasklet_struct *t = list;
  42.         list = list->next;
  43.         if (tasklet_trylock(t)) {
  44.             if (!atomic_read(&t->count)) {
  45.                 if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
  46.                     BUG();
  47.                 t->func(t->data);
  48.                 tasklet_unlock(t);
  49.                 continue;
  50.             }
  51.             tasklet_unlock(t);
  52.         }
  53.         local_irq_disable();
  54.         t->next = __get_cpu_var(tasklet_hi_vec).list;
  55.         __get_cpu_var(tasklet_hi_vec).list = t;
  56.         __raise_softirq_irqoff(HI_SOFTIRQ);
  57.         local_irq_enable();
  58.     }
  59. }
  1. 在<Interrupt.h(includelinux)>中
  2. enum
  3. {
  4.     TASKLET_STATE_SCHED,    /* Tasklet is scheduled for execution */
  5.     TASKLET_STATE_RUN   /* Tasklet is running (SMP only) */
  6. };
  7. #ifdef CONFIG_SMP
  8. static inline int tasklet_trylock(struct tasklet_struct *t)
  9. {
  10.     return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);
  11. }
  12. static inline void tasklet_unlock(struct tasklet_struct *t)
  13. {
  14.     smp_mb__before_clear_bit(); 
  15.     clear_bit(TASKLET_STATE_RUN, &(t)->state);
  16. }
  17. static inline void tasklet_unlock_wait(struct tasklet_struct *t)
  18. {
  19.     while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); }
  20. }
  21. #else
  22. #define tasklet_trylock(t) 1
  23. #define tasklet_unlock_wait(t) do { } while (0)
  24. #define tasklet_unlock(t) do { } while (0)
  25. #endif
  1. 在<Bitops.h(inclide/asm-i386)>
  2. /**
  3.  * clear_bit - Clears a bit in memory
  4.  * @nr: Bit to clear
  5.  * @addr: Address to start counting from
  6.  *
  7.  * clear_bit() is atomic and may not be reordered.  However, it does
  8.  * not contain a memory barrier, so if it is used for locking purposes,
  9.  * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
  10.  * in order to ensure changes are visible on other processors.
  11.  */
  12. static inline void clear_bit(int nr, volatile unsigned long * addr)
  13. {
  14.     __asm__ __volatile__( LOCK_PREFIX
  15.         "btrl %1,%0"
  16.         :"+m" (ADDR)
  17.         :"Ir" (nr));
  18. }
  19. static inline void __clear_bit(int nr, volatile unsigned long * addr)
  20. {
  21.     __asm__ __volatile__(
  22.         "btrl %1,%0"
  23.         :"+m" (ADDR)
  24.         :"Ir" (nr));
  25. }
  26. #define test_bit(nr,addr) /
  27. (__builtin_constant_p(nr) ? /
  28.  constant_test_bit((nr),(addr)) : /
  29.  variable_test_bit((nr),(addr)))
  30. #define smp_mb__before_clear_bit()  barrier() 
  31. #define smp_mb__after_clear_bit()   barrier()
  1. #if 0 /* Fool kernel-doc since it doesn't do macros yet */
  2. /**
  3.  * test_bit - Determine whether a bit is set
  4.  * @nr: bit number to test
  5.  * @addr: Address to start counting from
  6.  */
  7. static int test_bit(int nr, const volatile void * addr);
  8. #endif
  9. static __always_inline int constant_test_bit(int nr, const volatile unsigned long *addr)
  10. {
  11.     return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0;
  12. }
  13. static inline int variable_test_bit(int nr, const volatile unsigned long * addr)
  14. {
  15.     int oldbit;
  16.     __asm__ __volatile__(
  17.         "btl %2,%1/n/tsbbl %0,%0"
  18.         :"=r" (oldbit)
  19.         :"m" (ADDR),"Ir" (nr));
  20.     return oldbit;
  21. }
  22. #define test_bit(nr,addr) /
  23. (__builtin_constant_p(nr) ? /
  24.  constant_test_bit((nr),(addr)) : /
  25.  variable_test_bit((nr),(addr)))
  1. 在<Bitops.h>中
  2. /**
  3.  * test_and_clear_bit - Clear a bit and return its old value
  4.  * @nr: Bit to clear
  5.  * @addr: Address to count from
  6.  *
  7.  * This operation is atomic and cannot be reordered.
  8.  * It can be reorderdered on other architectures other than x86.
  9.  * It also implies a memory barrier.
  10.  */
  11. static inline int test_and_clear_bit(int nr, volatile unsigned long * addr)
  12. {
  13.     int oldbit;
  14.     __asm__ __volatile__( LOCK_PREFIX
  15.         "btrl %2,%1/n/tsbbl %0,%0"
  16.         :"=r" (oldbit),"+m" (ADDR)
  17.         :"Ir" (nr) : "memory");
  18.     return oldbit;
  19. }
  20. 在<Atomic.h(include/asm-i386)>中
  21. /**
  22.  * atomic_read - read atomic variable
  23.  * @v: pointer of type atomic_t
  24.  * 
  25.  * Atomically reads the value of @v.
  26.  */ 
  27. #define atomic_read(v)      ((v)->counter)
  1. 在<Bug.h(include/asm-i386)>
  2. /*
  3.  * Tell the user there is some problem.
  4.  * The offending file and line are encoded encoded in the __bug_table section.
  5.  */
  6. #ifdef CONFIG_BUG
  7. #define HAVE_ARCH_BUG
  8. #ifdef CONFIG_DEBUG_BUGVERBOSE
  9. #define BUG()                               /
  10.     do {                                /
  11.         asm volatile("1:/tud2/n"                /
  12.                  ".pushsection __bug_table,/"a/"/n"     /
  13.                  "2:/t.long 1b, %c0/n"          /
  14.                  "/t.word %c1, 0/n"             /
  15.                  "/t.org 2b+%c2/n"              /
  16.                  ".popsection"              /
  17.                  : : "i" (__FILE__), "i" (__LINE__),    /
  18.                  "i" (sizeof(struct bug_entry)));       /
  19.         for(;;) ;                       /
  20.     } while(0)
  21. #else
  22. #define BUG()                               /
  23.     do {                                /
  24.         asm volatile("ud2");                    /
  25.         for(;;) ;                       /
  26.     } while(0)
  27. #endif
  28. #endif

呵呵,总算把代码帖完了:P

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值