zoukankan      html  css  js  c++  java
  • 中断子系统8_软中断入口处理

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


  • 相关阅读:
    86. Partition List
    2. Add Two Numbers
    55. Jump Game
    70. Climbing Stairs
    53. Maximum Subarray
    64. Minimum Path Sum
    122. Best Time to Buy and Sell Stock II
    以场景为中心的产品设计方法
    那些产品经理犯过最大的错
    Axure教程:如何使用动态面板?动态面板功能详解
  • 原文地址:https://www.cnblogs.com/riasky/p/3429350.html
Copyright © 2011-2022 走看看