进程切换switch_to()注释

进程切换前须要作准备工做,其中对于内核进程和用户进程在切换地址空间中的处理方式是不一样的,主要由于内核进程只使用内核地址空间,而linux的内核地址空间是固定的,但用户进程就不同了,而内核会借用用户的地址空间,mm_struct中的页表信息在tlb中是有缓存的,这一起的刷新问题必须保持一致性,推荐两篇文章,写得很好,对这个问题说得很清楚。linux

《Linux TLB 刷新的懒惰模式》缓存

http://blog.csdn.net/Henzox/article/details/41963271函数

这篇文章主要讲述了在SMP处理器上,每一个cpu有本身的tlb,在一个cpu借用某个用户进程的内存空间的时候,这个用户进程可能在另外一个cpu上被调度执行,有可能引发这个进程内存空间的变化,tlb数据会失效,为了保持一致性,会向引用这个内存空间的cpu发送IPI消息通知其刷新对应的tlb条目。Task_struct中记录cpu对其mm_struct引用的信息存储在cpu_vm_mask中,最多支持32cpu信息记录,TLBSTATE_LAZY模式下,cpu处理IPI消息时,将该cpu对应位的掩码清除,不刷新tlb,下次IPI消息就不回发送到本身这里了。优化

《尝试总结memory barrier (经典)》spa

http://blog.csdn.net/zhangxinrun/article/details/5843632.net

这篇文章主要讲现代cpu在乱序执行以及编译优化,和JIT等技术使得cpu在真正执行指令的时候可能并不如同你写代码的时候的串行执行,加入内存壁障的做用就是防止gcc编译器对代码的优化,总的实现功能主要是保证内存壁障以前的写操做作完,内存壁障以后的读代码都从内存中从新读取数据。debug

内存壁障在x86上的实现方式是lock总线,这会使得全部cpulock涉及到的指令操做的数据的cache都失效,而lock会致使当前cpu将其cache写入内存,经过(BUS-Watching)技术,其余cpu会使有对应数据的cache失效,即下一次访问的时候必须从内存取。经过MESI协议,保持缓存一致性。指针

寄存器信息的切换源码rest

 1 #define switch_to(prev,next,last) do {                    \
 2     asm volatile(
 3         "pushl %%esi\n\t"                    \
 4         "pushl %%edi\n\t"                    \
 5         "pushl %%ebp\n\t"                    \
 6         "movl %%esp,%0\n\t"    /* save ESP */        \
 7         "movl %3,%%esp\n\t"    /* restore ESP */    \
 8         "movl $1f,%1\n\t"        /* save EIP */        \
 9         "pushl %4\n\t"        /* restore EIP */    \
10         "jmp __switch_to\n"                \
11         "1:\t"                        \
12         "popl %%ebp\n\t"                    \
13         "popl %%edi\n\t"                    \
14         "popl %%esi\n\t"                    \
15         :"=m" (prev->thread.esp), "=m" (prev->thread.eip), \
16         "=b" (last)                    \
17         :"m" (next->thread.esp), "m" (next->thread.eip), \
18         "a" (prev), "d" (next), \
19         "b" (prev));                    \
20 } while (0)

 

 

esiediebpesp存入task_struct中,并将1:开始处做为eip保存,下次找个进程被调度的时候,ret返回后就从这里开始执行。code

加载新进程的esp,eip压栈,这个eip实际上对应的就是上次本身被调度离开的时候存储的1:的位置,因此等最后ret返回的时候就从这里开始执行,恢复ebpediesi,彻底恢复进程。

__switch_toFASTCALL标记,则这个函数的参数会在eaxedx中取,即对应prevnext

__switch_to保存prevfpufsgs段,清空可能的io权限位图bitmap,将next进程的内核栈指针,fsgs,可能的debug寄存器信息,并设置其io权限位图bitmap

接下来就是内存管理了,仍是挺快的。

相关文章
相关标签/搜索