认认真真的聊聊"软"中断
软中断与硬中断很像
开启内核软中断处理的守护进程

asmlinkage void __init start_kernel(void) {
    ...
    trap_init();
    sched_init();
    time_init();
    ...
    rest_init();
}
static void rest_init(void) {
    kernel_thread(init, NULL, CLONE_KERNEL);
} 
static int init(void * unused) {
    do_pre_smp_initcalls();
}
static void do_pre_smp_initcalls(void) {
    spawn_ksoftirqd();
}
__init int spawn_ksoftirqd(void) {
    cpu_callback(&cpu_nfb, CPU_ONLINE, (void *)(long)smp_processor_id());
    register_cpu_notifier(&cpu_nfb);
    return 0;
}
static int __devinit cpu_callback(...) {
    kernel_thread(ksoftirqd, hcpu, CLONE_KERNEL);
}
static int ksoftirqd(void * __bind_cpu) {
    for (;;) {
        while (local_softirq_pending()) {
            do_softirq();
            cond_resched();
        }
    }
}
asmlinkage void do_softirq(void) {
    h = softirq_vec;
    pending = local_softirq_pending();
    do {
        if (pending & 1) {
            h->action(h);
        h++;
        pending >>= 1;
    } while (pending);
}
// 这就是软中断处理函数表(软中断向量表)
// 和硬中断的中断向量表一样
static struct softirq_action softirq_vec[32];
asmlinkage void do_softirq(void) {
    // h = 软中断向量表起始地址指针
    h = softirq_vec;
    // 这个是软中断标志位们,一次性拿到所有的软中断标志位
    pending = local_softirq_pending();
    do {
        // 此时的软中断标志位有值(说明有软中断)
        if (pending & 1) {
            // 去对应的软中断向量表执行对应的处理函数
            h->action(h);
        // 软中断向量表指针向后移动
        h++;
        // 同时软中断处理标志位也向后移动
        pending >>= 1;
    } while (pending);
}

typedef struct {
    unsigned int __softirq_pending;
    unsigned long idle_timestamp;
    unsigned int __nmi_count;   /* arch dependent */
    unsigned int apic_timer_irqs;   /* arch dependent */
} irq_cpustat_t;
extern irq_cpustat_t irq_stat[];    /* defined in asm/hardirq.h */
#define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)
#define __IRQ_STAT(cpu, member) ((void)(cpu), irq_stat[0].member)
#define softirq_pending(cpu)  __IRQ_STAT((cpu), __softirq_pending)
#define local_softirq_pending() softirq_pending(smp_processor_id())
pending = local_softirq_pending();
pending = irq_stat[0].__softirq_pending;
// 软中断向量表指针向后移动
h++;
// 同时软中断处理标志位也向后移动
pending >>= 1;

注册软中断向量表
softirq_vec[0].action = NULL;
softirq_vec[1].action = run_timer_softirq;
softirq_vec[2].action = net_tx_action;
...
softirq_vec[31].action = xxx;
subsys_initcall(net_dev_init);
static int __init net_dev_init(void) {
    ...
    // 网络发包的处理函数
    open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
    // 网络收包的处理函数
    open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
    ...
}
void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
{
    softirq_vec[nr].data = data;
    // 简直完全一样
    softirq_vec[nr].action = action;
}
enum
{
    HI_SOFTIRQ=0,
    TIMER_SOFTIRQ,
    NET_TX_SOFTIRQ,
    NET_RX_SOFTIRQ,
    SCSI_SOFTIRQ,
    TASKLET_SOFTIRQ
};
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,
    NR_SOFTIRQS
};
触发一次软中断
pending = local_softirq_pending();

代码这么写就行了。
local_softirq_pending() |= 1UL << 2;
#define __raise_softirq_irqoff(nr) \
do { local_softirq_pending() |= 1UL << (nr); } while (0)
static inline void __netif_rx_schedule(struct net_device *dev) {
    list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
    // 发出软中断
    __raise_softirq_irqoff(NET_RX_SOFTIRQ);
}
static inline void __netif_rx_schedule(struct net_device *dev) {
    list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
    // 发出软中断
    local_softirq_pending() |= 1UL << (NET_RX_SOFTIRQ)
}
 总结

static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs) {
   __netif_rx_schedule(netdev);
}
static inline void __netif_rx_schedule(struct net_device *dev) {
    list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
    __raise_softirq_irqoff(NET_RX_SOFTIRQ);
}
评论
