禁止抢占

   由于内核是抢占性的,内核中的进程在任何时刻都可能停下来以便另一个具有更高优先级的进程运行。这意味着一个任务与被抢占的任务可能会在同一个临界区内运行。为了避免这样的情况,内核抢占代码使用自旋锁作为非抢占区域的标记。如果一个自旋锁被持有,内核便不能进行抢占。因为内核抢占和SMP面对相同的并发问题,并且内核已经是SMP安全的,因此,这种简单的变化使得内核也是抢占安全的。

  实际中,某些情况并不需要自旋锁,但是仍然需要关闭内核抢占。出现得最频繁的情况就是每个处理器上的数据。如果数据对每个处理器是唯一的,那么这样的数据可能就不需要使用锁来保护,因为数据只能被一个处理器访问。如果自旋锁没有被持有,内核有是抢占式的,那么一个新调度的任务就可能访问同一个变量。为了解决这个问题,可以通过preempt_disable()禁止内核抢占。这是一个可以嵌套调用的函数,可以调用任意次。每次调用都必须有一个相应的preempt_enable()调用。当最后一次preempt_enable()被调用后,内核抢占才重新启用。

 

  1. /*
  2.  * include/linux/preempt.h - macros for accessing and manipulating
  3.  * preempt_count (used for kernel preemption, interrupt count, etc.)
  4.  */
  5. #ifdef CONFIG_PREEMPT
  6. asmlinkage void preempt_schedule(void);
  7. #define preempt_disable() /
  8. do { /
  9.     inc_preempt_count(); /
  10.     barrier(); /
  11. while (0)
  12. #define preempt_enable_no_resched() /
  13. do { /
  14.     barrier(); /
  15.     dec_preempt_count(); /
  16. while (0)
  17. #define preempt_check_resched() /
  18. do { /
  19.     if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) /
  20.         preempt_schedule(); /
  21. while (0)
  22. #define preempt_enable() /
  23. do { /
  24.     preempt_enable_no_resched(); /
  25.     barrier(); /
  26.     preempt_check_resched(); /
  27. while (0)
  28. #else
  29. #define preempt_disable()       do { } while (0)
  30. #define preempt_enable_no_resched() do { } while (0)
  31. #define preempt_enable()        do { } while (0)
  32. #define preempt_check_resched()     do { } while (0)
  33. #endif

  抢占计数存放着被持有锁的数量和preempt_disable()的调度次数,如果计数是0,那么内核可以进行抢占,如果为1或更大的值,那么内核就不会进行抢占。这个计数非常有用,它是一种对原子操作和睡眠很有效的调试方法。函数preempt_count()返回这个值。

  1. /*
  2.  * include/linux/preempt.h - macros for accessing and manipulating
  3.  * preempt_count (used for kernel preemption, interrupt count, etc.)
  4.  */
  5. #ifdef CONFIG_DEBUG_PREEMPT
  6.   extern void fastcall add_preempt_count(int val);
  7.   extern void fastcall sub_preempt_count(int val);
  8. #else
  9. # define add_preempt_count(val) do { preempt_count() += (val); } while (0)
  10. # define sub_preempt_count(val) do { preempt_count() -= (val); } while (0)
  11. #endif
  12. #define inc_preempt_count() add_preempt_count(1)
  13. #define dec_preempt_count() sub_preempt_count(1)
  14. #define preempt_count() (current_thread_info()->preempt_count)
  1. 在<Thread_info.h(include/asm-i386)>中
  2. struct thread_info {
  3.     struct task_struct  *task;      /* main task structure */
  4.     struct exec_domain  *exec_domain;   /* execution domain */
  5.     unsigned long       flags;      /* low level flags */
  6.     unsigned long       status;     /* thread-synchronous flags */
  7.     __u32           cpu;        /* current CPU */
  8.     int         preempt_count;  /* 0 => preemptable, <0 => BUG */
  9.     mm_segment_t        addr_limit; /* thread address space:
  10.                            0-0xBFFFFFFF for user-thead
  11.                            0-0xFFFFFFFF for kernel-thread
  12.                         */
  13.     void            *sysenter_return;
  14.     struct restart_block    restart_block;
  15.     unsigned long           previous_esp;   /* ESP of the previous stack in case
  16.                            of nested (IRQ) stacks
  17.                         */
  18.     __u8            supervisor_stack[0];

搞定!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值