其他
认认真真的聊聊"软"中断
软中断与硬中断很像
开启内核软中断处理的守护进程
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);
}