Chinaunix首页 | 论坛 | 博客
  • 博客访问: 630684
  • 博文数量: 51
  • 博客积分: 773
  • 博客等级: 军士长
  • 技术积分: 2392
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-07 21:32
文章分类
文章存档

2018年(1)

2013年(16)

2012年(34)

分类: LINUX

2013-06-04 21:59:21

           在分时系统中,内核总是可以随意抢占用户进程,同时系统调用和其他内核任务也可以被其他较高优先级的内核任务给抢占掉。在内核中与抢占相关的函数包括:

  1. preempt_disable:为当前任务关闭抢占功能,可以多次重复调用,其实就是增加一个引用计数器的值;
  2. preempt_enable:与preempt_disable相反,再度打开抢占功能,递减引用计数器的值,当值达到零后,可以让抢占功能再度开启,然后强制调用schedule(),让其他较高优先级的任务执行;
  3. preempt_enable_no_resched:与preempt_enable功能相同,只是引用计数器到0后不会强制调用schedule函数出让CPU;

          这些函数都会被互斥操作如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)

分别表示不同情况下非抢占的计数:

image

在调用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))

阅读(6482) | 评论(6) | 转发(3) |
给主人留下些什么吧!~~