switch_to()负责从上一个进程的处理器状态切换到新进程的处理器状态
15 #define switch_to(prev,next,last) do { 16 unsigned long esi,edi; 17 asm volatile("pushfl " 18 "pushl %%ebp " 19 "movl %%esp,%0 " /* save ESP */ 20 "movl %5,%%esp " /* restore ESP */ 21 "movl $1f,%1 " /* save EIP */ 22 "pushl %6 " /* restore EIP */ 23 "jmp __switch_to " 24 "1: " 25 "popl %%ebp" 26 "popfl" 27 :"=m" (prev->thread.esp),"=m" (prev->thread.eip), 28 "=a" (last),"=S" (esi),"=D" (edi) 29 :"m" (next->thread.esp),"m" (next->thread.eip), 30 "2" (prev), "d" (next)); 31 } while (0)
注: 在内核代码中当需要访问当前进程的task_struct结构时使用的指针current实际上是个宏定义,它是根据当前进程的堆栈指针ESP计算出来的
第一步 pushfl pushl %%ebp 进程prev的内核堆栈 | | | | |-----------| | eflags | | ebp | %%esp-->| | 第二步 movl %%esp,%0 //prev->thraad.esp(%0) 进程prev的内核堆栈 | | | | |-----------| | eflags | (%%esp) | ebp | prev->thread.esp-->| | 第三步 movl %5,%%esp //next->thread.esp(%5) 进程next的内核堆栈 | | | | | | | eflags | | ebp | %%esp-->| | (next->thread.esp) 第四步 movl $1f,%1 //prev->thread.eip(%1) prev->thread.eip = (第25行的地址) 作为进程prev下一次被调度运行时的“返回地址” 第五步 pushl %6 //next->thread.eip(%6) 进程next的内核堆栈 | | | | | | |eflags | |ebp | |next->thread.eip| %%esp-->| | 将next->thread.eip压入堆栈(next的内核堆栈?):这里的next->thread.eip正是 进程next上一次被调离时在第21行中保存的。它也执行这里的标号"1", 即25行的popl指令 |
|