0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

揭開Linux內(nèi)核進程上下文切換的神秘面紗

Linux閱碼場 ? 來源:Linuxer ? 作者:Linuxer ? 2020-10-10 16:25 ? 次閱讀

作者簡介

韓傳華,就職于南京大魚半導體有限公司,主要從事linux相關(guān)系統(tǒng)軟件開發(fā)工作,負責Soc芯片BringUp及系統(tǒng)軟件開發(fā),樂于分享喜歡學習,喜歡專研Linux內(nèi)核源代碼。

我都知道操作系統(tǒng)的一個重要功能就是進行進程管理,而進程管理就是在合適的時機選擇合適的進程來執(zhí)行,在單個cpu運行隊列上各個進程宏觀并行微觀串行執(zhí)行,多個cpu運行隊列上的各個進程之間完全的并行執(zhí)行。進程管理是個復雜的過程,例如進程的描述、創(chuàng)建和銷毀、生命周期管理、進程切換、進程搶占、調(diào)度策略、負載均衡等等。本文主要關(guān)注進程管理的一個切入點,那就是進程的上下文切換,來理解linux內(nèi)核是如何進程進程上下文切換的,從而揭開上下文切換的神秘面紗。
(注意:本文以linux-5.0內(nèi)核源碼講解,采用arm64架構(gòu))

本文目錄:
1.進程上下文的概念
2.上下文切換詳細過程
2.1 進程地址空間切換
2.2 處理器狀態(tài)(硬件上下文)切換
3.ASID機制
4.普通用戶進程、普通用戶線程、內(nèi)核線程切換的差別
5.進程切換全景視圖
6.總結(jié)

1.進程上下文的概念

進程上下文是進程執(zhí)行活動全過程的靜態(tài)描述。我們把已執(zhí)行過的進程指令和數(shù)據(jù)在相關(guān)寄存器與堆棧中的內(nèi)容稱為進程上文,把正在執(zhí)行的指令和數(shù)據(jù)在寄存器與堆棧中的內(nèi)容稱為進程正文,把待執(zhí)行的指令和數(shù)據(jù)在寄存器與堆棧中的內(nèi)容稱為進程下文。

實際上linux內(nèi)核中,進程上下文包括進程的虛擬地址空間和硬件上下文。

進程硬件上下文包含了當前cpu的一組寄存器的集合,arm64中使用task_struct結(jié)構(gòu)的thread成員的cpu_context成員來描述,包括x19-x28,sp, pc等。

如下為硬件上下文存放示例圖:

2.上下文切換詳細過程

進程上下文切換主要涉及到兩部分主要過程:進程地址空間切換和處理器狀態(tài)切換。地址空間切換主要是針對用戶進程而言,而處理器狀態(tài)切換對應于所有的調(diào)度單位。下面我們分別看下這兩個過程:

__schedule // kernel/sched/core.c->context_switch ->switch_mm_irqs_off //進程地址空間切換 ->switch_to //處理器狀態(tài)切換

2.1 進程地址空間切換

進程地址空間指的是進程所擁有的虛擬地址空間,而這個地址空間是假的,是linux內(nèi)核通過數(shù)據(jù)結(jié)構(gòu)來描述出來的,從而使得每一個進程都感覺到自己擁有整個內(nèi)存的假象,cpu訪問的指令和數(shù)據(jù)最終會落實到實際的物理地址,對用進程而言通過缺頁異常來分配和建立頁表映射。進程地址空間內(nèi)有進程運行的指令和數(shù)據(jù),因此到調(diào)度器從其他進程重新切換到我的時候,為了保證當前進程訪問的虛擬地址是自己的必須切換地址空間。
實際上,進程地址空間使用mm_struct結(jié)構(gòu)體來描述,這個結(jié)構(gòu)體被嵌入到進程描述符(我們通常所說的進程控制塊PCB)task_struct中,mm_struct結(jié)構(gòu)體將各個vma組織起來進行管理,其中有一個成員pgd至關(guān)重要,地址空間切換中最重要的是pgd的設(shè)置。

