软中断

linux中断的处理分为顶半部和低半部,顶半部在硬件中断处理函数中实现(request_irq()中可申请用户回调函数),底半部的实现机制有三种:软中断/tasklet/workqueue。

软中断的执行时机通常是顶半部返回的时候,tasklet是基于软中断实现的,因此也运行于软中断上下文。

在linux内核中,用softirq_action结构体表征一个软中断,这个结构体包含软中断处理函数指针和传递给该函数的参数。使用open_softirq()函数可以注册软中断对应的处理函数,而raise_softirq()函数可以触发一个软中断。

local_bh_disable()和local_bh_enable()是内核中用于禁止和使能软中断及tasklet底半部机制的函数。

本文档描述基于3.14.77内核。

1. 定义

softirq定义在linux/interrupt.h中,实现在kernel/softirq.c中。tasklet是基于软中断实现的,相关代码也在这两个文件中。

enum
{
    HI_SOFTIRQ=0,
    TIMER_SOFTIRQ,
    NET_TX_SOFTIRQ,
    NET_RX_SOFTIRQ,
    BLOCK_SOFTIRQ,
    BLOCK_IOPOLL_SOFTIRQ,
    TASKLET_SOFTIRQ,
    SCHED_SOFTIRQ,
    HRTIMER_SOFTIRQ,
    RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */

    NR_SOFTIRQS
};

#define SOFTIRQ_STOP_IDLE_MASK (~(1 << RCU_SOFTIRQ))

/* map softirq index to softirq name. update 'softirq_to_name' in
 * kernel/softirq.c when adding a new softirq.
 */
extern const char * const softirq_to_name[NR_SOFTIRQS];

/* 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 *);
};

说明:之前linux版本,struct softirq_action包含两项action(软中断服务程序)和data(服务程序输入参数),因为其参数为softirq_action,可定义为全局变量而省去data定义。

static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;

softirq相关函数

asmlinkage void do_softirq(void);
asmlinkage void __do_softirq(void);

#ifdef __ARCH_HAS_DO_SOFTIRQ
void do_softirq_own_stack(void);
#else
static inline void do_softirq_own_stack(void)
{
    __do_softirq();
}
#endif

extern void open_softirq(int nr, void (*action)(struct softirq_action *));
extern void softirq_init(void);
extern void __raise_softirq_irqoff(unsigned int nr);

extern void raise_softirq_irqoff(unsigned int nr);
extern void raise_softirq(unsigned int nr);

 2. 实现机制

 软中断守护程序是软中断机制实现的核心,它的实现过程简单。通过查询软中断的状态来判断是否发生事件,当发生事件就会映射软中断向量表,调用执行注册的action()函数就可以了。从这一点分析可以看出,软中断的服务程序是daemon。在linux中软中断daemon线程函数为do_softirq()。

asmlinkage 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_own_stack();

    local_irq_restore(flags);
}

 网络软中断举例:

当网络上有数据时,发生了硬件中断,硬件中断服务程序会接收网络数据,设置中断状态,并将网络数据挂接到链表中,进行中断调度,这一步可以通过net_schedule()函数完成。硬件中断服务程序最后退出并且CPU开始调度软中断,软中断daemon会发现网络软中断发生了事件,其会执行网络中断对应的服务程序,即进入网络协议栈处理程序。

参考:

1. linux中断编程

2. linux内核对中断的处理方式

3. 设备驱动开发详解 宋宝华

4. linux网络编程 宋敬彬

原文地址:https://www.cnblogs.com/twodog/p/12136688.html