關鍵詞: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; }