zoukankan      html  css  js  c++  java
  • 中断与异常(四)

    这节主要说软中断,书中注释相对少点,理解困难点,后面有些问题需要大家帮忙,感激不尽。

    2.4以前的内核采用bhbottom half)机制,来避免中断关闭时间太长而丢失重要中断。

    因为bh机制实际上是调用bh_base[32]中的某一项来完成,所以后文用bh_base来代替。

    由于bh_base设计的是cpu不可重入,在SMP系统中,即使其他CPU空闲也无法执行bh_base函数,造成瓶颈,因而引入了新的框架----“软中断”。

    机制分层“软中断”-----tasklet-----bh_base”。Bh_base设计最简单,因为不需要考虑多cpu,重入问题,而tasklet可以多cpu执行,不可重入,软中断则是多cpu,可重入。

    2.4以后的linux则是通过一层层的封装来用软中断实现bh_base,这是比较麻烦的,看了好久。

    从最上层的软中断说起

    内核定义四种软中断

    enum
    {
        HI_SOFTIRQ=0,
        NET_TX_SOFTIRQ,
        NET_RX_SOFTIRQ,
        TASKLET_SOFTIRQ
     };

    软中断向量

    struct softirq_action

    {

    void        (*action)(struct softirq_action *);

    这就比较蛋疼了,结构体中的函数的参数就是当前的结构体的指针,因为书中所举例子没用这个参数,无法感觉这么设计的精妙之处啊,而且造成了理解障碍

    void        *data;

    通常是软中断号

    };

    软中断向量表softirq_vec

    static struct softirq_action softirq_vec[32] __cacheline_aligned;

    全局,32项,虽然内核只用了4项,还不推荐分配新的软中断

    软中断控制/状态表irq_stat[NR_CPUS]

    为了能多cpu处理软中断,所以每个cpu需要记录自己的硬中断、软中断个数、状态,软中断队列等信息,是一个irq_cpustat_t结构体数组

    /* assembly code in softirq.h is sensitive to the offsets of these fields */
    
    typedef struct {
    
      unsigned int __softirq_pending;
    
      unsigned int __local_irq_count;
    
      unsigned int __local_bh_count;
    
      unsigned int __syscall_count;
    
      struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
    
      unsigned int __nmi_count;        /* arch dependent */
    
    } ____cacheline_aligned irq_cpustat_t;

    cpu同时执行不同的tasklet就靠其中的一些相关数据来管理

    多层封装实现

    tasklet封装bh_base

    因为tasklet可以允许多个cpu执行不同的tasklet,而bh_base32个,同一时间允许一个cpu执行一个bh_base,所以内核新建了bh_task_vec[32]数组来进行封装。

    来看看是怎么利用tasklet_struct架构巧妙的处理的。结构体定义

    struct tasklet_struct
    
    {
    
      struct tasklet_struct *next;
    
      unsigned long state;
    
      atomic_t count;
    
      void (*func)(unsigned long);
    
      unsigned long data;
    
    };

    在初始化bh_task_vec[32]的过程中,将bh_actioni绑定到对应的bh_task_vec[i]上就完成了封装。

    void tasklet_init(struct tasklet_struct *t,
                void (*func)(unsigned long), unsigned long data) {   t->next = NULL;   t->state = 0;   atomic_set(&t->count, 0);   t->func = func;   t->data = data; } void __init softirq_init() {   int i;   for (i=0; i<32; i++)     tasklet_init(bh_task_vec+i, bh_action, i);   open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);   open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL); }

    此处将bh_task_vec[i]bh_actioni绑定到了一起,如果你经验丰富也许就会发现,bh_action拿到了这个i不就可以去执行bh_base[i]linux确实是这样做的。

    软中断封装tasklet

    最终linux是希望所有的bottom half在新的软中断框架下运行的,所以还要进行一次封装。

    linuxbh_task_vec封装到了0号软中断线上,也就是HI_SOFTIRQ,其主要实现的就是将软中断请求调度到一个可执行cpu上,让这个cpu去执行这个最本质的bn_base[i]

    这就是软中断的精髓,将软中断任务进行调度,因为不同的cpu有不同的软中断队列,自然就形成了多cpu同时执行软中断,这是软中断的最理想形态,但tasklet设计成不可重入,只需在tasklet进行调度之前进行判断,合法才进行调度,而bh_base则在执行之前加上全局锁,这样就很好的满足了多样化的需求。这些设计确实厉害,不得不服。

    来看具体实现代码,从上一节硬中断调用do_softirq()说起

     

     

    为了使do_irq()能够执行一个特定的bh_base函数,需要先申请0号软中断线,申请软中断线和软中断调度任务的代码是多cpu,可重入的,这就使得某个cpu申请软中断,其他cpu执行,软中断的基本框架就有了。

    申请执行bh_base[nr]函数

    回顾上面的do_irq()0号软中断线执行h->action(h),实际上执行的是绑定在0号软中断线上的服务例程tasklet_hi_action

    最后一个函数完成最终bh_base[nr]调用

  • 相关阅读:
    Spring 中出现Element : property Bean definitions can have zero or more properties. Property elements correspond to JavaBean setter methods exposed by the bean classes. Spring supports primitives, refer
    java定时器schedule和scheduleAtFixedRate区别
    hql语句中的select字句和from 字句
    使用maven搭建hibernate的pom文件配置
    Failure to transfer org.apache.maven:maven-archiver:pom:2.5 from http://repo.maven.apache.org/ maven2 was cached in the local repository, resolution will not be reattempted until the update interv
    对于文件File类型中的目录分隔符
    hibernate的事务管理和session对象的详解
    解决mac 中的myeclipse控制台中文乱码问题
    ibatis selectKey用法问题
    Java中getResourceAsStream的用法
  • 原文地址:https://www.cnblogs.com/hmxb/p/4906001.html
Copyright © 2011-2022 走看看