RT-Thread内核之线程调度(5)
生活随笔
收集整理的這篇文章主要介紹了
RT-Thread内核之线程调度(5)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
轉(zhuǎn)載于:?http://blog.csdn.net/lpjybn/article/details/46911559
?
5.線程切換的本質(zhì)?
到現(xiàn)在我們知道,每個(gè)線程的執(zhí)行需要一定的“物質(zhì)”基礎(chǔ)。首先,需要獲得CPU的使用權(quán),這就包括CPU內(nèi)部各寄存器的使用,然后有自己獨(dú)立的棧空間,這部分的空間每個(gè)線程應(yīng)該各自獨(dú)立。然后,每個(gè)線程都有一段獨(dú)特的指令以完成特定的功能。由這些就組成了“線程上下文”,線程的切換就是線程上下文的切換。在RT-Thread中有兩個(gè)架構(gòu)相關(guān)的函數(shù)來(lái)完成這項(xiàng)工作:rt_hw_context_switch,rt_hw_context_switch_interrupt。 那么這兩個(gè)函數(shù)有什么區(qū)別呢?顯然,rt_hw_context_switch是在非中斷中進(jìn)行上下文切換,而rt_hw_context_switch_interrupt則是在中斷上下文中完成線程切換的。這里以S3C2440處理為例: /******************************************************************************************* ** 函數(shù)名稱: rt_hw_context_switch ** 函數(shù)功能: 非中斷中進(jìn)行上下文切換 ** 入口參數(shù): from 被切出的線程的棧頂指針 ** to 被切入的線程的棧頂指針 ** 返 回 值: 無(wú) ** 調(diào) 用: *******************************************************************************************/ .globl rt_hw_context_switch rt_hw_context_switch: ? ? stmfd sp!, {lr} ? ?/** 將被中斷的線程的下一條要執(zhí)行的指令的地址壓入棧中 ?*?(LR存放下一條將要執(zhí)行的指令地址)? ?*/ ? ? stmfd sp!, {r0-r12, lr}/** 將LR,R12-R0寄存器依次入棧 */ ? ? ??mrs r4, cpsr ? ? ? ? ? ??/** 讀取CPSR寄存器的值到R4中 */ ? ? stmfd sp!, {r4} ? ? ? ? ?/** 將R4寄存器的值(CPSR)壓入棧中 */ ? ? mrs r4, spsr ? ? ? ? ? ??/** 讀取SPSR寄存器的值到R4寄存器中 */ ? ? stmfd sp!, {r4} ? ? ? ? ?/** 將R4寄存器的值(SPSR)壓入棧中 */ ? ? ? str sp, [r0] ? ? ? ? ? ??/** 將線程的棧頂指針保存到線程結(jié)構(gòu)的sp中 */ ? ? ? ldr sp, [r1] ? ? ? ? ? ??/** 從新線程的線程結(jié)構(gòu)的sp中取出該線程的棧頂指針 */ ? ? ? ldmfd sp!, {r4} ? ? ? ? ? ?/** 從線程的棧中彈出SPSR寄存器值到R4寄存器中 */ ? ? msr spsr_cxsf, r4 ? ? ? ? ?/** 將值寫入SPSR寄存器中 */ ? ? ldmfd sp!, {r4} ? ? ? ? ? ?/** 從線程的棧中彈出CPSR寄存器值到R4寄存器中 */ ? ? msr spsr_cxsf, r4 ? ? ? ? ?/** 將值寫入CPSR寄存器中 */ ? ? ? ldmfd sp!, {r0-r12, lr, pc}^ ? ??/** 恢復(fù)該線程其他寄存器的值PC,LR,R12 - R0 */ ? ? /******************************************************************************************* ** 函數(shù)名稱: rt_hw_context_switch_interrupt ** 函數(shù)功能: 中斷中進(jìn)行上下文切換 ** 入口參數(shù): from 被切出的線程的棧頂指針 ** to 被切入的線程的棧頂指針 ** 返 回 值: 無(wú) ** 調(diào) 用: ******************************************************************************************/ .globl rt_thread_switch_interrupt_flag .globl rt_interrupt_from_thread .globl rt_interrupt_to_thread ? .globl rt_hw_context_switch_interrupt rt_hw_context_switch_interrupt: ? ? ? ? /** 1.判斷rt_thread_switch_interrupt_flag變量的值是否為1 */ ? ??ldr r2, =rt_thread_switch_interrupt_flag? ??/** 加載變量rt_thread_switch_interrupt_flag ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* 的地址到r2寄存器中? ? ? ? ? ?*/ ? ?ldr r3, [r2]?? ??/** 讀取rt_thread_switch_interrupt_flag寄存器的值到R3寄存器中 */ ? ?cmp r3, #1?? ? ??/** 判斷rt_thread_switch_interrupt_flag的值是否為1 */ ? ? ? /** 如果rt_thread_switch_interrupt_flag值為1 */ ? ?beq?_reswitch ? ??/** 如果rt_thread_switch_interrupt_flag值為1,跳轉(zhuǎn)到標(biāo)號(hào)_reswitch執(zhí)行 */ ? ?mov r3, #1?? ? ? ?/** 如果rt_thread_switch_interrupt_flag值為0,將其值設(shè)置為1 */ ? ?str r3, [r2] ? ? ?ldr r2, =rt_interrupt_from_thread ? ?/** 加載rt_interrupt_from_thread變量的地址到R2寄存 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? * 器中? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */ ? ? ?str r0, [r2]?? ? ?/** 將被切換出的線程的棧頂?shù)刂繁4娴阶兞縭t_interrupt_from_thread中 */ ? _reswitch: ? ?ldr r2, =rt_interrupt_to_thread ? ???/** 加載rt_interrupt_to_thread變量的地址到R2寄存器 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? * 中 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */ ? ? ?str r1, [r2]?? ? ??/** 將被切入的線程的棧頂?shù)刂繁4娴阶兞縭t_interrupt_to_thread中 */ ? ?mov pc, lr? ? /******************************************************************************************* ** 函數(shù)名稱: rt_hw_context_switch_interrupt ** 函數(shù)功能: 中斷中進(jìn)行上下文切換 ** 入口參數(shù): from 被切出的線程的棧頂指針 ** to 被切入的線程的棧頂指針 ** 返 回 值: 無(wú) ** 調(diào) 用: *******************************************************************************************/ .globl rt_thread_switch_interrupt_flag .globl rt_interrupt_from_thread .globl rt_interrupt_to_thread ? .globl rt_hw_context_switch_interrupt rt_hw_context_switch_interrupt: ? ?/** 1.判斷rt_thread_switch_interrupt_flag變量的值是否為1 */ ?ldr r2, =rt_thread_switch_interrupt_flag/** 加載變量rt_thread_switch_interrupt_flag的地址到r2寄存器中 */ ?ldr r3, [r2] ? ??/** 讀取rt_thread_switch_interrupt_flag寄存器的值到R3寄存器中 */ ?cmp r3, #1 ? ? ??/** 判斷rt_thread_switch_interrupt_flag的值是否為1 */ ? ?/** 如果rt_thread_switch_interrupt_flag值為1 */ ?beq _reswitch ? ??/** 如果rt_thread_switch_interrupt_flag值為1,跳轉(zhuǎn)到標(biāo)號(hào)_reswitch執(zhí)行 */ ?mov r3, #1 ? ? ? ?/** 如果rt_thread_switch_interrupt_flag值為0,將其值設(shè)置為1 */ ?str r3, [r2] ? ?ldr r2, =rt_interrupt_from_thread ? ?/** 加載rt_interrupt_from_thread變量的地址到R2寄存器中 */ ?str r0, [r2] ? ? ?/** 將被切換出的線程的棧頂?shù)刂繁4娴阶兞縭t_interrupt_from_thread中 */ ? _reswitch: ?ldr r2, =rt_interrupt_to_thread ? ???/** 加載rt_interrupt_to_thread變量的地址到R2寄存器中 */ ?str r1, [r2] ? ? ??/** 將被切入的線程的棧頂?shù)刂繁4娴阶兞縭t_interrupt_to_thread中 */ ?mov pc, lr? ? ? 我們發(fā)現(xiàn)rt_hw_context_switch_interrupt并沒(méi)有完成線程的切換,只是用全局變r(jià)t_interrupt_from_thread 和rt_interrupt_to_thread保存了被換出和換入的線程的棧頂指針,而真正的切換過(guò)程在中斷處理中完成。 ? .globl rt_interrupt_enter .globl rt_interrupt_leave .globl rt_thread_switch_interrupt_flag .globl rt_interrupt_from_thread .globl rt_interrupt_to_thread vector_irq: ? ? stmfd sp!, {r0-r12,lr} ? ??/** 使用中斷模式的棧空間來(lái)存儲(chǔ)SVC模式下的PC, R12 - R0 */ ? ? bl?rt_interrupt_enter ? ? ?/** 調(diào)用rt_interrupt_enter函數(shù): 中斷嵌套的層數(shù)加1 */ ? ? bl?rt_hw_trap_irq ? ? ? ? ?/** 根據(jù)中斷號(hào)去調(diào)用中斷處理程序:由于中斷處理程序是在IRQ模式執(zhí)行, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? * 因此系統(tǒng)是不支持中斷嵌套的? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */ ? ? bl?rt_interrupt_leave ? ???/** 調(diào)用rt_interrupt_leave函數(shù): 中斷嵌套的層數(shù)減1 */ ? ? ? ? /** 在中斷退出之前,判斷rt_thread_switch_interrupt_flag變量的值是否為1 */ ? ? ldr r0, =rt_thread_switch_interrupt_flag ? ??/** 讀取變量rt_thread_switch_interrupt_flag ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? * 的地址到r0寄存器中? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */ ? ? ldr r1, [r0] ? ? ? ? ?/** 讀取變量rt_thread_switch_interrupt_flag的值 */ ? ? cmp r1, #1 ? ? ? ? ???/** 判斷變量rt_thread_switch_interrupt_flag的值是否為1 */ ? ? ? beq?_interrupt_thread_switch ? ??/** 如果為1說(shuō)明在退出中斷模式之前還需要進(jìn)行任務(wù)切換工作; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? * 如果為0則可以安全的退出中斷模式了? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */ ? ? ? ? ldmfd sp!, {r0-r12,lr} ? ? ?/** 恢復(fù)SVC模式下的各個(gè)寄存器值 */ ? ? subs pc, lr, #4 ? ? ? ? ? ??/** 繼續(xù)從被中斷點(diǎn)執(zhí)行 */? _interrupt_thread_switch: ? ? ??/** 1.將變量rt_thread_switch_interrupt_flag的值清0 */ ? ? mov r1, ?#0 ? ? ? ? ??/** 設(shè)置R1寄存器的值為0 */ ? ? str r1, ?[r0] ? ? ? ??/** 將變量rt_thread_switch_interrupt_flag的值設(shè)置為0 */ ? ? ? ldmfd sp!, {r0-r12,lr} ? ??/** 恢復(fù)保存在IRQ模式中的各寄存器值 */ ? ? stmfd sp!, {r0-r3} ? ? ? ??/** 將R0-R3寄存器入棧 */ ? ? mov r1, ?sp ? ? ? ? ? ? ? ?/** 將此時(shí)的棧指針保存在R1中 */ ? ? add sp, ?sp, #16 ? ? ? ? ??/** 將SP的值加16,SP重新指向R0-R3入棧時(shí)的位置 */ ? ? sub r2, ?lr, #4 ? ? ? ? ???/** 計(jì)算出被中斷的線程的PC值保存到R2中 */ ? ? ? mrs r3, ?spsr ? ? ? ? ? ??/** 加載被中斷的線程的CPSR寄存器值到R3寄存器中 */ ? ? orr r0, ?r3, #NOINT ? ? ??/** 屏蔽中斷位 */ ? ? msr spsr_c, r0 ? ? ? ? ? ?/** 將設(shè)置后的值寫回IRQ模式的SPSR寄存器中 */ ? ? ? ldr r0, ?=.+8 ? ? ? ? ? ??/** 通過(guò)反匯編查看: 是將下面第二條指令的地址存到R0中 */ ? ? movs pc, ?r0 ? ? ? ? ? ? ?/** movs指令會(huì)影響到CPSR,包括N,Z,C標(biāo)志位,CPSR會(huì)被SPSR覆蓋 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* 因此執(zhí)行此條指令相當(dāng)于完成處理器從IRQ到SVC模式的切換 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* 下面指令的sp將為SVC下的sp寄存器,而非IRQ模式的sp ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/ ? ? ? stmfd sp!, {r2} ? ? ? ? ? ??/** 將被中斷的線程的PC值入棧 */ ? ? stmfd sp!, {r4-r12,lr} ? ? ?/** 將被中斷的線程的LR,R12-R4寄存器入棧 */ ? ? mov r4, ?r1 ? ? ? ? ? ? ? ??/** 將R1的值保存到R4 */ ? ? mov r5, ?r3 ? ? ? ? ? ? ? ??/** 將R3的值保存到R5(IRQ_SPSR) */ ? ? ldmfd r4!, {r0-r3} ? ? ? ? ?/** 將棧中保存的R0-R3寄存器值恢復(fù) */ ? ? stmfd sp!, {r0-r3} ? ? ? ? ?/** 將R3-R0寄存器值入棧 */ ? ? stmfd sp!, {r5} ? ? ? ? ? ??/** 將舊任務(wù)的CPSR值入棧 */ ? ? mrs r4, ?spsr ? ? stmfd sp!, {r4} ? ? ? ? ? ??/** 將舊任務(wù)的SPSR值入棧 */ ? ? ? ? /** 讀取保存在變量rt_interrupt_from_thread的舊線程的sp值 */ ? ? ldr r4, ?=rt_interrupt_from_thread ? ? ldr r5, ?[r4] ? ? str sp, ?[r5] ? ? ? ? ? ? ??/** 保存換出任務(wù)的棧頂指針 */ ? ? ? ??/** 獲取新線程的棧頂指針 */ ? ? ldr r6, ?=rt_interrupt_to_thread ? ??/** 加載變量rt_interrupt_to_thread的地址到R6寄存器 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? * 中? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */ ? ? ldr r6, ?[r6] ? ? ? ? ? ??/** 加載變量rt_interrupt_to_thread的值到R6中 */ ? ? ldr sp, ?[r6] ? ? ? ? ? ??/** 加載變量rt_interrupt_to_thread的值到SP寄存器中 */ ? ? ? ldmfd sp!, {r4} ? ? ? ? ? ??/** 彈出新線程的SPSR寄存器值 */ ? ? msr SPSR_cxsf, r4 ? ? ldmfd sp!, {r4} ? ? ? ? ? ??/** 彈出新線程的CPSR寄存器值 */ ? ? msr CPSR_cxsf, r4 ? ? ? ldmfd sp!, {r0-r12,lr,pc} ??/** 彈出新線程的其他各寄存器,線程恢復(fù) */
?
轉(zhuǎn)載于:https://www.cnblogs.com/tureno/articles/7999942.html
總結(jié)
以上是生活随笔為你收集整理的RT-Thread内核之线程调度(5)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Beta 冲刺 (5/7)
- 下一篇: 线程调用同步方法