pgd中保存的是進程的頁全局目錄的虛擬地址(本文會涉及到頁表相關(guān)的一些概念,在此不是重點,不清楚的可以查閱相關(guān)資料,后期有機會會講解進程頁表),記住保存的是虛擬地址,那么pgd的值是何時被設(shè)置的呢?答案是fork的時候,如果是創(chuàng)建進程,需要分配設(shè)置mm_struct,其中會分配進程頁全局目錄所在的頁,然后將首地址賦值給pgd。

我們來看看進程地址空間究竟是如何切換的,結(jié)果會讓你大吃一驚(這里暫且不考慮asid機制,后面有機會會在其他文章中講解):
代碼路徑如下:

context_switch // kernel/sched/core.c->switch_mm_irqs_off ->switch_mm ->__switch_mm ->check_and_switch_context ->cpu_switch_mm ->cpu_do_switch_mm(virt_to_phys(pgd),mm) //arch/arm64/include/asm/mmu_context.h arch/arm64/mm/proc.S158 /*159 * cpu_do_switch_mm(pgd_phys, tsk)160 *161 * Set the translation table base pointer to be pgd_phys.162 *163 * - pgd_phys - physical address of new TTB164 */165 ENTRY(cpu_do_switch_mm)166 mrs x2, ttbr1_el1167 mmid x1, x1 // get mm->context.id168 phys_to_ttbr x3, x0169170 alternative_if ARM64_HAS_CNP171 cbz x1, 1f // skip CNP for reserved ASID172 orr x3, x3, #TTBR_CNP_BIT173 1:174 alternative_else_nop_endif175 #ifdef CONFIG_ARM64_SW_TTBR0_PAN176 bfi x3, x1, #48, #16 // set the ASID field in TTBR0177 #endif178 bfi x2, x1, #48, #16 // set the ASID179 msr ttbr1_el1, x2 // in TTBR1 (since TCR.A1 is set)180 isb181 msr ttbr0_el1, x3 // now update TTBR0182 isb183 b post_ttbr_update_workaround // Back to C code...184ENDPROC(cpu_do_switch_mm)

代碼中最核心的為181行,最終將進程的pgd虛擬地址轉(zhuǎn)化為物理地址存放在ttbr0_el1中,這是用戶空間的頁表基址寄存器,當訪問用戶空間地址的時候mmu會通過這個寄存器來做遍歷頁表獲得物理地址(ttbr1_el1是內(nèi)核空間的頁表基址寄存器,訪問內(nèi)核空間地址時使用,所有進程共享,不需要切換)。完成了這一步,也就完成了進程的地址空間切換,確切的說是進程的虛擬地址空間切換。

內(nèi)核處理的是不是很簡單,很優(yōu)雅,別看只是設(shè)置了頁表基址寄存器,也就是將即將執(zhí)行的進程的頁全局目錄的物理地址設(shè)置到頁表基址寄存器,他卻完成了地址空間切換的壯舉,有的小伙伴可能不明白為啥這就完成了地址空間切換?試想如果進程想要訪問一個用戶空間虛擬地址,cpu的mmu所做的工作,就是從頁表基址寄存器拿到頁全局目錄的物理基地址,然后和虛擬地址配合來查查找頁表,最終找到物理地址進行訪問(當然如果tlb命中就不需要遍歷頁表),每次用戶虛擬地址訪問的時候(內(nèi)核空間共享不考慮),由于頁表基地址寄存器內(nèi)存放的是當前執(zhí)行進程的頁全局目錄的物理地址,所以訪問自己的一套頁表,拿到的是屬于自己的物理地址(實際上,進程是訪問虛擬地址空間的指令數(shù)據(jù)的時候不斷發(fā)生缺頁異常,然后缺頁異常處理程序為進程分配實際的物理頁,然后將頁幀號和頁表屬性填入自己的頁表條目中),就不會訪問其他進程的指令和數(shù)據(jù),這也是為何多個進程可以訪問相同的虛擬地址而不會出現(xiàn)差錯的原因,而且做到的各個地址空間的隔離互不影響(共享內(nèi)存除外)。

