任務(wù)堆棧不是系統(tǒng)堆棧 搞混了就會(huì)完蛋
但是,代碼可不像大妹子那么好看。一眼望去,好幾個(gè).c文件中密密麻麻的字符,簡直是老鼠拉烏龜,沒有下手的地方呀!
本文引用地址:http://2s4d.com/article/201904/399825.htm有些人總是有著鷹一般銳利的眼睛,比如他們會(huì)發(fā)現(xiàn),新版倚天屠龍記中張無忌和趙敏居然足足吻了25秒鐘,而且張無忌一邊吻還一邊貪婪地咽口水。好吧,我承認(rèn),我也發(fā)現(xiàn)了張無忌咽口水的猥瑣模樣,但是對(duì)于枯燥的代碼,我實(shí)在沒有這般銳利的眼睛,只好一行代碼一行代碼地硬著頭皮看。
I2C部分自然是不用看的。只看上層驅(qū)動(dòng)就可以了,很快,我把目光放在了函數(shù)atsha204_mac身上,這正是我最終調(diào)用的那個(gè)函數(shù)。
這個(gè)函數(shù)實(shí)在也太顯眼了,因?yàn)檫@個(gè)函數(shù)不僅調(diào)用了好幾個(gè)函數(shù),里面還有三個(gè)大數(shù)組形式的局部變量:
uint8_t transmit_buffer[SHA204_CMD_SIZE_MAX];
uint8_t response_buffer[SHA204_RSP_SIZE_MAX];
uint8_t soft_digest[32];
單單是這三個(gè)局部變量就足足用掉了151個(gè)字節(jié)!再加上其他局部變量,快到200字節(jié)了,要知道,在調(diào)用這個(gè)函數(shù)時(shí),它里面的所有局部變量都是要放到堆棧上的,這樣的話,才可能會(huì)在中斷發(fā)生時(shí)保存現(xiàn)場,以在中斷服務(wù)程序完成后再度恢復(fù)現(xiàn)場。
現(xiàn)場當(dāng)然不止包括局部變量,還要再加上調(diào)用的子函數(shù),這樣算下來,atsha204_mac這個(gè)函數(shù)運(yùn)行時(shí)消耗掉的堆棧還不得快到300字節(jié)了?齊工調(diào)用這個(gè)函數(shù)的主程序是裸機(jī)形式,消耗的是系統(tǒng)堆棧,系統(tǒng)堆棧的默認(rèn)配置是512字節(jié),可是我是在帶有操作系統(tǒng)的任務(wù)里面調(diào)用這個(gè)函數(shù)的,消耗的是任務(wù)堆棧,我對(duì)任務(wù)堆棧的默認(rèn)配置是256字節(jié)!!
問題一目了然了,我輕輕地?fù)]了揮手,把齊工提溜了過來,
和齊工說完問題的原因之后,我心情大好,問起了齊工:“你知道不知道你的主程序設(shè)置的堆??臻g有多大?”根據(jù)我對(duì)齊工的了解,一心撲在炒股上面的他,應(yīng)該不知道在哪里設(shè)置堆棧空間,更遑論堆??臻g有多大了。
果然,他瞪著無辜的小眼神掃了我一眼,嘴角彎出一抹笑意,等著我的科普。
我滿意地看著他的表情,鼓起腮幫子說了起來,“在prm文件里面,你看一下這個(gè)設(shè)置STACKSIZE 0x200,512個(gè)字節(jié)。你驗(yàn)證加密認(rèn)證模塊時(shí),用的就是這個(gè)堆棧,你可以看一下MCU初始化時(shí)對(duì)SP寄存器的設(shè)置和堆棧區(qū)域的初始化,SP寄存器設(shè)置堆棧棧頂,初始化程序里,從棧頂開始,根據(jù)STACKSIZE把用作堆棧的那部分RAM初始化為0。”
“哦,那按你的意思,如果Atmel的那個(gè)函數(shù)在裸機(jī)里面運(yùn)行,消耗的就是系統(tǒng)堆棧,但是這個(gè)函數(shù)一旦在你的任務(wù)里面運(yùn)行,消耗的就是任務(wù)堆棧了,為什么呢?”齊工精靈剔透,一下子就提問到了問題的本質(zhì)。
‘孺子可教也!’我一邊在心里嘀咕著,一邊組織著語言,回答他的問題。
“你來看一下在我用的這個(gè)ucos操作系統(tǒng)里,任務(wù)切換時(shí)到底執(zhí)行了什么就清楚了?!蔽乙贿厔澙髽?biāo)轉(zhuǎn)輪,一邊在屏幕上找著對(duì)SP指針進(jìn)行操作的地方。嗯?那雙發(fā)現(xiàn)張無忌咽口水的鷹一般銳利的眼睛哪里去了?找了半天后,我突然意識(shí)到,應(yīng)該翻到匯編代碼里面去找,于是我翻到os_cpu_a.s文件里面,終于找到了下面這條語句:
lds 0,x ; 3~, Load the SP of the next task
這是任務(wù)切換時(shí)將SP寄存器設(shè)置為待切換任務(wù)結(jié)構(gòu)體中的堆棧指針內(nèi)容的地方,它和裸機(jī)形式里只初始化一次SP的方式不一樣,每次切換到新的任務(wù)時(shí)都要設(shè)置一次,所以如果任務(wù)堆棧設(shè)計(jì)地過小,就無法運(yùn)行atsha204_mac這個(gè)消耗大量堆棧的函數(shù)。
“那怎么解決呢?”齊工怯怯地問,顯然,他不想改這個(gè)函數(shù)的實(shí)現(xiàn)方式。
從臉盲癥中恢復(fù)的我定定地看了一下齊工,想到他上次給我推薦了一只好股票的“恩惠”,大手一揮,朗然道:“你不用管了,我可以在創(chuàng)建任務(wù)之前調(diào)用這個(gè)函數(shù),這時(shí)它用的還是系統(tǒng)堆棧。也可以在任務(wù)中調(diào)用它,把調(diào)用位置所在的任務(wù)堆棧加大也可以。”
看到他漸漸輕松了的笑容,我又加上了一句科普:任務(wù)堆棧不是系統(tǒng)堆棧,搞混了就會(huì)完蛋??!
評(píng)論