www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 公眾號精選 > 嵌入式IoT

rt-thread中的壓棧與出棧

1.說明

本文主要想分析一下rt-thread中線程的壓棧與入棧的相關(guān)操作。從而更好的掌握線程切換與線程恢復(fù)的相關(guān)知識。

2.使用場景

首先需要明白的是什么情況下需要進(jìn)行壓棧與出棧的操作?對于這個問題可以做這樣的設(shè)想,當(dāng)程序一直做一件事的時候,是順序執(zhí)行的,不會有任何干擾。但是此時來了一個中斷,那么程序邏輯肯定會優(yōu)先去處理中斷。那么這時需要做哪些事情?

也許這個例子有點脫離實際,講的通俗明白一些,就是一個人在專注的完成一件事,此時應(yīng)該是很順利的進(jìn)行。但是當(dāng)事情還沒有做完,但是又有一個更加緊急的事情需要你去處理,這時應(yīng)該怎么做?

對于一個人來講:

(1)將手里沒有做完的事情保留起來,保留當(dāng)前的進(jìn)度

(2)將大腦清空,全力完成更加重要的事情

(3)恢復(fù)到?jīng)]有做完的事情的現(xiàn)場,去接著完成沒有做完的事情

人的大腦是這樣工作的,其實芯片的邏輯也需要這樣執(zhí)行,我們知道芯片如何知道當(dāng)前程序的狀態(tài),無外乎幾個重要的寄存器,sp(程序指針寄存器),通用寄存器Rx,以及LR鏈接寄存器等等。有了這些信息,就可以知道程序當(dāng)前運行的狀態(tài)了,這個就是程序的現(xiàn)場。

對于armv7來說,寄存器可以分為以下幾種:

armasm_pge1464343210583

在rt-thread操作系統(tǒng)中,涉及到壓棧與出棧操作的有兩個地方,第一個是中斷的進(jìn)入與中斷處理完成后的退出,第二個是線程的切換。

3.簡單分析一下rt-thread線程棧的初始化

對于/bsp/qemu-vexpress-a9來說,系統(tǒng)上電后執(zhí)行rtt的第一行代碼在/libcpu/arm/cortex-a/start_gcc.S文件。

然后執(zhí)行_reset函數(shù),這個函數(shù)是匯編函數(shù)寫的,因為前期沒有棧空間,所以代碼需要采用匯編指令完成。

然后分配??臻g等等。執(zhí)行到rtt的其他部分邏輯。這里就不贅述了。這里主要分析的是線程的初始化。

每一個線程在初始化的時候,需要分配棧空間

rt_thread_create/rt_thread_init --> _rt_thread_init --> rt_hw_stack_init

最后調(diào)用到了/libcpu/arm/cortex-a/stack.c文件。

rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, rt_uint8_t *stack_addr, void *texit)
{ rt_uint32_t *stk;

 stack_addr += sizeof(rt_uint32_t);
 stack_addr  = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
 stk      = (rt_uint32_t *)stack_addr;
 *(--stk) = (rt_uint32_t)tentry; /* entry point */ *(--stk) = (rt_uint32_t)texit; /* lr */ *(--stk) = 0xdeadbeef; /* r12 */ *(--stk) = 0xdeadbeef; /* r11 */ *(--stk) = 0xdeadbeef; /* r10 */ *(--stk) = 0xdeadbeef; /* r9 */ *(--stk) = 0xdeadbeef; /* r8 */ *(--stk) = 0xdeadbeef; /* r7 */ *(--stk) = 0xdeadbeef; /* r6 */ *(--stk) = 0xdeadbeef; /* r5 */ *(--stk) = 0xdeadbeef; /* r4 */ *(--stk) = 0xdeadbeef; /* r3 */ *(--stk) = 0xdeadbeef; /* r2 */ *(--stk) = 0xdeadbeef; /* r1 */ *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ /* cpsr */ if ((rt_uint32_t)tentry & 0x01)
 *(--stk) = SVCMODE | 0x20; /* thumb mode */ else *(--stk) = SVCMODE; /* arm mode   */ #ifdef RT_USING_LWP *(--stk) = 0; /* user lr */ *(--stk) = 0; /* user sp*/ #endif #ifdef RT_USING_FPU *(--stk) = 0; /* not use fpu*/ #endif /* return task's current stack address */ return (rt_uint8_t *)stk;
}

初始化線程的時候,每個線程都是有一個棧空間的,這個??臻g不僅僅保存一下參數(shù)變量,還在棧地址的首地址處保存了線程執(zhí)行需要的現(xiàn)場。而且每個線程都有一個獨立的棧內(nèi)存,這個內(nèi)存就是在棧的入口處。

當(dāng)線程發(fā)生切換的時候,需要取出這些寄存器

.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: #ifdef RT_USING_SMP /* r0 :svc_mod context
 * r1 :addr of from_thread's sp
 * r2 :addr of to_thread's sp
 * r3 :to_thread's tcb
 */ str     r0, [r1]

 ldr     sp, [r2]
 mov     r0, r3
 bl      rt_cpus_lock_status_restore

 b       rt_hw_context_switch_exit

執(zhí)行到rt_hw_context_switch_exit函數(shù)

.global rt_hw_context_switch_exit
rt_hw_context_switch_exit: #ifdef RT_USING_SMP #ifdef RT_USING_SIGNALS mov     r0, sp
 cps #Mode_IRQ
 bl      rt_signal_check
 cps #Mode_SVC
 mov     sp, r0 #endif #endif #ifdef RT_USING_FPU /* fpu context */ ldmfd sp!, {r6}
 vmsr fpexc, r6
 tst  r6, #(1<<30)
 beq 1f ldmfd sp!, {r5}
 vmsr fpscr, r5
 vldmia sp!, {d16-d31}
 vldmia sp!, {d0-d15} 1: #endif #ifdef RT_USING_LWP ldmfd   sp, {r13, r14}^ /* usr_sp, usr_lr */ add     sp, #8 #endif ldmfd   sp!, {r1}
 msr     spsr_cxsf, r1 /* original mode */ ldmfd   sp!, {r0-r12,lr,pc}^ /* irq return */ 

該函數(shù)可能看起來有些費勁,我來解釋一下大概的內(nèi)容:

當(dāng)線程間要從上一個線程切換到下一個線程的時候,首先會將切換之前現(xiàn)場保存起來,也就是將這些寄存器的知保存到內(nèi)存中,然后將sp指向下線程的地址。此時需要恢復(fù)下一個需要切換的線程的寄存器。

4.總結(jié)

如果需要理清楚rt-thread的??臻g的壓棧與入棧,其實最根本的問題就是如何去處理現(xiàn)場狀態(tài)的問題。也就是每個線程都需要有一個獨立的??臻g,然后這些??臻g除了保存數(shù)據(jù),還需要保存寄存器。當(dāng)進(jìn)行任務(wù)切換的時候,當(dāng)前線程的寄存器需要保存該線程的棧內(nèi)存中,而下個線程的??臻g則會從自己的??臻g的起始地址處恢復(fù)。這個就是rt-thread棧運作的實現(xiàn)邏輯。


本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
關(guān)閉