中断管理基础学习笔记 - 6. 软中断

本文详细介绍了ARM64架构下的中断处理,特别是软中断机制。软中断在Linux内核中用于处理时间敏感的任务,分为多个类型,如HI_SOFTIRQ、TIMER_SOFTIRQ等。每个软中断由索引标识,且有相应的软中断描述符数组softirq_vec。注册软中断通过open_softirq,触发软中断使用raise_softirq或raise_softirq_irqoff。软中断的执行时机包括中断返回、ksoftirqd线程和local_bh_enable。tasklet是一种特殊的软中断,通过DECLARE_TASKLET声明,tasklet_schedule安排执行,tasklet_action负责执行。整个过程确保了软中断的串行执行和优先级调度。

1. 前言

本专题我们开始学习进程管理部分。本文主要参考了《奔跑吧, Linux内核》、ULA、ULK的相关内容。
本专题记录ARM架构下中断是如何管理的,Linux内核中的中断管理机制是如何设计与实现的,以及常用的下半部机制,如软中断、tasklet、workqueue等。本文及后续中断相关笔记均以qemu 5.0.0内嵌平台为例,中断控制器采用GIC-400控制器,支持GIC version2技术规范。本文开始介绍ARM64的中断处理过程,上一节介绍了中断的高层处理过程gic_handle_irq,在gic_handle_irq的最后会调用irq_exit退出中断,irq_exit的执行过程中会处理软中断。

kernel版本:5.10
平台:arm64

注:
为方便阅读,正文标题采用分级结构标识,每一级用一个"-“表示,如:两级为”|- -", 三级为”|- - -“

2. 软中断概述

软中断再Linux2.3引入,是预留给系统中对时间要求最为严格和最重要的下半部使用的,目前驱动中只有块设备和网络子系统使用了软中断。

软中断类型

系统静态定义了若干种软中断类型,内核开发者不希望用户再扩充新的软中断类型,如有需要,建议使用tasklet机制。每一种软中断都使用索引来表示一种相对的优先级,索引号越小,软中断优先级高,并在一轮软中断处理中得到优先执行。
已经定义好的软中断类型如下:

/* PLEASE, avoid to allocate new softirqs, if you need not _really_ high
   frequency threaded job scheduling. For almost all the purposes
   tasklets are more than enough. F.e. all serial device BHs et
   al. should be converted to tasklets, not to softirqs.
 */
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,    /* Preferable RCU should always be the last softirq */

        NR_SOFTIRQS
};

软中断数据结构

  • struct softirq_action
/* softirq mask and active fields moved to irq_cpustat_t in
 * asm/hardirq.h to get better cache usage.  KAO
 */
struct softirq_action
{
   
   
        void    (*action)(struct softirq_action *); 
};

用于描述软中断所要执行的回调

static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;

软中断描述符数组softirq_vec[],类似于硬件中断描述符数据结构irq_desc[],每个软中断类型对应一个描述符,其中软中断的索引号就是该数组的索引.NR_SOFTIRQS为支持的最大软中断类型个数,__cacheline_aligned_in_smp用于将softirq_vec数据结构和L1缓存行对齐

  • irq_cpustat_t
typedef struct {
   
   
	unsigned int __softirq_pending;
} ____cacheline_aligned irq_cpustat_t;

描述软中断状态信息,可以理解为软中断状态寄存器,其成员__softirq_pending的每个bit位表示一个软中断类型的状态,置0表示此类型软中断没有触发,置1表示已经触发,需要执行对应的软中断处理函数。

#ifndef __ARCH_IRQ_STAT
DEFINE_PER_CPU_ALIGNED(irq_cpustat_t, irq_stat);
EXPORT_PER_CPU_SYMBOL(irq_stat);
#endif

每一个CPU有一个软中断状态信息变量irq_stat(即__softirq_pending),__softirq_pending的每一个bit代表本CPU的一个软中断类型

3. 注册软中断

void open_softirq(int nr, void (*action)(struct softirq_action *))
    |--softirq_vec[nr].action = action;

softirq_vec[]是一个多CPU共享的数组,软中断的初始化通常是在系统启动时init函数中完成(如:subsys_initcall(blk_softirq_init);),系统启动时是串行执行的,因此没有额外保护机制。

4. 触发软中断

raise_softirq和raise_softirq_irqoff是触发软中断的两个主要接口,注意触发软中断只是将per cpu的irq_stat.__softirq_pending的相应bit位置位,中断处理退出函数irq_exit执行软中断才会真正的执行软中断对应的回调action

raise_softirq

void raise_softirq(unsigned int nr)
    |  //关闭本地中断,实际屏蔽本地CPU的PSTATE的irq bit
    |--local_irq_save(flags);
    |--raise_softirq_irqoff(nr);
    |      |--__raise_softirq_irqoff(nr);
    |      |      |--lockdep_assert_irqs_disabled();
    |      |      |  //实际是置位本地cpu的irq_stat.__softirq_pending的第nr bit
    |      |      |--or_softirq_pending(1UL << nr);
    |      |  //如果不在中断上下文,wakeup_softirqd唤醒本cpu的ksoftirqd线程执行软中断处理函数
    |      |--if (!in_interrupt()) 
    |             |--wakeup_softirqd();
    |--local_irq_restore(flags);

主动触发一个软中断的API接口函数,它会主动关闭本地中断,它实际只会记录

or_softirq_pending:通过置位本地cpu的irq_stat.__softirq_pending的第nr bit,来使得软中断处于pending状态,这样irq_exit->invoke_softirq来执行软中断的softirq_action

wakeup_softirqd:如果不在中断上下文,wakeup_softirqd唤醒本cpu的ksoftirqd线程执行软中断处理函数。 每个cpu都会有一个ksoftirqd线程,专门处理自己CPU的软中断

小结:从这里可以看出每个cpu都通过一个变量irq_stat(per_cpu类型)维护本CPU的所有类型软中断状态,如果变量中某个bit位置位,表示发生了对应类型的软中断,需要退出中断上下文时,执行软中断的处理函数(后面会总结软中断执行的三个时机)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值