Linux内核探讨-- 第五章

文是个人分析《Linux内核设计与实现》而写的总结,欢迎转载,请注明出处:

                                                                              http://blog.csdn.net/dlutbrucezhang/article/details/12347097

      

      第五章--下半部和退后执行的工作

      上一篇文章提到中断分为上半部和下半部,上半部称作中断处理程序。下半部处理的则是比较耗时的工作。那么为什么会出现下半部呢?
      我们知道,中断是异步发生的,一旦CPU接收了中断,那么就必须处理,所以,就要打断当前执行的代码,如果当前执行的代码很重要,那么中断处理就不应该占据很长的时间,所以,在中断处理中把需要紧急处理的工作放在处理程序中,而把耗时的工作放在下半部执行。下半部执行的时机是不确定的,只是保证它不在当前执行就可以了,一般是放在中断处理程序返回后就会立即执行。这是出现下半部原因的第一个方面。
      中断在执行时,最好的情况是屏蔽掉它那一条中断线,可是,很不幸的事总是会发生,有些中断会使用IRQF_DISABLED标志,那么,所有的中断都会被屏蔽。如果,中断处理是一项很耗时的工作,且这时会不停的出现中断,那么用户进程就会因此而饥饿,所以,需要找个方法来应付这种情况。

      1.下半部执行的策略

      下半部的执行在Linux内核不断完善的过程中,出现了一系列方法,由于有些方法早已经被淘汰了,所以,这里仅介绍在2.6内核中出现的处理方法。
      在2.6内核中出现了三种策略。
      软中断,tasklet,工作队列
      下面,我就对这三种策略进行介绍。

      2.软中断

      这种策略最为高效,但是实际在使用中却用到的不多,因为我们需要处理同步问题,且不能在中断上下文中睡眠,所以,实现难度比较大。
      它是在内核编译期间静态指定的,存在32个软中断,但是实际用到的只有9个。
      软中断保留给系统中对时间要求最为严格以及最重要的下半部使用。
      一个注册的软中断必须被标记以后才能够得到处理,最终系统会调用 do_softirq(),执行软中断,下面,让我们来看看它的执行代码:
void do_softirq(void)
{
        __u32 pending;
        unsigned long flags;

        if (in_interrupt())
                return;

        local_irq_save(flags);

        pending = local_softirq_pending();

        if (pending)
                __do_softirq();

        local_irq_restore(flags);
}

      可以看到,首先它会检查软中断位图,看看哪一位会被标记,如果那一位被标记,那么它所对应的处理程序就会执行,因为位图中存在32位,所以,这段程序是循环执行的,且最多会循环32次。
      软中断允许同类型的软中断同时执行,这也是不好控制它的原因,这里牵扯到了内核同步的问题,这在以后的文章中会有所介绍。

      3.tasklet

      tasklet 其实也是软中断,只是它实现的方式可能会有不同,存在两种tasklet,一种是高优先级的,一种是普通的,它们之间的区别只是优先级,是谁先执行和谁后执行的差别。
      和软中断不同的是,即使是在不同的处理器上也不能同时执行相同类型的tasklet,这样使得驱动开发人员易于编写下半部程序,也更方便的操作。
      它的实现可以使静态的,也可以是动态加载的,它不是以位图的方式显示被标记,而是以链表的形式存放下半部程序,等待执行。

      4.ksoftirqd

      这是一个内核线程,每个CPU上存在一个,它是作为辅助线程而存在的,是用来辅助处理软中断的。我们考虑下面这个问题。
      软中断一旦被触发,除了中断处理程序之外,不会被任何的任务所抢占,软中断也不可以抢占软中断。不过,有时,软中断会在程序中触发它自己,这样就会出现软中断会一直执行下去,用户进程得不到处理,这时,就需要有一种解决方案。ksoftirqd 由此出现,这个线程一般处于睡眠状态,一旦某个软中断触发了它自己,那么这个线程就会被唤醒执行下半部。

      5.工作队列

      它是一种区别于软中断和tasklet的下半部执行方案。它处于进程上下文中,所以,它是可以睡眠的。由于处于进程上下文中,所以,它是由内核线程处理的。一般情况下,我们不定义自己的内核线程,而用的是默认的内核线程,叫做 event。同样也是每个CPU都有一个实例。一旦工作队列上存在任务,那么内核线程会被唤醒以执行下半部。

      6.preempt_count

      这个字段是不是很熟悉呢?没错,第一次对他的介绍出现在内核抢占中,内核可以抢占的时机是 preempe_count这个字段为0,且调度标志被置位。而这里表达的意思是下半部是否被禁止,由于内核中同步的需要,下半部是可能被禁止的,一旦这个标志不是 0 ,那么下半部是不允许执行的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值