admin管理员组

文章数量:1794759

preempt

preempt

kernel通过preempt_count变量来判断是否处于中断(soft/hard/nmi)上下文,是否可以抢占,先看示例

#define in_irq()		(hardirq_count())
#define hardirq_count()	(preempt_count() & HARDIRQ_MASK)
static __always_inline int preempt_count(void)
{return current_thread_info()->preempt_count;
}static inline struct thread_info *current_thread_info(void) __attribute_const__;struct thread_info {unsigned long		flags;		/* low level flags */int			preempt_count;	/* 0 => preemptable, <0 => bug */mm_segment_t		addr_limit;	/* address limit */struct task_struct	*task;		/* main task structure */__u32			cpu;		/* cpu */__u32			cpu_domain;	/* cpu domain */struct cpu_context_save	cpu_context;	/* cpu context */__u32			syscall;	/* syscall number */__u8			used_cp[16];	/* thread used copro */unsigned long		tp_value[2];	/* TLS registers */
#ifdef CONFIG_CRUNCHstruct crunch_state	crunchstate;
#endifunion fp_state		fpstate __attribute__((aligned(8)));union vfp_state		vfpstate;
#ifdef CONFIG_ARM_THUMBEEunsigned long		thumbee_state;	/* ThumbEE Handler Base register */
#endif
};

preempt_count具体定义 

linux/preempt.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_NEED_RESCHED:	0x80000000*/
#define PREEMPT_BITS	8
#define SOFTIRQ_BITS	8
#define HARDIRQ_BITS	4
#define NMI_BITS	1#define PREEMPT_SHIFT	0
#define SOFTIRQ_SHIFT	(PREEMPT_SHIFT + PREEMPT_BITS)
#define HARDIRQ_SHIFT	(SOFTIRQ_SHIFT + SOFTIRQ_BITS)
#define NMI_SHIFT	(HARDIRQ_SHIFT + HARDIRQ_BITS)#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)
#define SOFTIRQ_OFFSET	(1UL << SOFTIRQ_SHIFT)
#define HARDIRQ_OFFSET	(1UL << HARDIRQ_SHIFT)
#define NMI_OFFSET	(1UL << NMI_SHIFT)#define SOFTIRQ_DISABLE_OFFSET	(2 * SOFTIRQ_OFFSET)/* We use the MSB mostly because its available */
#define PREEMPT_NEED_RESCHED	0x80000000/* preempt_count() and related functions, depends on PREEMPT_NEED_RESCHED */
#include <asm/preempt.h>#define hardirq_count()	(preempt_count() & HARDIRQ_MASK)
#define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
#define irq_count()	(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \| NMI_MASK))/** Are we doing bottom half or hardware interrupt processing?** in_irq()       - We're in (hard) IRQ context* in_softirq()   - We have BH disabled, or are processing softirqs* in_interrupt() - We're in NMI,IRQ,SoftIRQ context or have BH disabled* in_serving_softirq() - We're in softirq context* in_nmi()       - We're in NMI context* in_task()	  - We're in task context** Note: due to the BH disabled confusion: in_softirq(),in_interrupt() really*       should not be used in new code.*/
#define in_irq()		(hardirq_count())
#define in_softirq()		(softirq_count())
#define in_interrupt()		(irq_count())
#define in_serving_softirq()	(softirq_count() & SOFTIRQ_OFFSET)
#define in_nmi()		(preempt_count() & NMI_MASK)
#define in_task()		(!(preempt_count() & \(NMI_MASK | HARDIRQ_MASK | SOFTIRQ_OFFSET)))
NMI (Non Maskable Interrupt)

硬中断会有如下流程,如PPI和SPI 

int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,bool lookup, struct pt_regs *regs)
{irq_enter();irq = irq_find_mapping(domain, hwirq);generic_handle_irq(irq);irq_exit();}void irq_enter(void){preempt_count_add(HARDIRQ_OFFSET);
}void irq_exit(void)
{preempt_count_sub(HARDIRQ_OFFSET);
}

软中断处理函数

asmlinkage __visible void __softirq_entry __do_softirq(void)
{__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
restart:........................................__local_bh_enable(SOFTIRQ_OFFSET);
}static __always_inline void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
{preempt_count_add(cnt);
}
static void __local_bh_enable(unsigned int cnt)
{preempt_count_sub(cnt);
}
#define preempt_disable() \
do { \preempt_count_inc(); \barrier(); \
} while (0)
#define preempt_enable() \
do { \barrier(); \if (unlikely(preempt_count_dec_and_test())) \__preempt_schedule(); \
} while (0)

 

本文标签: preempt