分类: LINUX
2014-01-03 14:07:39
在分时系统中,内核总是可以随意抢占用户进程,同时系统调用和其他内核任务也可以被其他较高优先级的内核任务给抢占掉。在内核中与抢占相关的函数包括:
这些函数都会被互斥操作如rcu_read_lock、rcu_read_unlock、spin_lock、spin_unlock等函数调用,同时用于访问各个CPU变量的函数在读取数据之前也会调用这些函数关闭抢占功能,如get_cpu和get_cpu_var。
每个进程都有一个计数器,preempt_count内嵌于thread_info结构内,来表示特定进程是否允许抢占功能。这个字段由preempt_count()读取,通过inc_preempt_count()和dec_preempt_count()函数间接操作。preempt_count字段被分为三组,每个字节分别表示一个计数器,来统计不同情况下的非抢占情况,分别为硬件中断、软件中断和一般非抢占情况:
struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
__u32 flags; /* low level flags */
__u32 status; /* thread synchronous flags */
__u32 cpu; /* current CPU */
int preempt_count; /* 0 => preemptable,
BUG */
mm_segment_t addr_limit;
struct restart_block restart_block;
void __user *sysenter_return;
#ifdef CONFIG_X86_32
unsigned long previous_esp; /* ESP of the previous stack in
case of nested (IRQ) stacks
*/
__u8 supervisor_stack[0];
#endif
int uaccess_err;
};
访问这个字段通过宏:
#define preempt_count() (current_thread_info()->preempt_count)
# define add_preempt_count(val) do { preempt_count() += (val); } while (0)
# define sub_preempt_count(val) do { preempt_count() -= (val); } while (0)
分别表示不同情况下非抢占的计数:
在调用schedule抢占当前任务之前,当前进程的图中的PREEMPT_ACTIVE会被设置。
其中还列出了在对应情况下操作对应非抢占计数的函数。
如local_bh_disable:
void local_bh_disable(void)
{
__local_bh_disable((unsigned long)__builtin_return_address(0),
SOFTIRQ_DISABLE_OFFSET);
}
static inline void __local_bh_disable(unsigned long ip, unsigned int cnt)
{
add_preempt_count(cnt);
barrier();
}
其实就是增加对应字节的计数。
其实查看当前任务所处的环境也是针对这三个不同的字节的计数情况:
#define in_irq() (hardirq_count()) //硬中断中
#define in_softirq() (softirq_count()) //软中断中
#define in_interrupt() (irq_count())
#define in_serving_softirq() (softirq_count() & SOFTIRQ_OFFSET)
#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))