linux是如何支持smp的-welcometoscts&cgcl!_第1頁
已閱讀1頁,還剩25頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、Linux 是如何支持SMP的,陳華才 2006.11,華中科技大學(xué) CGCL&SCTS實驗室,一、三個問題,在SMP機器上,Linux的啟動過程是怎樣的?在SMP機器上,Linux的進程調(diào)度如何進行?在SMP機器中,中斷系統(tǒng)有何特點?,華中科技大學(xué) CGCL&SCTS實驗室,二、Linux啟動過程(基本概念),SMP機器中,有以下幾個基本概念:BSP:也叫BP,是Bootstrap Processor的

2、縮寫,即啟動CPU,在操作系統(tǒng)啟動過程的前期,只有BSP在執(zhí)行指令。AP:Application Processor的縮寫,即應(yīng)用CPU。APIC:高級可編程中斷控制器,分為本地APIC和IO APIC。IPI:處理器間中斷,用于處理器之間的通信。,華中科技大學(xué) CGCL&SCTS實驗室,Linux啟動過程(續(xù)),由于BIOS代碼并不是支持多線程的,所以在SMP中,系統(tǒng)必須讓所有AP進入中斷屏蔽狀態(tài),不與BSP一起執(zhí)

3、行BIOS代碼。為了達到這一目的,可以利用兩種手段:1、利用系統(tǒng)硬件本身進行處理;2、系統(tǒng)硬件與BIOS程序一起處理。在后一種方法中,BIOS程序?qū)⑵渌麬P置于中斷屏蔽狀態(tài),使其休眠,只選擇BSP執(zhí)行BIOS代碼中的后繼部分。BIOS要同時完成對APIC以及其他與MP相關(guān)的系統(tǒng)組件初始化過程,并建立相應(yīng)的系統(tǒng)配置表格,以便操作系統(tǒng)使用。,華中科技大學(xué) CGCL&SCTS實驗室,Linux啟動過程(主要流程),1,BIOS初始化(

4、屏蔽AP,建立系統(tǒng)配置表格)。2,MBR里面的引導(dǎo)程序(Grub,Lilo等)將內(nèi)核加載到內(nèi)存。3,執(zhí)行head.S中的startup_32函數(shù)(最后將調(diào)用start_kernel)。4,執(zhí)行start_kernel,這個函數(shù)相當(dāng)于應(yīng)用程序里面的main,在早期的內(nèi)核中,這個函數(shù)就叫main。5,start_kernel進行一系列初始化,最后將執(zhí)行 smp_init() //啟動各個AP,關(guān)鍵的一

5、步 rest_init() //調(diào)用init()創(chuàng)建1號進程,自身執(zhí)行 cpu_idle()成為0號進程6,1號進程即init進程完成余下的工作。,華中科技大學(xué) CGCL&SCTS實驗室,Linux啟動過程(smp_init()函數(shù)),static void __init smp_init(void) { sm

6、p_boot_cpus(); smp_threads_ready=1; smp_commence(); //讓各AP開始執(zhí)行指令 }smp_boot_cpus()函數(shù)初始化各AP,設(shè)置為待命模式(holding pattern,就是處于等待BSP發(fā)送IPI指令的狀態(tài)),并為之建立0號進程。smp_threads_ready=1表示各AP的idle進程已經(jīng)建立。smp_comm

7、ence()函數(shù)讓各AP開始執(zhí)行指令。注意:在smp機器中,有幾個CPU,就有幾個idle進程(0號進程),但1號進程即init進程只有一個。,華中科技大學(xué) CGCL&SCTS實驗室,Linux啟動過程(smp_boot_cpus()函數(shù)),void __init smp_boot_cpus(void){ for (apicid = 0; apicid = 0) && (max_cpus <= c

8、pucount+1)) continue; //如果超過最大支持范圍,不需要初始化 do_boot_cpu(apicid);// 對每個AP調(diào)用do_boot_cpu函數(shù) }}void __init smp_boot_cpus(void){ init_cpu_to_apicid(); for (bit = 0; bit < BITS_PER_LONG; bit++){ apicid =

9、 cpu_present_to_apicid(bit); if (apicid == BAD_APICID) continue; if (apicid == boot_cpu_apicid) continue; if (!(phys_cpu_present_map & apicid_to_phys_cpu_present(apicid))) continue; do

10、_boot_cpu(apicid); }},華中科技大學(xué) CGCL&SCTS實驗室,Linux啟動過程(do_boot_cpu(cpuid)函數(shù)),static void __init do_boot_cpu (int apicid) // linux/arch/i386/kernel/smpboot.c{ struct task_struct *idle; // 空閑進程結(jié)構(gòu) if (fork_by_ha

