進程切換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

接下來就是內存管理了,仍是挺快的。

相關文章
相關標籤/搜索