0
点赞
收藏
分享

微信扫一扫

内核进程切换

凛冬已至夏日未远 2022-02-20 阅读 101
linux

调度器在进程调度的时候,主要实现两个功能:

进程切换总结为两步:

(1)切换进程的进程地址空间。将 next进程的页表切换到硬件页表中,由switch_mm实现。

(2)切换next进程的内核栈和硬件上下文。由switch_to函数实现,硬件上下文提供了内核执行next进程的所有硬件信息。

switch_mm

switch_mm是将新进程的页表基地址设置到页表基地址寄存器,刷新TLB及设置硬件页表。

如何提高TLB的性能?对于TLB来说,可以分为全局和进程独有两种类型。为了支持进程独有类型的TLB,ARM提出了一种硬件解决方案ASID(Address Space ID),这样TLB就可以识别哪些TLB属于某个进程,每个TLB都包含一个ASID。ASID机制从硬件上保证了进程切换时TLB不会出现冲突。

switch_to

#define switch_to(prev, next, last)					\
	do {								\
		((last) = __switch_to((prev), (next)));			\
	} while (0)

#endif

第一个参数表示将要被调度出去的进程prev,第二个参数表示将要被调度进来的进程next,第三个参数表示需要对prev进程进行清理,也就是传入prev进程。

/*
 * Thread switching.
 */
__notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
				struct task_struct *next)
{
	struct task_struct *last;

	fpsimd_thread_switch(next);
	tls_thread_switch(next);
	hw_breakpoint_thread_switch(next);
	contextidr_thread_switch(next);
	entry_task_switch(next);
	ssbs_thread_switch(next);
	erratum_1418040_thread_switch(next);
	ptrauth_thread_switch_user(next);

	// 完成这个CPU上任何悬而未决的TLB或缓存维护,
    // 以防线程迁移到不同的CPU上。这个全屏障也是membarrier系统调用所要求的。
	
	dsb(ish);

	/*
	 * MTE thread switching must happen after the DSB above to ensure that
	 * any asynchronous tag check faults have been logged in the TFSR*_EL1
	 * registers.
	 */
	mte_thread_switch(next);
	/* avoid expensive SCTLR_EL1 accesses if no change */
	if (prev->thread.sctlr_user != next->thread.sctlr_user)
		update_sctlr_el1(next->thread.sctlr_user);

	/* the actual thread switch */
	last = cpu_switch_to(prev, next);

	return last;
}

cpu_context

cpu_context保存了硬件上下文信息,进程切换时,我们需要将prev进程的x19-x28寄存器以及fp,sp和pc寄存器内容保存到cpu_context结构中,然后把next进程上一次保存的数据恢复到实际硬件的寄存器中,这样就完成了进程的上下文切换。

struct cpu_context {
	unsigned long x19;
	unsigned long x20;
	unsigned long x21;
	unsigned long x22;
	unsigned long x23;
	unsigned long x24;
	unsigned long x25;
	unsigned long x26;
	unsigned long x27;
	unsigned long x28;
	unsigned long fp;
	unsigned long sp;
	unsigned long pc;
};
举报

相关推荐

0 条评论