Wirte by 021.
E_Thread
K_THREAD
- 线程结构体
1 | 结构体 |
线程状态不同存储
1
2
3
4
5
6正在运行线程 --- kpcr
等待线程 --- 等待链表
就绪/调度线程 --- 32个链表
线程的生命周期
创建 — 初始化线程变量
1
2
3
4
5
6
7
8
9
10
111,结构体初始化赋值
2,执行体,函数,参数,赋值
7, kernelStack 栈顶 赋值,esp 赋值。
kernelStack = 入栈对象 (1-6)
创建堆栈
1
2
3
4
5创建堆栈,申请堆栈 stackpage , 0x80000 大小,
4,堆栈初始化,起始地址、
5,设定堆栈边界值(终止地址)
寄存器入栈
1
6, 入栈
线程切换 SwapContext
- 线程不是被动切换,而是主动切换。 意思是,无论是时间片到了的被动切换,还是线程IO阻塞主动出让执行权,都需要当前线程调用切换线程函数.
- 线程没有使用TSS保存寄存器,而是使用堆栈.
- 线程切换过程就是堆栈切换过程.
- 在线程切换过程中,会判断2个线程是否属于同一个进程,如果不是,就切换cr3页面,也就是进程空间也切换了.
TheadSwap
1
2
3
4
5
6
7参数 : 1,当前线程(esp)地址, 2,将要被切换线程(edi)地址
步骤:
1,保存当前线的栈顶,上图的push操作.
2,将当前线程(esp)地址,存储到KernelStack中 --- mov [esi kernelStack] ,esp
3,将内核中 将要被切换edi线程 的地址,交换到当前位置 --- mov esp, [edi kernelStack]主动切换
1
取出当前CPU kpcr正在执行的线程放到edi中
线程中断
时钟中断
线程中断条件
1
2
31.时间片到期
2,备用线程(KPCR.PrcbData.nextThread)
3,主动调用切换切换线程函数,KiswapThreadCPU时间片
1
2
3
4
51,KPROCESS.ThreadQuantum 值是当前进程设置的时间片值
2,_KTHREAD.ThreadQuantum 会读取 KPROCESS.ThreadQuantum的值,在线程初始化的时候
在win32里面初始为6,每次中断会调用KeupdateRuntime函数会将当前线程_KTHREAD.ThreadQuantum - 3,如果减到0,则将
KPCR.PrcbData.QuantumEnd 位 置为 非0,表示当前线程时间片到期.
Tss
内核堆栈
1
2
3
4
5initStack 栈底
kernelStack 栈顶
stackLimte 边界
TSS.esp0得到当前线程0环堆栈,线程在切换的时候保证0环线程堆栈的唯一和有序性.
异常中断
1
INT N, 页面异常
如何永久占用CPU?
1
满足 不调用API , 并且不会出现异常,并调用cli指令,屏蔽时间中断,CPU就会忽略时钟片中断.
线程优先级
线程调度链表
1
2
3
4
532个线程调度双向链表。
KiFindReadyThread 查找方式: 先找 31 ... 30 .. 29, 优先查找高级别的。
32位:
0 1 0 1 0 0 0 0 ... 0 , 31位上为1,证明当前有优先级的线程需要处理。
当调度链表中没有任何需要调度执行的任务时,cpu会执行idelThread.