// irq统计信息
1.1 typedef struct {
unsigned int __softirq_pending;//softirq标志位,32种softirq
unsigned long idle_timestamp;
unsigned int __nmi_count; //nmi中断发生次数
unsigned int apic_timer_irqs; /* arch dependent */
} ____cacheline_aligned irq_cpustat_t;
// 检查softirq标志是否被置位
1.2 #define local_softirq_pending() \
__IRQ_STAT(smp_processor_id(), __softirq_pending)
// per-cpu irq统计信息
1.3 #define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)
// 软中断入口函数
// 调用路径 __do_IRQ->irq_exit->do_softirq
// 函数主要任务:
// 1.确保没有hardirq,softirq运行情况,否则直接退出
// 2.关中断,检查是否有raise的softirq
// 2.1 执行软中断处理函数
// 3.恢复中断状态
// 注:
// 1.软中断执行过程中,开中断,关软中断,禁止内核抢占
// 2.do_softirq会在中断、softirqd两条路径上被调用,同时只有一个在执行
2.1 asmlinkage void do_softirq(void)
{
__u32 pending;
unsigned long flags;
//如果当前有hardirq,softirq在运行中,直接退出
if (in_interrupt())
return;
//关中断下检查softirq标志
local_irq_save(flags);
pending = local_softirq_pending();
//执行softirq处理函数
if (pending)
__do_softirq();
//恢复之前的中断状态
local_irq_restore(flags);
}
// 执行软中断处理函数
// 调用路径 __do_IRQ->irq_exit->do_softirq->__do_softirq
// 函数主要任务:
// 1.获取raise的softirq比特位
// 2.禁止本cpu的softirq
// 3.清除softirq标志位
// 4.开中断
// 5.遍历softirq_vec,执行被raise的softirq_action的处理函数
// 6.关中断
// 7.检查softirq标志位
// 7.1 如果有raise的softirq,并且没有超过最大的遍历次数,重复步骤3
// 7.2 否则,唤醒softirq核心进程处理softirq
// 8.开启本cpu的softirq
2.2 asmlinkage void __do_softirq(void)
{
struct softirq_action *h;
__u32 pending;
//最大遍历次数10次
int max_restart = MAX_SOFTIRQ_RESTART;
int cpu;
//本cpu被raise的softirq
pending = local_softirq_pending();
//禁止本cpu softirq
local_bh_disable();
cpu = smp_processor_id();
restart:
//softirq标志位清空
local_softirq_pending() = 0;
//开中断
local_irq_enable();
h = softirq_vec;
do {
if (pending & 1) {
h->action(h);
rcu_bh_qsctr_inc(cpu);
}
h++;
pending >>= 1;
} while (pending);
local_irq_disable();
pending = local_softirq_pending();
if (pending && --max_restart)
goto restart;
//超过最大的调用次数,唤醒softirq核心进程
if (pending)
wakeup_softirqd();
//开启软中断
__local_bh_enable();
}
// 禁止本cpu softirq
2.2 #define local_bh_disable() \
do { add_preempt_count(SOFTIRQ_OFFSET); barrier(); } while (0)
// 唤醒softirq进程
// 函数主要任务:
// 1.获取本cpu的softirq进程
// 2.如果进程未执行,唤醒其
// 注:
// 关中断,关软中断状态下唤醒softirq进程
3.1 static inline void wakeup_softirqd(void)
{
//per cpu进程
struct task_struct *tsk = __get_cpu_var(ksoftirqd);
//softirq进程非就绪状态
if (tsk && tsk->state != TASK_RUNNING)
{
wake_up_process(tsk);//唤醒进程
}
}
// softirq核心进程function
// 函数主要任务:
// 1.检查softirq标志
// 2.禁止内核抢占
// 3.通过do_softirq执行软中断处理函数
// 4.开启内核抢占
// 注:
// 1.软中断执行过程中,开中断,关软中断,禁止内核抢占
// 2.do_softirq会在中断、softirqd两条路径上被调用,同时只有一个在执行
3.2 static int ksoftirqd(void * __bind_cpu)
{
//设置静态优先级
set_user_nice(current, 19);
//当前进程不允许被frozen
current->flags |= PF_NOFREEZE;
//可中断睡眠
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
//没有raised的softirq,调度
if (!local_softirq_pending())
{
schedule();
}
//进程被唤醒
__set_current_state(TASK_RUNNING);
//检查softirq标志
while (local_softirq_pending()) {
//禁止内核抢占
preempt_disable();
//与中断路径执行相同的处理函数,二者同时只有一个在执行
do_softirq();
//开启内核抢占
preempt_enable();
//检查是否need reschedule
cond_resched();
}
set_current_state(TASK_INTERRUPTIBLE);
}
//设置进程为运行状态,然后退出
//此进程不再会被wakeup_softirqd唤醒执行
__set_current_state(TASK_RUNNING);
return 0;
}
// softirq数组
// irq_cpustat_t->__softirq_pending只有32bit,因此共有32种软中断
4.1 static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp;
// softirq描述符
4.2 struct softirq_action
{
void (*action)(struct softirq_action *);
void *data;
};
// 静态编译的软中断类型
4.3 enum
{
HI_SOFTIRQ=0,
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
SCSI_SOFTIRQ,
TASKLET_SOFTIRQ
};
// raise softirq
// 注:
// 调用者负责调用前禁止中断
5.1 inline fastcall void raise_softirq_irqoff(unsigned int nr)
{
//设置对应的bit位
__raise_softirq_irqoff(nr);
//当前不在中断上下文中,唤醒softirq进程
if (!in_interrupt())
wakeup_softirqd();
}
// raise softirq
// 注:
// 本函数会负责关闭中断
5.2 void fastcall raise_softirq(unsigned int nr)
{
unsigned long flags;
//关中断
local_irq_save(flags);
raise_softirq_irqoff(nr);
local_irq_restore(flags);
}
// 注册softirq
5.3 void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
{
softirq_vec[nr].data = data;
softirq_vec[nr].action = action;
}
中断子系统8_软中断入口处理
最新推荐文章于 2020-12-20 14:19:14 发布