关键词:errno、EMFILE、ulimit、lsof等等。

背景是在对程序进行压力测试,运行了一段时间之后出现一个复位操作失败。

这个复位操作通过打开一个设备,进行读写操作,已达到控制GPIO输入输出的目的。

1. 初步分析原因

经过初步分析发觉fopen()返回NULL指针,说明fopen()错误了。

但是要想知道错误原因,还需要借助errno。通过errno为24,即可知道出错的原因为EMFILE。

由errno-base.h可知,EMFILE是打开文件过多的意思。

#define    EMFILE        24    /* Too many open files */

2. 找到是谁打开了哪个文件而没有释放

首先明白系统对资源使用限制的,通过ulimit可以查看限制或者修改限制。

关于文件打开文件数目的限制通过ulimit -n查看,或者ulimit -n <file null>修改限制。

通过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)
-c: core file size (blocks)
-m: resident set size (kb) unlimited
-l: locked memory (kb)
-p: processes
-n: file descriptors 1024
-v: address space (kb) unlimited
-w: locks unlimited
-e: scheduling priority
-r: real-time priority

lsof显示系统所有打开文件,那么很简单通过lsof即可查看到相关信息。

通过lsof可以看到打开的文件非常多,而且主要集中在uImage这个文件。

...
/heop/package/AiApp/AiApp /heop/package/AiApp/uImage
/heop/package/AiApp/AiApp /heop/package/AiApp/uImage
/heop/package/AiApp/AiApp /heop/package/AiApp/uImage
...

然后看到uImage这个文件被打开了1000多次,问题就很明了了。

通过走查代码,发现uImage文件在被打开后由于某些条件未fclose()。解决也比较简单。

3. EMFILE出现代码走查

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 >= ) {
...
}
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, , 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;
}

最新文章

  1. JavaScript Arguments.callee解释
  2. Android Studio 导入百度地图jar和so的正确方式
  3. 处理大并发之五 使用libevent利器bufferevent
  4. java socket 网络编程常见异常
  5. java操作数据库出错
  6. Warp divergence
  7. cocos2dx从入门到精通课程
  8. Android ContentProvider的实现
  9. 【笔记】UML核心元素
  10. CircleDisplay
  11. hdu 4604 动态规划
  12. d008: 求两数的整数商 和 商
  13. UVA 12263 Rankings(拓扑排序)
  14. 国内Android应用推广的六大主流方式
  15. Linux C编程一站式学习读书笔记——socket编程
  16. udp接收
  17. 如何使用 IDEA 创建项目并且上传到 GitHub
  18. UVALive - 4222
  19. linux下添加逻辑分区并挂载(手动和自动方式)
  20. 用C#创建一个窗体,在构造函数里面写代码和在from_load事件里面写代码有什么不同?

热门文章

  1. standard_init_linux.go:207: exec user process caused &quot;no such file or directory&quot;
  2. 记一个AbstractMethodError
  3. weed3-1.hello world
  4. [认证 &amp; 授权] 3. 基于OAuth2的认证(译)
  5. WebShell代码分析溯源(九)
  6. GitLab基本设置-新增用户
  7. 【转载】C#中decimal保留2位有效小数
  8. FS-Cache 调研
  9. mongodb基本安装
  10. THUWC2019酱油记