zoukankan      html  css  js  c++  java
  • Linux 软中断

    本文转载自: http://blog.chinaunix.net/uid-9620812-id-3833377.html,如有需要,请移步访问。

    Technorati 标签:

    ---------------------------------------我是分割线----------------------------------------

    一、软中断注册
    和硬中断类似,软中断也有类似的中断向量表,只不过是用“软件”实现的。
    struct softirq_action softirq_vec[32]是软中断向量表  
    (文件linux_2_6_24/kernel/softirq.c)

    1. struct softirq_action
    2. {
    3.     void (*action)(struct softirq_action *); //钩子函数
    4.     void *data;                              //钩子函数的形参
    5. };

    内核用到的中断向量(其实就是数组下标)如下所示
    (文件linux_2_6_24/include/linux/interrupt.h)

    1. enum{
    2.     HI_SOFTIRQ=0, //高优先级的tasklet
    3.     TIMER_SOFTIRQ,      //内核定时器
    4.     NET_TX_SOFTIRQ,     //网络发送
    5.     NET_RX_SOFTIRQ,     //网络接收
    6.     BLOCK_SOFTIRQ,      //???
    7.     TASKLET_SOFTIRQ,    //普通的tasklet
    8.     SCHED_SOFTIRQ
    9. }

    内核注册一个软中断用函数,本质上就是就是初始化数组某一元素

    1. void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
    2. {   //nr 即软中断向量编号
    3.     softirq_vec[nr].data = data;
    4.     softirq_vec[nr].action = action;
    5. }

    内核注册软中断的地方有:

    1. start_kernel()
    2. -->init_timers()
    3. -->open_softirq(TIMER_SOFTIRQ,run_timer_softirq,NULL)
    4. -->softirq_init()
    5. -->open_softirq(TASKLET_SOFTIRQ, tasklet_action,NULL)
    6. -->open_softirq(HI_SOFTIRQ,tasklet_hi_action,NULL)
    7. -->do_initcall()
    8. -->net_dev_init()
    9. -->open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
    10. -->open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
    11. -->blk_dev_init()
    12. -->open_softirq(BLOCK_SOFTIRQ, blk_done_softirq,NULL)

    二、软中断触发
    前面注册完了,现在开始触发。
    内核用一个数据结构来标记曾经有“软中断”发生过(或者说成软中断被触发过)
    __softirq_pending 共32bit,即每个bit对应软中断的一个向量,实际使用了6个bit
    第n个bit置1,即softirq_vec[n]有软中断发生。

    1. typedef struct {
    2.     unsigned int __softirq_pending; /* set_bit is used on this */
    3.     unsigned int __last_jiffy_stamp;
    4. } ____cacheline_aligned irq_cpustat_t;
    5. extern irq_cpustat_t irq_stat[]; /* defined in asm/hardirq.h */
    6. #define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)
    7. #define local_softirq_pending()
    8.     __IRQ_STAT(smp_processor_id(), __softirq_pending)
    9. #define set_softirq_pending(x) (local_softirq_pending() = (x))
    10. #define or_softirq_pending(x) (local_softirq_pending() |= (x))
    11. #define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0)

    常用的软中断触发函数

    1. void raise_softirq_irqoff(int nr){    //nr 即软中断向量编号
    2.     __raise_softirq_irqoff(nr);
    3. }

    但这只是“触发”软中断,软中断并不会立即被处理
    三、软中断处理
    函数_ _do_softirq是一次性按照向量表从高到低循环处理所有软中断(潜台词,软中断不可嵌套)
    _ _do_softirq()的调用时机:
    1. irq_exit() 硬件中断处理完,返回时调用

    1. do_IRQ() -->irq_exit()
    2. -->local_softirq_pending()
    3. -->_ _do_softirq()

    2. ksoftirqd()  用于辅助处理软中断的内核线程,每一个CPU上都运行着一个ksoftirqd。

    1. start_kernel() --> kernel_init() -->do_pre_smp_initcalls()
    2. -->spawn_ksoftirqd() -->cpu_callback()
    3. -->kthread_create(ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu)
    4. -->ksoftirqd()
    5. -->local_softirq_pending()
    6. -->_ _do_softirq()

    3. local_bh_enable()时,发现有待处理的软中断且当时没处在软硬中断上下文中

    1. local_bh_enable()
    2. -->local_softirq_pending()
    3. -->_ _do_softirq()

    处理过程代码详解

    1. asmlinkage void __do_softirq(void)
    2. {
    3.     struct softirq_action *h;
    4.     __u32 pending;
    5. int max_restart = MAX_SOFTIRQ_RESTART;
    6. int cpu;
    7.     pending = local_softirq_pending();
    8.     account_system_vtime(current);
    9. /*软中断处理中,禁止软中断再次进入,软中断处理是不可重入的*/
    10.     __local_bh_disable((unsigned long)__builtin_return_address(0));
    11.     trace_softirq_enter();
    12.     cpu = smp_processor_id();
    13. restart:
    14. /* Reset the pending bitmask before enabling irqs
    15.     下面首先清除pending,以便系统可以激活其它软件中断,
    16.     然后使能外部中断
    17.     系统在下面的处理中,将使能外部中断以提高系统的响应,
    18.     注意,必须先清除pending,再使能外部中断,否则死锁*/
    19.     set_softirq_pending(0);
    20.     local_irq_enable();
    21.     h = softirq_vec;
    22. /*下面按照从高到低调用open_softirq注册的句柄*/
    23. do {
    24. if (pending & 1) {
    25. h->action(h); //关键的一句,tasklet、内核timer、网络中断都是在这里搞的
    26.             rcu_bh_qsctr_inc(cpu);
    27. }
    28.         h++;
    29.         pending >>= 1;
    30. } while (pending);
    31.     local_irq_disable();
    32.     pending = local_softirq_pending();
    33. if (pending && --max_restart)
    34.         goto restart;
    35. if (pending)
    36.         wakeup_softirqd();
    37.     trace_softirq_exit();
    38.     account_system_vtime(current);
    39.     _local_bh_enable();
    40. }
  • 相关阅读:
    codeforces_1075_C. The Tower is Going Home
    leetcode_Stone Game_dp_思维
    leetcode_Counting Bits_dp
    Divide and Conquer_1.最大连续子数组
    python_MachineLearning_感知机PLA
    IIS中启用gzip压缩(网站优化)
    asp.net运行机制图
    asp.net 的那点事(2、浏览器和一般处理程序)
    asp.net 的那点事(1、当用户在浏览器地址栏输入了网址后,发生了什么?)
    android环境搭配 运行android sdk manager时出现错误问题解决
  • 原文地址:https://www.cnblogs.com/cherishui/p/4318660.html
Copyright © 2011-2022 走看看