其實,地址空間切換過程中,還會清空tlb,防止當前進程虛擬地址轉(zhuǎn)化過程中命中上一個進程的tlb表項,一般會將所有的tlb無效,但是這會導致很大的性能損失,因為新進程被切換進來的時候面對的是全新的空的tlb,造成很大概率的tlb miss,需要重新遍歷多級頁表,所以arm64在tlb表項中增加了非全局(nG)位區(qū)分內(nèi)核和進程的頁表項,使用ASID區(qū)分不同進程的頁表項,來保證可以在切換地址空間的時候可以不刷tlb,后面會主要講解ASID技術(shù)。

還需要注意的是僅僅切換用戶地址空間,內(nèi)核地址空間由于是共享的不需要切換,也就是為何切換到內(nèi)核線程不需要也沒有地址空間的原因。

如下為進程地址空間切換示例圖:

2.2 處理器狀態(tài)(硬件上下文)切換

前面進行了地址空間切換,只是保證了進程訪問指令數(shù)據(jù)時訪問的是自己地址空間(當然上下文切換的時候處于內(nèi)核空間,執(zhí)行的是內(nèi)核地址數(shù)據(jù),當返回用戶空間的時候才有機會執(zhí)行用戶空間指令數(shù)據(jù)**,地址空間切換為進程訪問自己用戶空間做好了準備**),但是進程執(zhí)行的內(nèi)核棧還是前一個進程的,當前執(zhí)行流也還是前一個進程的,需要做切換。

arm64中切換代碼如下:

switch_to->__switch_to ... //浮點寄存器等的切換 ->cpu_switch_to(prev, next) arch/arm64/kernel/entry.S:1032 /*1033 * Register switch for AArch64. The callee-saved registers need to be saved1034 * and restored. On entry:1035 * x0 = previous task_struct (must be preserved across the switch)1036 * x1 = next task_struct1037 * Previous and next are guaranteed not to be the same.1038 *1039 */1040 ENTRY(cpu_switch_to)1041 mov x10, #THREAD_CPU_CONTEXT1042 add x8, x0, x101043 mov x9, sp1044 stp x19, x20, [x8], #16 // store callee-saved registers1045 stp x21, x22, [x8], #161046 stp x23, x24, [x8], #161047 stp x25, x26, [x8], #161048 stp x27, x28, [x8], #161049 stp x29, x9, [x8], #161050 str lr, [x8]1051 add x8, x1, x101052 ldp x19, x20, [x8], #16 // restore callee-saved registers1053 ldp x21, x22, [x8], #161054 ldp x23, x24, [x8], #161055 ldp x25, x26, [x8], #161056 ldp x27, x28, [x8], #161057 ldp x29, x9, [x8], #161058 ldr lr, [x8]1059 mov sp, x91060 msr sp_el0, x11061 ret1062 ENDPROC(cpu_switch_to)

其中x19-x28是arm64 架構(gòu)規(guī)定需要調(diào)用保存的寄存器,可以看到處理器狀態(tài)切換的時候?qū)⑶耙粋€進程(prev)的x19-x28,fp,sp,pc保存到了進程描述符的cpu_contex中,然后將即將執(zhí)行的進程(next)描述符的cpu_contex的x19-x28,fp,sp,pc恢復到相應寄存器中,而且將next進程的進程描述符task_struct地址存放在sp_el0中,用于通過current找到當前進程,這樣就完成了處理器的狀態(tài)切換。

實際上,處理器狀態(tài)切換就是將前一個進程的sp,pc等寄存器的值保存到一塊內(nèi)存上,然后將即將執(zhí)行的進程的sp,pc等寄存器的值從另一塊內(nèi)存中恢復到相應寄存器中,恢復sp完成了進程內(nèi)核棧的切換,恢復pc完成了指令執(zhí)行流的切換。其中保存/恢復所用到的那塊內(nèi)存需要被進程所標識,這塊內(nèi)存這就是cpu_contex這個結(jié)構(gòu)的位置(進程切換都是在內(nèi)核空間完成)。

