关键词:errno、EMFILE、ulimit、lsof等等。linux
背景是在对程序进行压力测试,运行了一段时间以后出现一个复位操做失败。ide
这个复位操做经过打开一个设备,进行读写操做,已达到控制GPIO输入输出的目的。测试
通过初步分析发觉fopen()返回NULL指针,说明fopen()错误了。spa
可是要想知道错误缘由,还须要借助errno。经过errno为24,便可知道出错的缘由为EMFILE。指针
由errno-base.h可知,EMFILE是打开文件过多的意思。code
#define EMFILE 24 /* Too many open files */
首先明白系统对资源使用限制的,经过ulimit能够查看限制或者修改限制。blog
关于文件打开文件数目的限制经过ulimit -n查看,或者ulimit -n <file null>修改限制。ip
经过ulimit -n命令能够查看linux系统里打开文件描述符的最大值,通常缺省值是1024。资源
ulimit -a -f: file size (blocks) unlimited -t: cpu time (seconds) unlimited -d: data seg size (kb) unlimited -s: stack size (kb) 8192 -c: core file size (blocks) 0 -m: resident set size (kb) unlimited -l: locked memory (kb) 64 -p: processes 3274 -n: file descriptors 1024 -v: address space (kb) unlimited -w: locks unlimited -e: scheduling priority 0 -r: real-time priority 0
lsof显示系统全部打开文件,那么很简单经过lsof便可查看到相关信息。get
经过lsof能够看到打开的文件很是多,并且主要集中在uImage这个文件。
... 14232 /heop/package/AiApp/AiApp /heop/package/AiApp/uImage 14232 /heop/package/AiApp/AiApp /heop/package/AiApp/uImage 14232 /heop/package/AiApp/AiApp /heop/package/AiApp/uImage ...
而后看到uImage这个文件被打开了1000屡次,问题就很明了了。
经过走查代码,发现uImage文件在被打开后因为某些条件未fclose()。解决也比较简单。
open系统调用入口是do_sys_open(),经过get_unused_fd_flags()来得到可用的句柄号。
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) { ... fd = get_unused_fd_flags(flags); if (fd >= 0) { ... } putname(tmp); return fd; } SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode) { if (force_o_largefile()) flags |= O_LARGEFILE; return do_sys_open(AT_FDCWD, filename, flags, mode); }
而后就看看句柄是如何分配的,以及有什么限制。
经过rlimit(RLIMIT_NOFILE)能够得到系统对打开文件数目的限制,等同于ulimit -n。
而后__alloc_fd()应该着这个范围以内。当判断fd>=end的时候,返回-EMFILE。
int get_unused_fd_flags(unsigned flags) { return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags); } int __alloc_fd(struct files_struct *files, unsigned start, unsigned end, unsigned flags) { ... error = -EMFILE; if (fd >= end) goto out; ... out: spin_unlock(&files->file_lock); return error; }