11、nd() thread.eip = (unsigned long) start_secondary; // 將空閑進程結(jié)構(gòu)的eip設(shè)置為start_secondary函數(shù)的入口處 start_eip = setup_trampoline(); // 得到trampoline.S代碼的入口地址 stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle); *((

12、volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4; *((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf; // 將trampoline.S的入口地址寫入熱啟動的中斷向量(warm reset vector)40:67 apic_write_

13、around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));// 確定發(fā)送對象 apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); // 發(fā)送INIT IPI apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); //確定發(fā)送對象 apic_wr

14、ite_around(APIC_ICR, APIC_DM_STARTUP | (start_eip >> 12)); //發(fā)送STARTUP IPI} 較新的內(nèi)核中,后面的幾個apic_write_around()放在wakeup_secondary_via_NMI()或wakeup_secondary_via_INIT()中完成,華中科技大學(xué) CGCL&SCTS實驗室,Linux啟動過程(AP的啟

15、動過程),1,AP響應(yīng)IPI中斷,跳轉(zhuǎn)到trampoline.S的入口,裝入gdt和idt,然后跳轉(zhuǎn)到head.s入口執(zhí)行startup_32()函數(shù)。2,startup_32()中有一個ready變量,startup_32()每執(zhí)行一次ready加1,ready初始值為0,所以BSP時ready為1,將跳到start_kernel(),AP時ready大于1,所以AP不會執(zhí)行start_kernel(),而是跳至initializ

16、e_secondary()。3,執(zhí)行initialize_secondary(),轉(zhuǎn)至current->thread.esp,跳至start_secondary()。4,執(zhí)行start_secondary()函數(shù)。,華中科技大學(xué) CGCL&SCTS實驗室,Linux啟動過程(initialize_secondary()函數(shù)),void __init initialize_secondary(void){ as

17、m volatile( "movl %0,%%esp\n\t" "jmp *%1" : :"r" (current->thread.esp),"r" (current->thread.eip));} 以上過程就是設(shè)置好堆棧指針和指令指針,因而函數(shù)返回之后就跳轉(zhuǎn)到了start_secondary()函數(shù)。

