preempt_count

来源:互联网 发布:js修改div背景颜色 编辑:程序博客网 时间:2024/04/30 19:58

定义

/* * low level task data that entry.S needs immediate access to. * __switch_to() assumes cpu_context follows immediately after cpu_domain. */struct thread_info {unsigned longflags;/* low level flags */mm_segment_taddr_limit;/* address limit */struct task_struct*task;/* main task structure */struct exec_domain*exec_domain;/* execution domain */struct restart_blockrestart_block;intpreempt_count;/* 0 => preemptable, <0 => bug */intcpu;/* cpu */};
在支持可抢占的系统中,一个进程的therad_info信息定义如上。其中preempt_count代表的是该进程是否可以被抢占,根据注释的说明当peermpt_count等于0的时候当前进程就可以被抢占,当小于0存在bug,当不等于0也就是大于0说明当前进程不可以被抢占。不可抢占的原因很多,比如当前进程在中断上下文中或者使用了锁(spin_lock的过程中会disable掉抢占的)。至于当前是什么原因不能被抢占,就需要看peermpt_count每个字段的含义。

字段含义

先来看如下图所示的各个字段的含义

再来看看代码中关于preempt_count的各个字段的定义:
<linux/include/preempt_mask.h>------------------------------------------/* * We put the hardirq and softirq counter into the preemption * counter. The bitmask has the following meaning: * * - bits 0-7 are the preemption count (max preemption depth: 256) * - bits 8-15 are the softirq count (max # of softirqs: 256) * * The hardirq count could in theory be the same as the number of * interrupts in the system, but we run all interrupt handlers with * interrupts disabled, so we cannot have nesting interrupts. Though * there are a few palaeontologic drivers which reenable interrupts in * the handler, so we need more than one bit here. * * PREEMPT_MASK:0x000000ff * SOFTIRQ_MASK:0x0000ff00 * HARDIRQ_MASK:0x000f0000 *     NMI_MASK:0x00100000 * PREEMPT_ACTIVE:0x00200000 */#define PREEMPT_BITS8#define SOFTIRQ_BITS8#define HARDIRQ_BITS4#define NMI_BITS1
结合上述的示图和代码的定义可知,bit0-7代表的是抢占的次数,最大抢占深度为256次; bit8-15代表的是软中断的次数,最大也是256次; bit16-19表示硬件中断的次数,注释的大概意思是避免中断嵌套,但是也不能防止某些驱动中嵌套使用中断,所以嵌套16层也是最大次数了。bit20代表NMI中断,bit21代表当前抢占是否active。

相关宏定义

linux系统为了方便得出各个字段的值,提供了一系列宏定义如下:
#define PREEMPT_SHIFT0#define SOFTIRQ_SHIFT(PREEMPT_SHIFT + PREEMPT_BITS)                        //0+8=8#define HARDIRQ_SHIFT(SOFTIRQ_SHIFT + SOFTIRQ_BITS)                        //8+8=16#define NMI_SHIFT(HARDIRQ_SHIFT + HARDIRQ_BITS)                        //16+4=20#define __IRQ_MASK(x)((1UL << (x))-1)#define PREEMPT_MASK(__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT)#define SOFTIRQ_MASK(__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)#define HARDIRQ_MASK(__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)#define NMI_MASK(__IRQ_MASK(NMI_BITS)     << NMI_SHIFT)#define PREEMPT_OFFSET(1UL << PREEMPT_SHIFT)                //1<<0#define SOFTIRQ_OFFSET(1UL << SOFTIRQ_SHIFT)                //1<<8#define HARDIRQ_OFFSET(1UL << HARDIRQ_SHIFT)                //1<<16#define NMI_OFFSET(1UL << NMI_SHIFT)                    //1<<20#define SOFTIRQ_DISABLE_OFFSET(2 * SOFTIRQ_OFFSET)           //16#define PREEMPT_ACTIVE_BITS1#define PREEMPT_ACTIVE_SHIFT(NMI_SHIFT + NMI_BITS)#define PREEMPT_ACTIVE(__IRQ_MASK(PREEMPT_ACTIVE_BITS) << PREEMPT_ACTIVE_SHIFT)#define hardirq_count()(preempt_count() & HARDIRQ_MASK)                                     //硬中断count#define softirq_count()(preempt_count() & SOFTIRQ_MASK)                                     //软中断count#define irq_count()(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \| NMI_MASK))                                                  //所有中断=硬+软+NMI
从上述的定义可以得出,如果想知道硬中断的次数就使用hardirq_count, 如果想知道软中断次数就使用softirq_count, 如果想知道所有中断的次数就使用irq_count。

各种上下文

/* * Are we doing bottom half or hardware interrupt processing? * Are we in a softirq context? Interrupt context? * in_softirq - Are we currently processing softirq or have bh disabled? * in_serving_softirq - Are we currently processing softirq? */#define in_irq()(hardirq_count())#define in_softirq()(softirq_count())#define in_interrupt()(irq_count())#define in_serving_softirq()(softirq_count() & SOFTIRQ_OFFSET)
其中in_irq用于判断当前进程是否在硬中断中;  in_softirq用于判断是否当前进程在软件中断或者有别的进程disable了软中断
in_interrupt用于判断当前进程是否在中断中; 而in_serving_softirq用于判断当前进程是否在软件中断中,通过bit8这一位来判断。

#define in_atomic()((preempt_count() & ~PREEMPT_ACTIVE) != 0)
使用上述的宏判断当前进程是否处于原子操作中。



0 0