问题分析: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 &