18、,華中科技大學(xué) CGCL&SCTS實驗室,Linux啟動過程(start_secondary()函數(shù)),int __init start_secondary(void *unused){ cpu_init(); smp_callin(); while (!atomic_read(&smp_commenced)) rep_nop(); local_flush_tlb(); return cpu_idl

19、e(); // 進入空閑進程}至此,AP啟動完成。,華中科技大學(xué) CGCL&SCTS實驗室,三、Linux進程調(diào)度,基本數(shù)據(jù)結(jié)構(gòu)task_struct:表示一個任務(wù)(進程)。struct task_struct{ volatile long states; //當(dāng)前狀態(tài),包括可運行、可中斷、不可中斷、停止等 long priority; //靜態(tài)優(yōu)先級,實時進程忽略此成員 long nic

20、e; //用戶可以控制的優(yōu)先級 unsigned long rt_priority; //實時進程優(yōu)先級 long counter; //剩余時間片,開始運行時初值等于priority unsigned long policy; //調(diào)度策略,有SCHED_FIFO,SCHED_RR,SCHED_OTHER三種 struct task_struct *next_task,*prev_task; //

21、前(后)一個任務(wù) struct task_struct *next_run,*prev_run; //前(后)一個可運行任務(wù) unsigned short uid,gid,euid,egid; //用戶id,組id,有效用戶id,有效組id int pid; //進程號 struct thread_struct thread; //保存執(zhí)行環(huán)境,包括一些寄存器內(nèi)容 struct mm_struct *

22、mm; //內(nèi)存結(jié)構(gòu) int processor; //正在使用的CPU int last_processor; //上次使用的CPU int lock_depth; //內(nèi)核鎖的深度},華中科技大學(xué) CGCL&SCTS實驗室,Linux進程調(diào)度(續(xù)),與task_struct有關(guān)的全局變量:task[NR_TASKS]:所有進程包括0號進程的數(shù)組,構(gòu)成一個雙向循環(huán)鏈表,表頭是BSP的0號進程,

23、即init_task。init_tasks[NR_CPUS]:所有CPU的0號進程的數(shù)組,構(gòu)成一個鏈表,它是上一個鏈表的子鏈表,調(diào)度器通過idle_task(cpu)宏來訪問這些idle進程。runqueue_head:所有就緒進程(狀態(tài)為可運行的進程)構(gòu)成一個鏈表,表頭是runqueue_head。current:表示當(dāng)前CPU 的當(dāng)前進程。此圖顯示了task和i

24、nit_tasks的關(guān)系,注意BSP的0號進程叫init_task而不是idle_task,但這個init_task不是1號進程init。,華中科技大學(xué) CGCL&SCTS實驗室,Linux進程調(diào)度(續(xù)),基本數(shù)據(jù)結(jié)構(gòu)schedule_data:表示一個CPU。static union { struct schedule_data { struct task_struct * curr; //此CPU上的當(dāng)

25、前進程 cycles_t last_schedule; //此CPU上次進程切換的時間 } schedule_data; char __pad [SMP_CACHE_BYTES];}這種union被組織在一個叫aligned_data [NR_CPUS]的數(shù)組中,每個元素代表一個CPU。,華中科技大學(xué) CGCL&SCTS實驗室,Linux進程調(diào)度(續(xù)),進程調(diào)度有關(guān)的主要函數(shù)和宏:schedu

26、le():進程調(diào)度的主函數(shù)。switch_to():schedule()中調(diào)用,進行上下文切換的宏。reschedule_idle():在SMP系統(tǒng)中,如果被切換下來的進程仍然是可運行的,則調(diào)用reschedule_idle()重新調(diào)度,以選擇一個空閑的或運行著低優(yōu)先級進程的CPU來運行這個進程。goodness():優(yōu)先級計算函數(shù),選擇一個最合適的進程投入運行。,華中科技大學(xué) CGCL&SCTS實驗室,Linux進

27、程調(diào)度(續(xù)),schedule()函數(shù)的主要工作:1,從移走進程processor域讀取cpu標(biāo)識,存入局部變量this_cpu。2,初始化sched_data變量,指向當(dāng)前處理器schedule_data結(jié)構(gòu)。 3,調(diào)用goodness()函數(shù)選取進程,對于上一次也在當(dāng)前處理器的進程加上PROC_CHANGE_PENALTY的優(yōu)先權(quán)。4,如果必要,重新計算動態(tài)優(yōu)先權(quán)。5,設(shè)置sched_data->last_

28、schedule值為當(dāng)前時間。6,調(diào)用switch_to()宏執(zhí)行切換。7,調(diào)用schedule_tail(),如果傳入的prev進程仍是可運行的而且不是空閑進程,schedule_tail調(diào)用reschedule_idle()來選擇一個合適的處理器。,華中科技大學(xué) CGCL&SCTS實驗室,Linux進程調(diào)度(續(xù)),switch_to(prev,next,last)的工作:1,將esi,edi,ebp壓入堆棧。

29、2,堆棧指針esp保存到prev->thread.esp。3,將esp恢復(fù)為next->thread.esp。4,將標(biāo)號1:的地址保存到prev->thread.eip。5,將next->eip壓入堆棧。6,無條件跳轉(zhuǎn)到__switch_to()函數(shù),切換LDT和fs,gs等寄存器,由于有了上一步的工作,因此本函數(shù)返回時已經(jīng)切換到了next的上下文。7,switch_to()中jmp指令以后的

30、代碼即標(biāo)號1:的代碼作的工作與第一步相反,即從堆棧彈出ebp,edi和esi。這部分的代碼是下次該進程運行時最先執(zhí)行的代碼。,華中科技大學(xué) CGCL&SCTS實驗室,Linux進程調(diào)度(續(xù)),圖解進程切換 prevs

31、chedule() next,………..………..………..時鐘中斷發(fā)生………..………..………..,………………………………上次切換產(chǎn)生的斷點 ………………………………,schedule{ ……. switch_to(){ esi,ebi,ebp入棧 保存e

32、sp 恢復(fù)esp 保存標(biāo)號1: 地址 next->eip入棧 jmp __switch_to1: ebp,edi,esi出棧 } ……},華中科技大學(xué) CGCL&SCTS實驗室,Linux進程調(diào)度(續(xù)),reschedule_idle()的工作過程:1,先檢查p進程上一次運行的cpu是否空閑,如果空閑,這是最好的cpu,直接返回。 2,找

33、一個合適的cpu,查看SMP中的每個CPU上運行的進程,與p進程相比的搶先權(quán),把具有最高的搶先權(quán)值的進程記錄在target_task中,該進程運行的cpu為最合適的CPU。 3,如target_task為空,說明沒有找到合適的cpu,直接返回。 4,如果target_task不為空,則說明找到了合適的cpu,因此將target_task->need_resched置為1,如果運行target_task的cpu不是當(dāng)前運行的

34、cpu,則向運行target_task的cpu發(fā)送一個IPI中斷,讓它重新調(diào)度。,華中科技大學(xué) CGCL&SCTS實驗室,四、Linux中斷系統(tǒng),,華中科技大學(xué) CGCL&SCTS實驗室,Linux中斷系統(tǒng)(續(xù)),本地APIC的作用:1,接收理本地外部中斷(直接連在LINTIN 0/1上的設(shè)備)。2,接收本地內(nèi)部中斷(除法錯誤等軟件上的中斷)。3,接收來自IO APIC的中斷。IO APIC的作用:1,接收系

35、統(tǒng)總線上的IPI消息。2,接收外部設(shè)備的中斷。3,將接收到的中斷分發(fā)給本地APIC。注意:1,外設(shè)可以通過LINTIN0/1直接連在某一個本地APIC上,不經(jīng)過IO APIC。2,處理器間中斷先由IO APIC接收,然后分發(fā)給相應(yīng)的本地APIC。這似乎暗示著中斷的分發(fā)策略完全是IO APIC的事情,本地APIC只是接收從IO APIC發(fā)過來的中斷,并不區(qū)分是IPI還是外部中斷。IO APIC的作用類似于以太網(wǎng)交換機。,華中科

36、技大學(xué) CGCL&SCTS實驗室,Linux中斷系統(tǒng)(續(xù)),Linux啟動過程中有一步是調(diào)用函數(shù)init_IRQ,作用是初始化各個中斷向量。init_IRQ中,調(diào)用set_intr_gate(unsigned int n, void *addr)函數(shù)注冊中斷向量,n表示中斷向量號,addr是中斷響應(yīng)函數(shù)的名字(地址)。各種跟SMP相關(guān)的中斷的入口函數(shù)是基本相同的,Linux提供了BUILD_SMP_INTERRUPT(x

37、,v)宏來完成中斷入口函數(shù)的定義和中斷響應(yīng)函數(shù)的聲明,時鐘中斷入口函數(shù)的處理稍有不同,使用的是BUILD_SMP_TIMER_INTERRUPT(x,v)宏,x是中斷響應(yīng)函數(shù)的名字,v是中斷向量號。中斷入口函數(shù)名是call_前綴加上入口函數(shù)的名字,如:apic_timer_interrupt是時鐘中斷響應(yīng)函數(shù),對應(yīng)的入口函數(shù)是call_apic_timer_interrupt。SMP系統(tǒng)的中斷響應(yīng)函數(shù)通常還需要加上smp_前綴,如smp

38、_apic_timer_interrupt。,華中科技大學(xué) CGCL&SCTS實驗室,Linux中斷系統(tǒng)(續(xù)),Linux針對IA32的SMP系統(tǒng)定義了五種主要的IPI:1, CALL_FUNCTION_VECTOR:發(fā)往自己除外的所有CPU,強制它們執(zhí)行指定的函數(shù);2, RESCHEDULE_VECTOR:使被中斷的CPU重新調(diào)度;3, INVLIDATE_TLB_VECTOR:使被中斷的CPU廢棄自己的TLB緩存

39、內(nèi)容。4, ERROR_APIC_VECTOR:錯誤中斷。5, SPUROUS_APIC_VECTOR:假中斷。,華中科技大學(xué) CGCL&SCTS實驗室,Linux中斷系統(tǒng)(續(xù)),發(fā)送IPI的函數(shù)主要有4個,分別是: send_IPI_self(int vector);發(fā)送IPI給自己,中斷類型由vector指定。 send_IPI_mask(int mask,int vector);發(fā)送IPI給某一個或某幾個C

40、PU,發(fā)送目標(biāo)由掩碼mask決定,中斷類型由vector決定。 send_IPI_all(int vector);發(fā)送IPI給所有CPU,參數(shù)意義同上。 send_IPI_allbutself(int vector);發(fā)送IPI給除自己以外的所有CPU,參數(shù)意義同上。早期曾經(jīng)存在一個發(fā)送給單個CPU的send_IPI_single的函數(shù),在IA32體系中現(xiàn)已廢棄。,華中科技大學(xué) CGCL&SCTS實驗室,五、結(jié)論,L

41、inux對SMP的支持主要體現(xiàn)在三個方面:啟動過程:BSP負責(zé)操作系統(tǒng)的啟動,在啟動的最后階段,BSP通過IPI激活各個AP,在系統(tǒng)的正常運行過程中,BSP和AP基本上是無差別的。進程調(diào)度:與UP系統(tǒng)的主要差別是執(zhí)行進程切換后,被換下的進程有可能會換到其他CPU上繼續(xù)運行。在計算優(yōu)先權(quán)時,如果進程上次運行的CPU也是當(dāng)前CPU,則會適當(dāng)提高優(yōu)先權(quán),這樣可以更有效地利用Cache。中斷系統(tǒng):為了支持SMP,在硬件上需要APIC

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 眾賞文庫僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論