問題分析:linux
1.原本向板子發送個reboot,板子程序收到reboot命令後會執行system(「reboot」);shell
可是板子並無重啓。bash
2.分析system執行機制函數
先來看一下system()函數的簡單介紹:spa
#include int system(const char *command)
system()函數調用/bin/sh來執行參數指定的命令,/bin/sh 通常是一個軟鏈接,指向某個具體的shell,好比bash,-c選項是告訴shell從字符串command中讀取命令; 在該command執行期間,SIGCHLD是被阻塞的,比如在說:hi,內核,這會不要給我送SIGCHLD信號,等我忙完再說; 在該command執行期間,SIGINT和SIGQUIT是被忽略的,意思是進程收到這兩個信號後沒有任何動做。debug
再來看一下system()函數返回值:code
爲了更好的理解system()函數返回值,須要瞭解其執行過程,實際上system()函數執行了三步操做:進程
看一下system()函數的源碼內存
int system(const char * cmdstring) { pid_t pid; int status; if(cmdstring == NULL) { return (1); //若是cmdstring爲空,返回非零值,通常爲1 } if((pid = fork())<0) { status = -1; //fork失敗,返回-1 } else if(pid == 0) { execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); _exit(127); // exec執行失敗返回127,注意exec只在失敗時才返回如今的進程,成功的話如今的進程就不存在啦~~ } else //父進程 { while(waitpid(pid, &status, 0) < 0) { if(errno != EINTR) { status = -1; //若是waitpid被信號中斷,則返回-1 break; } } } return status; //若是waitpid成功,則返回子進程的返回狀態 }
因爲返回值是-1,所以比較懷疑fork執行失敗。在控制檯上輸入fork後,果真返回-1。fork返回-1主要由兩種緣由:系統達到最大進程數上限或者系統內存不足。因爲系統當前進程數並很少,所以懷疑內存不足。
0803版本中升級了因爲CPUH內存空間不足,致使升級失敗的問題。這個問題是經過將CPUL的100M內存挪至CPUH解決的。至此,問題已基本明確,確實是因爲挪動內存後,CPUL上的剩餘內存不足以fork。
其實這裏我有一個疑問,fork會複製父進程的數據空間、堆和棧的副本。所以,若是父進程的內存佔用超過系統總可用內存的50%,調用system或fork就會存在風險。而linux提供了另一個函數:vfork。vfork並不會複製父進程的完整地址空間,這個函數主要應用的場景就是fork後,當即調用exec(exec會使用新程序替換掉當前進程的正文段、數據段、堆和棧)。按照上面提到的fork流程,fork時須要大量的內存來存放父進程的地址空間,而在exec時又會當即用新程序替換掉。對於system調用失敗,僅僅是因爲內存不足以容納另外一份父進程地址空間,未免有點冤了。而直接使用vfork,則空閒內存並不須要那麼大,system爲什麼沒有使用更合適的vfork呢?字符串
有兩個解決方案,一個是從新調整CPUL以及CPUH的內存分配,另外一個是調整內核參數。
其中方案1存在必定的風險,由於內存的使用是動態的,若是分回來的過多,可能致使CPUH再次出現偶爾升級失敗,若是分過來的不夠,則有可能出現CPUL調用system失敗,所以,這裏主要考慮使用方案2。
在前面分析的過程當中,已經明確,是因爲觸發了Linux的虛擬內存保護,致使fork失敗。能夠經過修改/proc/sys/vm/overcommit_memory的值,來修改系統的虛擬內存保護策略。這個文件能夠取0、一、2三個值,含義以下:
0-Heuristic overcommit handling
0是LINUX系統的默認值。容許進程申請的內存超出一個合理(reasonable)值,若是進程申請超出的過多,則內存分配會被拒絕。若是進程超出範圍在合理值內,則也有可能觸發omm-kill,致使進程被殺死。
1-Always overcommit
接收進程申請的任何內存大小
2-Don’t overcommit
不容許超出內存總量。內存總量受另一個參數overcommit_ratio控制,系統總可用內存計算公式以下:
總可用內存 = (swap space + RAM size * overcommit_ratio)
可使用該選項爲系統預留必定量的內存。overcommit_ratio參數可經過修改/proc/sys/vm/overcommit_ratio設置。
考慮到咱們的代碼中出了system外,並無fork的需求,並且system在執行fork後會當即調用exec釋放掉申請的空間,所以咱們將overcommit_memory設置爲1。
解決方法:
在啓動腳本里增長:
echo 1 > /proc/sys/vm/overcommit_memory &