由于用戶空間通過異常/中斷進入內(nèi)核空間的時候都需要保存現(xiàn)場,也就是保存發(fā)生異常/中斷時的所有通用寄存器的值,內(nèi)核會把“現(xiàn)場”保存到每個進程特有的進程內(nèi)核棧中,并用pt_regs結(jié)構(gòu)來描述,當異常/中斷處理完成之后會返回用戶空間,返回之前會恢復之前保存的“現(xiàn)場”,用戶程序繼續(xù)執(zhí)行。
所以當進程切換的時候,當前進程被時鐘中斷打斷,將發(fā)生中斷時的現(xiàn)場保存到進程內(nèi)核棧(如:sp, lr等),然后會切換到下一個進程,當再次回切換回來的時候,返回用戶空間的時候會恢復之前的現(xiàn)場,進程就可以繼續(xù)執(zhí)行(執(zhí)行之前被中斷打斷的下一條指令,繼續(xù)使用自己用戶態(tài)sp),這對于用戶進程來說是透明的。

如下為硬件上下文切換示例圖:

3.ASID機制

前面講過,進程切換的時候,由于tlb中存放的可能是其他進程的tlb表項,所有才需要在進程切換的時候進行tlb的清空工作(清空即是使得所有的tlb表項無效,地址轉(zhuǎn)換需要遍歷多級頁表,找到頁表項,然后重新加載頁表項到tlb),有了ASID機制之后,命中tlb表項,由虛擬地址和ASID共同決定(當然還有nG位),可以減小進程切換中tlb被清空的機會。

下面我們講解ASID機制,ASID(Address Space Identifer 地址空間標識符),用于區(qū)別不同進程的頁表項,arm64中,可以選擇兩種ASID長度8位或者16位,這里以8位來講解。

如果ASID長度為8位,那么ASID有256個值,但是由于0是保留的,所有可以分配的ASID范圍就為1-255,那么可以標識255個進程,當超出255個進程的時候,會出現(xiàn)兩個進程的ASID相同的情況,因此內(nèi)核使用了ASID版本號。
內(nèi)核中處理如下(參考arch/arm64/mm/context.c):

1)內(nèi)核為每個進程分配一個64位的軟件ASID,其中低8位為硬件ASID,高56位為ASID版本號,這個軟件ASID存放放在進程的mm_struct結(jié)構(gòu)的context結(jié)構(gòu)的id中,進程創(chuàng)建的時候會初始化為0。
2)內(nèi)核中有一個64位的全局變量asid_generation,同樣它的高56位為ASID版本號,用于標識當前ASID分配的批次。
3)當進程調(diào)度,由prev進程切換到next進程的時候,如果不是內(nèi)核線程則進行地址空間切換調(diào)用check_and_switch_context,此函數(shù)會判斷next進程的ASID版本號是否和全局的ASID版本號相同(是否處于同一批次),如果相同則不需要為next進程分配ASID,不相同則需要分配ASID。
4)內(nèi)核使用asid_map位圖來管理硬件ASID的分配,asid_bits記錄使用的ASID的長度,每處理器變量active_asids保存當前分配的硬件ASID,每處理器變量reserved_asids存放保留的ASID,tlb_flush_pending位圖記錄需要清空tlb的cpu集合。
硬件ASID分配策略如下:
(1)如果進程的ASID版本號和當前全局的ASID版本號相同(同批次情況),則不需要重新分配ASID。
(2)如果進程的ASID版本號和當前全局的ASID版本號不相同(不同批次情況),且進程原本的硬件ASID已經(jīng)被分配,則重新分配新的硬件ASID,并將當前全局的ASID版本號組合新分配的硬件ASID寫到進程的軟件ASID中。
(3)如果進程的ASID版本號和當前全局的ASID版本號不相同(不同批次情況),且進程原本的硬件ASID還沒有被分配,則不需要重新分配新的硬件ASID,只需要更新進程軟件ASID版本號,并將當前全局的ASID版本號組合進程原來的硬件ASID寫到進程的軟件ASID中。
(4)如果進程的ASID版本號和當前全局的ASID版本號不相同(不同批次情況),需要分配硬件ASID時,發(fā)現(xiàn)硬件ASID已經(jīng)被其他進程分配完(asid_map位圖中查找,發(fā)現(xiàn)位圖全1),則這個時候需要遞增全局的ASID版本號,清空所有cpu的tlb,清空asid_map位圖,然后分配硬件ASID,并將當前全局的ASID版本號組合新分配的硬件ASID寫到進程的軟件ASID中。

