【Linux内核】Linux软中断处理机制-ksoftirqd

1.前言

软中断(softirq)是中断处理程序在开启中断的情况下执行的部分,可以被硬中断抢占。把延迟函数叫做软中断并不是因为它是一个真正的中断,而是因为延迟函数主要在中断上下文环境中运行。Linux中最多可以支持32种软中断操作,但目前Linux只实现了其中的几种。

中断号名称作用
0HI_SOFTIRQ高优先级tasklet
1TIMER_SOFTIRQ定时器软中断
2NET_TX_SOFTIRQ网络发送软中断
3NET_RX_SOFTIRQ网络接收软中断
4SCSI_SOFTIRQSCSI设备驱动专用软中断
5TASKLET_SOFTIRQ常规tasklet
    include/linux/interrupt.h
    enum
    {
          HI_SOFTIRQ=0,
          TIMER_SOFTIRQ,
          NET_TX_SOFTIRQ,
          NET_RX_SOFTIRQ,
          BLOCK_SOFTIRQ,
          IRQ_POLL_SOFTIRQ,
          TASKLET_SOFTIRQ,
          SCHED_SOFTIRQ,
          HRTIMER_SOFTIRQ, /* 没有使用,但是保留,因为有些工具依赖这个编号 */
          RCU_SOFTIRQ,     /* RCU软中断应该总是最后一个软中断 */
          NR_SOFTIRQS
    };

2.关键函数

  • 函数open_softirq()用来注册软中断的处理函数,在软中断向量表中为指定的软中断编号设置处理函数。
    kernel/softirq.c
    void open_softirq(int nr, void (*action)(struct softirq_action *))
    {
          softirq_vec[nr].action = action;
    }
  • 函数raise_softirq用来触发软中断,参数是软中断编号。
    void raise_softirq(unsigned int nr);

3.执行软中断

内核执行软中断的地方如下。

  • (1)在中断处理程序的后半部分执行软中断,对执行时间有限制:不能超过2毫秒,并且最多执行10次。
  • (2)每个处理器有一个软中断线程,调度策略是SCHED_NORMAL,优先级是120。
  • (3)开启软中断的函数local_bh_enable()。
    在中断处理程序的后半部分,调用函数irq_exit()以退出中断上下文,处理软中断,其代码如下:
    kernel/softirq.c
    void irq_exit(void)
    {preempt_count_sub(HARDIRQ_OFFSET);
          if (! in_interrupt() && local_softirq_pending())
              invoke_softirq();}

如果正在处理的硬中断没有抢占正在执行的软中断,没有禁止软中断,并且当前处理器的待处理软中断位图不是空的,那么调用函数invoke_softirq()来处理软中断。

    kernel/softirq.c
    1   static inline void invoke_softirq(void)
    2   {
    3    if (ksoftirqd_running())
    4         return;
    5
    6    if (! force_irqthreads) {
    7         __do_softirq();
    8    } else {
    9         wakeup_softirqd();
    10   }
    11  }

第3行代码,如果软中断线程处于就绪状态或运行状态,那么让软中断线程执行软中断。第6行和第7行代码,如果没有强制中断线程化,那么调用函数__do_softirq()执行软中断。第8行和第9行代码,如果强制中断线程化,那么唤醒软中断线程执行软中断。函数__do_softirq是执行软中断的核心函数,其主要代码如下:

    kernel/softirq.c
    1   #define MAX_SOFTIRQ_TIME  msecs_to_jiffies(2)
    2   #define MAX_SOFTIRQ_RESTART 10
    3   asmlinkage __visible void __softirq_entry __do_softirq(void)
    4   {
    5    unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
    6    unsigned long old_flags = current->flags;
    7    int max_restart = MAX_SOFTIRQ_RESTART;
    8    struct softirq_action *h;
    9    bool in_hardirq;
    10   __u32 pending;
    11   int softirq_bit;
    12
    1314   pending = local_softirq_pending();
    1516   __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
    1718
    19  restart:
    20   set_softirq_pending(0);
    21
    22   local_irq_enable();
    23
    24   h = softirq_vec;
    25
    26   while ((softirq_bit = ffs(pending))) {
    2728        h += softirq_bit - 1;
    2930        h->action(h);
    3132        h++;
    33        pending >>= softirq_bit;
    34   }
    35
    3637   local_irq_disable();
    38
    39   pending = local_softirq_pending();
    40   if (pending) {
    41        if (time_before(jiffies, end) && ! need_resched() &&
    42            --max_restart)
    43              goto restart;
    44
    45        wakeup_softirqd();
    46   }
    47
    4849   __local_bh_enable(SOFTIRQ_OFFSET);
    5051  }

第14行代码,把局部变量pending设置为当前处理器的待处理软中断位图。第16行代码,把抢占计数器的软中断计数加1。第20行代码,把当前处理器的待处理软中断位图重新设置为0。第22行代码,开启硬中断。第26~34行代码,从低位向高位扫描待处理软中断位图,针对每个设置了对应位的软中断编号,执行软中断的处理函数。第37行代码,禁止硬中断。第40行代码,如果软中断的处理函数又触发软中断,处理如下。❑ 第41~43行代码,如果软中断的执行时间小于2毫秒,不需要重新调度进程,并且软中断的执行次数没超过10,那么跳转到第19行代码继续执行软中断。第45行代码,唤醒软中断线程执行软中断。第49行代码,把抢占计数器的软中断计数减1。

4.ksoftirqd

软中断线程每个处理器有一个软中断线程,名称是“ksoftirqd/”后面跟着处理器编号,调度策略是SCHED_NORMAL,优先级是120。软中断线程的核心函数是run_ksoftirqd(),其代码如下:

    kernel/softirq.c
    static void run_ksoftirqd(unsigned int cpu)
    {
          local_irq_disable();
          if (local_softirq_pending()) {
                __do_softirq();
                local_irq_enable();return;
          }
          local_irq_enable();
    }

5.参与讨论

==================================

新的文章内容和分享已更新在:

|工|·-·|重|·-·|号|:协议森林

==================================

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux 软中断是一种内核,用于在内核中异步地执行某些任务。它允许在不影响实时性能的情况下,执行一些较长时间的任务。 软中断的实现基于 Linux 内核中的中断机。当外部硬件触发中断时,硬件会向 CPU 发送一个中断信号。在 Linux 内核中,中断处理程序会被调用来响应中断信号。中断处理程序通常会处理硬件设备的输入,然后将控权返回给内核。 在软中断中,中断处理程序被用于执行一些内核中的异步任务。Linux 内核中有一个专用的软中断处理程序,它被称为 ksoftirqd。这个处理程序会定期检查软中断队列,如果队列中有任务需要执行,就会调用对应的软中断处理程序来处理这些任务。 软中断的实现还涉及到了以下几个方面: 1. 软中断处理程序的注册。在内核中,可以通过注册函数将软中断处理程序注册到软中断向量中。 2. 软中断队列的管理。软中断队列是一个 FIFO 队列,用于存储需要执行的软中断任务。在内核中,可以通过添加任务到队列或者从队列中删除任务来管理软中断队列。 3. 软中断处理程序的实现。软中断处理程序通常是一个函数,会处理队列中的任务。在执行任务时,需要注意不要阻塞当前进程或者其他进程的执行。 总之,Linux 软中断是一种内核,它允许在内核中异步地执行某些任务,从而提高系统的性能和实时性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值