preempt_count

Posted Loopers

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了preempt_count相关的知识,希望对你有一定的参考价值。

定义

/*
 * 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 long		flags;		/* low level flags */
	mm_segment_t		addr_limit;	/* address limit */
	struct task_struct	*task;		/* main task structure */
	struct exec_domain	*exec_domain;	/* execution domain */
	struct restart_block	restart_block;
	int			preempt_count;	/* 0 => preemptable, <0 => bug */
	int			cpu;		/* 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_BITS	8
#define SOFTIRQ_BITS	8
#define HARDIRQ_BITS	4
#define NMI_BITS	1
结合上述的示图和代码的定义可知,bit0-7代表的是抢占的次数,最大抢占深度为256次; bit8-15代表的是软中断的次数,最大也是256次; bit16-19表示硬件中断的次数,注释的大概意思是避免中断嵌套,但是也不能防止某些驱动中嵌套使用中断,所以嵌套16层也是最大次数了。bit20代表NMI中断,bit21代表当前抢占是否active。

相关宏定义

linux系统为了方便得出各个字段的值,提供了一系列宏定义如下:
#define PREEMPT_SHIFT	0
#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_BITS	1
#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)
使用上述的宏判断当前进程是否处于原子操作中。



开发者涨薪指南 48位大咖的思考法则、工作方式、逻辑体系

以上是关于preempt_count的主要内容,如果未能解决你的问题,请参考以下文章

LInux中ThreadInfo中的preempt_count字段

linux 2.6调度和抢占 - preempt_count使用

Linux进程管理 实时调度

如何使用GDB提取结构成员的值

JAVA中Iterator的具体作用?

图像处理——优化PCA图像融合文中问题解答及相关优化