下面我們以實例來看ASID的分配過程:
如下圖:

我們假設(shè)圖中從A進程到D進程,有255個進程,剛好分配完了asid, ,從A到D的切換過程中使用的都是同一批次的asid版本號。

則這個過程中,有進程會創(chuàng)建的時候被切換到,假設(shè)不超出255個進程,在切換過程中會為新進程分配硬件的ASID,分配完后下次切換到他時由于他的ASID版本號和當前的全局的ASID版本號相同,所以不需要再次分配ASID,當然也不需要清空tlb。

注:這里說的ASID即為硬件ASID區(qū)別于ASID版本號。

情況1-ASID版本號不變屬于策略(1):從C進程到D進程切換,內(nèi)核判斷D進程的ASID版本號和當前的全局的ASID版本號相同,所以不需要為他分配ASID(執(zhí)行快速路徑switch_mm_fastpath去設(shè)置ttbrx_el1))。

情況2 -硬件ASID全部分配完屬于策略(4):假設(shè)到達D進程時,asid已經(jīng)全部分配完(系統(tǒng)中有255個進程都分配到了硬件asid號),這個時候新創(chuàng)建的進程E被調(diào)度器選中,切換到E,由于新創(chuàng)建的進程的軟件ASID被初始化為0,所以和當前的全局的ASID版本號不同(不在同一批次),則這個時候會執(zhí)行new_context為進程分配ASID,但是由于沒有可以分配的ASID,所以會將全局的ASID版本號加1(發(fā)生ASID回繞),這個時候全局的ASID為801,然后清空asid_map,置位tlb_flush_pending所有bit用于清空所有cpu的tlb,然后再次去分配硬件ASID給E進程,這個時候分配到了1給他(將ASID版本號)。

情況3-ASID版本號發(fā)生變化,進程的硬件ASID可以再次使用屬于策略(3):假設(shè)從E切換到了B進程,而B進程之前已經(jīng)在全局的ASID版本號為800的批次上分配了編號為5的硬件ASID,但是B進程的ASID版本號800和現(xiàn)在全局的ASID版本號801不相同,所有需要new_context為進程分配ASID,分配的時候發(fā)現(xiàn)asid_map中編號為5沒有被置位,也就是沒有其他進程分配了5這個ASID,所有可以繼續(xù)使用原來分配的硬件ASID 5。

情況4 -ASID版本號發(fā)生變化,有其他進程已經(jīng)分配了相同的硬件ASID屬于策略(2): 假設(shè)從B進程切換到A進程,而B進程之前已經(jīng)在全局的ASID版本號為800的批次上分配了編號為1的硬件ASID,但是B進程的ASID版本號800和現(xiàn)在全局的ASID版本號801不相同,所有需要new_context為進程分配ASID,分配的時候發(fā)現(xiàn)asid_map中編號為1已經(jīng)被置位,也就是其他進程已經(jīng)分配了1這個ASID,需要從asid_map尋找下一個空閑的ASID,則分配了新的ASID為6。

假設(shè)從A到E,由于E的ASID版本號和全局的ASID版本號(同一批次),和情況1相同,不需要分配ASID。但是之前原來處于800這個ASID版本號批次的進程都需要重新分配ASID,有的可以使用原來的硬件ASID,有的重新分配硬件ASID,但是都將ASID版本號修改為了現(xiàn)在全局的ASID版本號801。但是,隨著硬件ASID的不斷分配,最終處于801這一批次的硬件ASID也會分配完,這個時候就是上面的情況2,要情況所有cpu的tlb。

我可以看到有了ASID機制之后,由于只有當硬件ASID被分配完了(如被255個進程使用),發(fā)生回繞的時候才會清空所有cpu的tlb,大大提高了系統(tǒng)的性能(沒有ASID機制的情況下每次進程切換需要地址空間切換的時候都需要清空tlb)。

4. 普通用戶進程、普通用戶線程、內(nèi)核線程切換的差別

