Linux任务切换软硬件机制

前言

简单介绍下 Linux0.11 及 Linux 2.6 的任务切换机制

参考资料:
保护方式下的 80386 及其编程
《Linux 内核完全注释》
《深入理解 Linux 内核》

概念

任务切换的概念可参考之前写的 C51 单片机上的任务切换
大致如下图
Linux任务切换软硬件机制_第1张图片

即:
任务 1 在内存中保存有其硬件上下文
任务 2 在内存中保存有其硬件上下文

假设当前任务 1 在运行,现要执行任务 2
所谓任务切换就是将当前硬件上下文件,保存到任务 1 内存中,然后加载任务 2 的硬件上下文继续运行

x86 任务切换

TSS

针对 x86, 这是款高级货,当前任务的硬件上下文多,如果像 C51 一样手动 pop/push 速度慢,这时候为了增加切换速度,
直接将相关切换流程硬件标准化了,他通过一个 TSS 保存了当前任务的硬件上下文,直接通过切换 TSS 来触发硬件上下文保存切换加载工作
Linux任务切换软硬件机制_第2张图片
Linux任务切换软硬件机制_第3张图片

Linux任务切换软硬件机制_第4张图片
Linux任务切换软硬件机制_第5张图片

任务切换

切换 TSS 可以通过任务门来实现,所谓任务门,就是一个类似指向 TSS 描述符的指针,通过跳转等命令触发切换操作
Linux任务切换软硬件机制_第6张图片

辞旧迎新操作流程:
Linux任务切换软硬件机制_第7张图片
Linux任务切换软硬件机制_第8张图片

Linux 任务中切换

任务切换吧,因为 x86 任务切换要经过 TSS,所以 0.11 跟 2.4 切换细节上主要在任务的组织上

Linux0.11 的任务切换

Linux任务切换软硬件机制_第9张图片
Linux任务切换软硬件机制_第10张图片

可以看到, Linux0.11 上任务使用 64M 地址空间,在 4G 的地址每个任务占用的线性地址位置不一样,体现在 GDT 表中就如下所示:

Linux任务切换软硬件机制_第11张图片

每个任务都有自己独有的 LDT+TSS ,所以任务切换就是跳转到不同的 TSS 上执行就好了
实现上就如下所示:

	/*
	* switch_to(n)将切换当前任务到任务nr,即n。首先检测任务n 不是当前任务,
	* 如果是则什么也不做退出。如果我们切换到的任务最近(上次运行)使用过数学
	* 协处理器的话,则还需复位控制寄存器cr0 中的TS 标志。
	*/
	// 输入:%0 - 新TSS 的偏移地址(*&__tmp.a); %1 - 存放新TSS 的选择符值(*&__tmp.b);
	// dx - 新任务n 的选择符;ecx - 新任务指针task[n]。
	// 其中临时数据结构__tmp 中,a 的值是32 位偏移值,b 为新TSS 的选择符。在任务切换时,a 值
	// 没有用(忽略)。在判断新任务上次执行是否使用过协处理器时,是通过将新任务状态段的地址与
	// 保存在last_task_used_math 变量中的使用过协处理器的任务状态段的地址进行比较而作出的。
	#define switch_to(n) {\
	struct {long a,b;} __tmp; \
	__asm__( "cmpl %%ecx,_current\n\t" \	// 任务 n 是当前任务吗?(current ==task[n]?)
	  "je 1f\n\t" \							// 是,则什么都不做,退出。
	  "movw %%dx,%1\n\t" \					// 将新任务的选择符【TSS】-->*&__tmp.b。
	  "xchgl %%ecx,_current\n\t" \			// current = task[n];【ecx = 被切换出的任务。】
	  "ljmp %0\n\t" \						// 执行长跳转至*&__tmp,造成任务切换。
	  
	// 在任务切换回来后才会继续执行下面的语句。
	  "cmpl %%ecx,_last_task_used_math\n\t" \	// 新任务上次使用过协处理器吗?
	  "jne 1f\n\t" \							// 没有则跳转,退出。
	  "clts\n" \								// 新任务上次使用过协处理器,则清cr0 的TS 标志。
	  "1:"::"m" (*&__tmp.a), "m" (*&__tmp.b),
	  "d" (_TSS (n)), "c" ((long) task[n]));
	}

简单直接,找到新任务的 TSS 位置,然后 ljmp 跳过去就切换好了

Linux2.6 的任务切换

Linux0.11 上不同任务使用不同的 TSS/LDT 有一个问题,那就是 GDT 表格大小是有限的,所以支持的任务数量受很大限制
所以后面就不用这种方式了,但是 TSS/LDT 在 x86 上进行任务切换跳不过去,必须要用,那怎么办呢?
好办,每 CPU 一个的 TSS/LDT, 大家共享,不同任务有区别的部分大家各自保存,在任务切换函数中修改共享的 TSS/LDT 就好了

Linux任务切换软硬件机制_第12张图片

整体流程就变成了下面这样:
Linux任务切换软硬件机制_第13张图片

你可能感兴趣的:(Linux,Linux,任务切换,Switch_to)