软中断 与 调度 --- Linux Kernel 欣赏

先看一个 简单的 PR
在这里插入图片描述
下面是别人的 PR
在这里插入图片描述
作者 Joe Perches 说 :

Possible speed improvement of __do_softirq() by using ffs() instead of
using a while loop with an & 1 test then single bit shift

的确是的,ffs() 底层使用了汇编的实现.
好,那就来欣赏 Joe Perches 的思想吧.

asmlinkage __visible void __softirq_entry __do_softirq(void)
{
	/*
		#define MAX_SOFTIRQ_TIME  msecs_to_jiffies(2)
		
		有一个平衡系统的思想在这里面, 
		即 是否该需要唤醒 ksoftirqd 来进行处理软中断了.
		什么时候需要 wake_up_process  这个per-cpu的内核线程 来处理, 
		在这里做了第一个上限条件
	*/
	unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
	/*
		获取该TASK的标志.
		....
		#define PF_SIGNALED		0x00000400	/* Killed by a signal */
		#define PF_MEMALLOC		0x00000800	/* Allocating memory */
		
		下面会调用 current_restore_flags() 来更新存储该TASK的 flags.
	*/
	unsigned long old_flags = current->flags;
	/*
		和上面的 MAX_SOFTIRQ_TIME 一样,也是决定是否唤醒 ksoftirqd  的条件之一
		ksoftirq 不到一定的程度 它不会轻易出手的. 😄 哈哈
	*/
	int max_restart = MAX_SOFTIRQ_RESTART;	
	/*
		指向软中断描述符数组呗.
		你应该记得 irq_desc[] 吧,这里还挺有对称性
		不过 已经使用 radix tree 来表述 irq_desc 是更好的一种选择.
		
		好,既然是一个 数组, 
		那么下面在处理的时候 却没有保护机制来保护它 是每个 per cpu 变量 ?
		当然不需要保护的,下面在说明.
	*/
	struct softirq_action *h;
	/*
		trace 框架的一些逻辑,暂不分析.
	*/
	bool in_hardirq;
	/*
		存储有 __softirq_pending 的值.
		什么时候会将 __softirq_pending 的某位置 1
		这是softirq的框架问题,如 raise_softirq().
		下面在进行具体处理的时候再说,这只是定义一下,暂不做过多的解释.
	*/
	__u32 pending;
	/*
		你应该知道了这个是局部变量是想要干什么了吧
		no value !
	*/
	int softirq_bit;

	/*
		上面的变量已经定义完成了,下面来看它的核心部分
	*/
	
	/*
		#define PF_MEMALLOC		0x00000800	/* Allocating memory */
		屏蔽该Task 标记位: bit[11]
		why ?
		研究中 ...
	*/	
	current->flags &= ~PF_MEMALLOC;
	/*
		查看是否有待处理的软中断, 干脆吧 !
		
		如果使用 要用一个 delay flip-flop (Register ) 来替代这个 __softirq_pending 
		不使用 register 而是使用一个bitmap, 这样的架构方式也看出来softirq的地位
		它并不像 IAR register 一样可以从中直接读取触发 Interrupt的 hwirq.
		也许这就是下半部分对时间要求并不像 上半部分那样严格的一个例证吧 .
	
		好了,问题出来了: 为什么不加锁来保护它
		因为 它是 一个是per_cpu变量,  这是 Linux Kernel 的一个很好的特性.:
			struct irq_stat {
				unsigned int irqs[NR_ARCH_IRQS];
			};
			DECLARE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat);
			
			#define local_softirq_pending_ref irq_stat.__softirq_pending
	*/
	pending = local_softirq_pending();
	/*
		一些时间的统计. 
		1 : 统计哪些时间呢 ?
		2 : 为什么要在软中断中来进行这些时间的处理呢 ?
		    是否有这个必要 ? 
		3 : 与 时钟中断中的时间处理有哪些不同 ?.
		1 : 为进程添加系统时间  why ?
			p->stime += cputime;
			
		2 : Add system time to cpustat
		
		3 : Account for system time used	
		研究中 ...
	*/
	account_irq_enter_time(current);
	/*
		软中断数量 + 1.
		它最多能增加到 256 , 
		因为 bit[8:16] 表示软中断的数量.
		不论是 bit[8:16] softirq 
			  bit[17:20] hardirq
		还是 bit[20] NMI
		只要 preempt_count != 0  就关闭了 kernel 抢占.
		
		为什么要关闭抢占 ?
		中断上下文(hardirq context && softirq context ) 不允许被切换出去
		
		为什么不允许被切换出去 ?
		因为 它不是一个 调度实体 (可以想想什么是调度实体), CFS 管不了它呀 !
			
		bit[17:20] 是没有意义的,因为hardirq不允许中断嵌套了.
		一句话 :
			The hardirq count could in theory be the same as the number of interrupts in the system
			kernel中最强大的莫过于 NMI, 没有什么可以阻挡 !!!
	*/
	__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
	/*
		关于trace这块水还挺深 ! 
	*/
	in_hardirq = lockdep_softirq_start();
/*
	你终于来了 !
	为什么这里需要架构成 restart 处理
	无非是softirq处理后 又有softirq被触发了,__soft_pending 又被置位了 还需要处理.
	
	什么是hardirq ?
	它就是系统中的一个事件!(Intel manual 中明确定义)
	什么是softirq ? 
	它就是该 Event 处理的延续 !(我自己的理解 😄 哈哈)
*/	
restart:	
	/*
		为什么要清空 __softirq_pending
		因为下面紧接着要enable hardirq,hardirq可能会被触发, 又有可能置位 __softirq_pending
		且 pending 已经保存了 __softirq_pending 的值.
	*/
	set_softirq_pending(0);
	/*
		这一句话,改变了整个运行的环境 !
		攘外必先安内策略历史上并没有成功吧,又要处理内部的又要盯着外部的,
		在执行软中断的过程中(即 下面的 while 循环)是 enable hardirq的,处理完成后,又会再次disable hardirq,
		深刻体会 hardirq 是要警惕的, 因为它会带来很多不确定性的东西, Kernel 中的搅局者 ! 
	*/
	local_irq_enable();
	/*
		好了,下面会按照优先级从高到底的顺序依次处理了.:
		static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;
		它是一个 全局的. 所有CPU共享的.
		这能说明什么 ?
	*/
	h = softirq_vec;
}

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值