內(nèi)核地址空間切換的時候有一下原則:看的是進程描述符的mm_struct結(jié)構(gòu),即是成員mm:
1)如果mm為NULL,則表示即將切換的是內(nèi)核線程,不需要切換地址空間(所有任務共享內(nèi)核地址空間)。
2)內(nèi)核線程會借用前一個用戶進程的mm,賦值到自己的active_mm(本身的mm為空),進程切換的時候就會比較前一個進程的active_mm和當前進程的mm。
3)如果前一個任務的和即將切換的任務,具有相同的mm成員,也就是共享地址空間的線程則也不需要切換地址空間。

->所有的進程線程之間進行切換都需要切換處理器狀態(tài)。
->對于普通的用戶進程之間進行切換需要切換地址空間。
->同一個線程組中的線程之間切換不需要切換地址空間,因為他們共享相同的地址空間。
-> 內(nèi)核線程在上下文切換的時候不需要切換地址空間,僅僅是借用上一個進程mm_struct結(jié)構(gòu)。

有一下場景:
約定:我們將進程/線程統(tǒng)稱為任務,其中U表示用戶任務(進程/線程),K表示內(nèi)核線程,帶有數(shù)字表示同一個線程組中的線程。
有以下任務:Ua1 Ua2 Ub Uc Ka Kb (eg:Ua1為用戶進程, Ua2為和Ua1在同一線程組的用戶進程,Ub普通的用戶進程,Ka普通的內(nèi)核線程 )。

如果調(diào)度順序如下:

Uc -> Ua1 -> Ua2 -> Ub -> Ka -> Kb -> Ub

從Uc -> Ua1 由于是不同的進程,需要切換地址空間。
從 Ua1 -> Ua2 由于是相同線程組中的不同線程,共享地址空間,在切換到Ua1的時候已經(jīng)切換了地址空間,所有不需要切換地址空間。
從 Ua2 -> Ub 由于是不同的進程,需要切換地址空間。
從 Ub -> Ka 由于切換到內(nèi)核線程,所以不需要切換地址空間。
從Ka -> Kb 倆內(nèi)核線程之前切換,不需要切換地址空間。
從Kb -> Ub 從內(nèi)核線程切換到用戶進程,由于Ka和Kb都是借用Ub的active_mm,而Ub的active_mm 等于Ub的mm,所以這個時候 Kb的active_mm和 Ub的mm相同,所有也不會切換地址空間。

如下為多任務地址空間切換示例圖:

5. 進程切換全景視圖

我們以下場景為例:
A,B兩個進程都是普通的用戶進程,從進程A切換到進程B,簡單起見我們在這里不考慮其他的搶占時機,我們假設(shè)A,B進程只是循環(huán)進行一些基本的運算操作,從來不調(diào)用任何系統(tǒng)調(diào)用,只考慮被時鐘中斷,返回用戶空間之前被搶占的情況。

下面給出進程切換的全景視圖:


視圖中已經(jīng)講解很清楚,需要強調(diào)3個關(guān)鍵點:

1.發(fā)生中斷時的保存現(xiàn)場,將發(fā)生中斷時的所有通用寄存器保存到進程的內(nèi)核棧,使用struct pt_regs結(jié)構(gòu)。

2.地址空間切換將進程自己的頁全局目錄的基地址pgd保存在ttbr0_le1中,用于mmu的頁表遍歷的起始點。

3.硬件上下文切換的時候,將此時的調(diào)用保存寄存器和pc, sp保存到struct cpu_context結(jié)構(gòu)中。做好了這幾個保存工作,當進程再次被調(diào)度回來的時候,通過cpu_context中保存的pc回到了cpu_switch_to的下一條指令繼續(xù)執(zhí)行,而由于cpu_context中保存的sp導致當前進程回到自己的內(nèi)核棧,經(jīng)過一系列的內(nèi)核棧的出棧處理,最后將原來保存在pt_regs中的通用寄存器的值恢復到了通用寄存器,這樣進程回到用戶空間就可以繼續(xù)沿著被中斷打斷的下一條指令開始執(zhí)行,用戶棧也回到了被打斷之前的位置,而進程訪問的指令數(shù)據(jù)做地址轉(zhuǎn)化(VA到PA)也都是從自己的pgd開始進行,一切對用戶來說就好像沒有發(fā)生一樣,簡直天衣無縫。

6. 總結(jié)

進程管理中最重要的一步要進行進程上下文切換,其中主要有兩大步驟:地址空間切換和處理器狀態(tài)切換(硬件上下文切換),前者保證了進程回到用戶空間之后能夠訪問到自己的指令和數(shù)據(jù)(其中包括減小tlb清空的ASID機制),后者保證了進程內(nèi)核棧和執(zhí)行流的切換,會將當前進程的硬件上下文保存在進程所管理的一塊內(nèi)存,然后將即將執(zhí)行的進程的硬件上下文從內(nèi)存中恢復到寄存器,有了這兩步的切換過程保證了進程運行的有條不紊,當然切換的過程是在內(nèi)核空間完成,這對于進程來說是透明的。

責任編輯:xj

原文標題:深入理解Linux內(nèi)核進程上下文切換

文章出處:【微信公眾號:Linuxer】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11329

    瀏覽量

    209977
  • LINUX內(nèi)核
    +關(guān)注

    關(guān)注

    1

    文章

    316

    瀏覽量

    21688

原文標題:深入理解Linux內(nèi)核進程上下文切換

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    解讀版|Air780E軟件中C語言內(nèi)存數(shù)組的神秘面紗!

    今天我們來揭開Air780E 軟件中 C 語言內(nèi)存數(shù)組的神秘面紗,希望有所收獲。
    的頭像 發(fā)表于 11-17 10:00 ?286次閱讀
    解讀版|Air780E軟件中C語言內(nèi)存數(shù)組的<b class='flag-5'>神秘</b><b class='flag-5'>面紗</b>!

    用智能DAC揭開醫(yī)療報警設(shè)計的神秘面紗

    電子發(fā)燒友網(wǎng)站提供《用智能DAC揭開醫(yī)療報警設(shè)計的神秘面紗.pdf》資料免費下載
    發(fā)表于 09-14 10:50 ?0次下載
    用智能DAC<b class='flag-5'>揭開</b>醫(yī)療報警設(shè)計的<b class='flag-5'>神秘</b><b class='flag-5'>面紗</b>

    SystemView上下文統(tǒng)計窗口識別阻塞原因

    SystemView工具可以記錄嵌入式系統(tǒng)的運行時行為,實現(xiàn)可視化的深入分析。在新發(fā)布的v3.54版本中,增加了一項新功能:上下文統(tǒng)計窗口,提供了對任務運行時統(tǒng)計信息的深入分析,使用戶能夠徹底檢查每個任務,幫助開發(fā)人員識別阻塞原因。
    的頭像 發(fā)表于 08-20 11:31 ?459次閱讀

    北斗衛(wèi)星時鐘——揭開“授時”的神秘面紗

    ,這些時間信息又是從哪里來的呢?為什么我們可以隨時隨地都能獲取準確的時間信息?這得益于高精度的 授時服務 ,今天我們就來揭開“授時”的神秘面紗。 ? ? ?大家都知道我國的北斗導航衛(wèi)星,是用于定位導航的。那么北斗是怎么進行定位導
    的頭像 發(fā)表于 07-25 16:21 ?461次閱讀
    北斗衛(wèi)星時鐘——<b class='flag-5'>揭開</b>“授時”的<b class='flag-5'>神秘</b><b class='flag-5'>面紗</b>

    如何在FreeRTOS操作系統(tǒng)上跑RT-Thread?

    我現(xiàn)在有個項目用的MCU 內(nèi)核是很小眾的,芯片廠家僅支持freertos,我現(xiàn)在想把rt-thread弄上去跑,不知道該怎么實現(xiàn)開關(guān)中斷以及上下文切換等,能提供幫助嗎? 底層繼續(xù)使用freertos,我在應用中使用rt-thread
    發(fā)表于 07-09 08:30

    xAI公司將在八月揭開其新Grok-2大語言模型的神秘面紗

    在科技界的浩瀚星空中,埃隆·馬斯克的每一次發(fā)聲都如同璀璨的新星,瞬間照亮前行的道路。近日,這位科技巨擘在推特上的一則簡短宣告,再次將全球的目光聚焦于人工智能的前沿陣地——他的初創(chuàng)公司xAI即將在八月揭開其最新力作Grok-2大語言模型的神秘
    的頭像 發(fā)表于 07-02 11:38 ?512次閱讀

    揭開Pluto XZU20的神秘面紗—探尋未來緊湊而強大的FPGA解決方案

    創(chuàng)新成果具有挽救生命、改變生活和創(chuàng)造夢想的能力?,F(xiàn)在讓我們一起緊隨Pluto產(chǎn)品發(fā)布會的步伐,揭開PlutoXZU20的神秘面紗,與我們一起探尋未來緊湊而強大的FP
    的頭像 發(fā)表于 06-21 08:09 ?411次閱讀
    <b class='flag-5'>揭開</b>Pluto XZU20的<b class='flag-5'>神秘</b><b class='flag-5'>面紗</b>—探尋未來緊湊而強大的FPGA解決方案

    鴻蒙Ability Kit(程序框架服務)【應用上下文Context】

    [Context]是應用中對象的上下文,其提供了應用的一些基礎(chǔ)信息,例如resourceManager(資源管理)、applicationInfo(當前應用信息)、dir(應用文件路徑)、area
    的頭像 發(fā)表于 06-06 09:22 ?525次閱讀
    鴻蒙Ability Kit(程序框架服務)【應用<b class='flag-5'>上下文</b>Context】

    編寫一個任務調(diào)度程序,在上下文切換后遇到了一些問題求解

    大家好, 我正在編寫一個任務調(diào)度程序,在上下文切換后遇到了一些問題。 為下一個任務恢復上下文后: __builtin_tricore_mtcr_by_name(\"pcxi\"
    發(fā)表于 05-22 07:50

    揭開快充芯片的神秘面紗

    UFP芯片是一種用于USB快充技術(shù)的關(guān)鍵元件,它在移動設(shè)備和充電器之間進行通信和協(xié)調(diào),以實現(xiàn)高效、安全、快速的充電過程。下面我們將揭開快充芯片的神秘面紗,深入探討UFP快充芯片的工作原理和功能。
    的頭像 發(fā)表于 04-15 12:51 ?671次閱讀

    OpenHarmony中SELinux使用詳解

    )和上下文(context)。 我們可以通過ps -Z 命令來查看當前進程的域信息,也就是進程的SELinux信息: **# ps -Z LABEL PID TTY TIME CMD u:r:sh
    發(fā)表于 04-03 10:43

    Linux內(nèi)存故障追蹤的實用技術(shù)指南

    使用kprobe跟蹤swap_readpage()內(nèi)核函數(shù),這會在觸發(fā)換頁所在的進程上下文中進行,可以跟蹤觸發(fā)換頁操作的進程的信息。展示了哪個進程
    發(fā)表于 04-01 14:27 ?661次閱讀
    <b class='flag-5'>Linux</b>內(nèi)存故障追蹤的實用技術(shù)指南

    TC397收到EVAL_6EDL7141_TRAP_1SH 3上下文管理EVAL_6EDL7141_TRAP_1SH錯誤怎么解決?

    我收到EVAL_6EDL7141_TRAP_1SH 3 類(TIN4-Free 上下文列表下溢)上下文管理EVAL_6EDL7141_TRAP_1SH錯誤。 請告訴我解決這個問題的辦法。
    發(fā)表于 03-06 08:00

    請問risc-v中斷還需要軟件保存上下文和恢復嗎?

    risc-v中斷還需要軟件保存上下文和恢復嗎?
    發(fā)表于 02-26 07:40

    ISR的上下文保存和恢復是如何完成的?

    函數(shù):ifxCPU_enableInterrupts ();如果我讓更高優(yōu)先級的 ISR 中斷優(yōu)先級較低的 ISR,那么 ISR 的上下文保存和恢復是如何完成的?
    發(fā)表于 01-22 06:28