根据linux内核源码查找recv返回EBADF(errno 9)的原因
linux的内核版本是2.6.18,x86_64.
man里的解释是:
EBADF |
The argument s is an invalid descriptor |
我的模拟测试环境是:
前端loadrunner模拟web点击,通过后端的weblogic压自己的服务的时候发现,有时候recv会收到这个错误,意思就是这个fd已经失效了,但是有点不是很明白,所以查询下内核实现,验证下。
首先recv的实现就是调用的recvfrom:
/*
* Receive a datagram from a socket.
*/ asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags)
{
return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL);
}
然后看
sys_recvfrom
的实现:
asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned flags,
struct sockaddr __user *addr, int __user *addr_len)
{
struct socket *sock;
struct iovec iov;
struct msghdr msg;
char address[MAX_SOCK_ADDR];
int err,err2;
struct file *sock_file;
int fput_needed; sock_file = fget_light(fd, &fput_needed);
if (!sock_file)
return -EBADF; sock = sock_from_file(sock_file, &err);
if (!sock)
goto out; msg.msg_control=NULL;
msg.msg_controllen=0;
msg.msg_iovlen=1;
msg.msg_iov=&iov;
iov.iov_len=size;
iov.iov_base=ubuf;
msg.msg_name=address;
msg.msg_namelen=MAX_SOCK_ADDR;
if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT;
err=sock_recvmsg(sock, &msg, size, flags); if(err >= 0 && addr != NULL)
{
err2=move_addr_to_user(address, msg.msg_namelen, addr, addr_len);
if(err2<0)
err=err2;
}
out:
fput_light(sock_file, fput_needed);
return err;
}
从代码内可以看到是fget_light这个函数如果返回NULL,则对外报EBADF错误。
那么fget_light这个函数做了什么呢,继续看代码:
/*
* Lightweight file lookup - no refcnt increment if fd table isn't shared.
* You can use this only if it is guranteed that the current task already
* holds a refcnt to that file. That check has to be done at fget() only
* and a flag is returned to be passed to the corresponding fput_light().
* There must not be a cloning between an fget_light/fput_light pair.
*/
struct file fastcall *fget_light(unsigned int fd, int *fput_needed)
{
struct file *file;
struct files_struct *files = current->files; *fput_needed = 0;
/* 如果你的程序是多线程的,或者多进程并且进程间是通过clone产生并且带着CLONE_FILES标识,
那么此处&files->count值不为1 */
if (likely((atomic_read(&files->count) == 1))) {
file = fcheck_files(files, fd);
} else {
rcu_read_lock();
file = fcheck_files(files, fd);
if (file) {
/* 因为要引用和此fd相关的struct file结构,所以需要将引用计数器加1,
但是只有在f_count不为0的时候才去加1,如果f_count为0,说明此fd已经
被close掉,并且释放掉资源了。*/
if (atomic_inc_not_zero(&file->f_count))
*fput_needed = 1;
else
/* Didn't get the reference, someone's freed */
file = NULL;
}
rcu_read_unlock();
} return file;
}
再看函数fcheck_files
static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
{
struct file * file = NULL;
struct fdtable *fdt = files_fdtable(files); if (fd < fdt->max_fds)
file = rcu_dereference(fdt->fd[fd]);
return file;
}
其实到这里就可以看出来,fget_light总共有两个地方返回NULL,
1、fcheck_files内发现fd > fdt->max_fds 会返回NULL,这种情况一般不会发生,除非你调用recv的时候传入的fd值不是真实使用的fd,而是一个很大的值。
2、当我们要增加引用计数的时候,发现这个引用计数是0,也就是说被你自己进程的其他线程close了。
max_fds可以简单通过/proc/pid/status的FDSize查看值,这个max_fds其实是计算出来的,下面给出算法
/* NR_OPEN_DEFAULT就是long的bit数,x86是32,x64是64 */
nfds = NR_OPEN_DEFAULT;
/*
* Expand to the max in easy steps, and keep expanding it until
* we have enough for the requested fd array size.
*/
do {
#if NR_OPEN_DEFAULT < 256
if (nfds < 256)
nfds = 256;
else
#endif
if (nfds < (PAGE_SIZE / sizeof(struct file *)))
nfds = PAGE_SIZE / sizeof(struct file *);
else {
nfds = nfds * 2;
if (nfds > NR_OPEN)
nfds = NR_OPEN;
}
} while (nfds <= nr);
初始值是NR_OPEN_DEFAULT就是long的bit数,x64是64,x86是32,
如果超过这个就变成256,如果超过256就4096/8就是512,超过512就是
512*2=1024,再超过就是1024*2=2048,一直这样成倍增加,直到最大值NR_OPEN,是1024*1024=1048576
可能会有人问,不是还有ulimit设置的open files的限制的吗?
恩,是有,这个叫做进程的资源限制,不过这个检查是在分配新的fd,比如accept这时候去检查的,如果新的fd大于那个限制是会直接报错EMFILE这个错误的。
根据linux内核源码查找recv返回EBADF(errno 9)的原因的更多相关文章
- Linux内核源码分析方法
一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都 ...
- 【转】Linux内核源码分析方法
一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都 ...
- Linux内核源码分析方法_转
Linux内核源码分析方法 转自:http://www.cnblogs.com/fanzhidongyzby/archive/2013/03/20/2970624.html 一.内核源码之我见 Lin ...
- linux内核源码注解
轻松学习Linux操作系统内核源码的方法 针对好多Linux 爱好者对内核很有兴趣却无从下口,本文旨在介绍一种解读linux内核源码的入门方法,而不是解说linux复杂的内核机制:一.核心源程序的文件 ...
- Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)
http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...
- Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】
原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.c ...
- <Linux内核源码>文件系统VFS内核4.0.4版本基本概念源码
题外话:Linux内核从2.x和3.x到现在最新的4.x变化非常大,最直观的表现就是很多书上的内核代码已经无法直接继续使用,所以看看新的源码是非常有意义的! (下文中的内核源码都来自于 kernel ...
- Linux内核源码特殊用法
崇拜并且转载的: http://ilinuxkernel.com/files/5/Linux_Kernel_Source_Code.htm Linux内核源码特殊用法 1 前言 Linux内核源码主要 ...
- Linux内核源码分析之setup_arch (二)
1. 概述 接着上一篇<Linux内核源码分析之setup_arch (一)>继续分析,本文首先分析arm_memblock_init函数,然后分析内核启动阶段的是如何进行内存管理的. 2 ...
随机推荐
- Selenium2学习-029-WebUI自动化实战实例-027-判断元素是否存在
非常简单的源码,敬请各位小主参阅.若有不足之处,敬请大神指正,不胜感激! /** * Verify the element exist or not * * @author Aaron.ffp * @ ...
- Windows-007-进程相关命令(netstat、tasklist、taskkill、tskill)实战实例图文详解
本节主要讲述 Windows 系统下,nestat.tasklist.tskill 三个 CMD 命令的参数,及使用方法:以及如何利用三者结合查看进程信息和结束进程.敬请亲们参阅,希望能对亲们有所帮助 ...
- iOS开发中(null)与<null>的判断
判断(null): if(m_result==nil) { NSLog(@"KDA!"); } 判断<null>: if([m_result isEqual: ...
- 学习WEb前端开发的需要哪些条件
第一阶段--HTML的学习. 超文本标记语言(HyperText Mark-up Language 简称HTML)是一个网页的骨架,无论是静态网页还是动态网页,最终返回到浏览器端的都是HTML代码,浏 ...
- iOS: 使用KVO监听控制器中数组的变化
一.介绍: KVO是一种能动态监听到属性值的改变的方式,使用场景非常广泛,这里我只讲如何监听控制器ViewController中数组的变化. 二.了解: 首先我们应该知道KVO是不能直接监听控制器Vi ...
- 在Ubutu14.04的Eclipse启动Tomcat的问题
PS:因为tomcat文件夹的权限问题,导致我研究了一中午,首先是New Server时,不能输入server name,之后我删除了 org.eclipse.wst.server.core.pref ...
- sequelize翻译(1)
第一次翻译(由mongoose转了mysql) v 3.0.0 1.Sequelize类 2.sequelize对象 3.sequelize.define()返回的表对象 4.表对象的方法 1.Seq ...
- Java控制语句——if语句
Java控制语句分为三大类:①顺序结构:②选择结构:③循环结构. 选择结构又分为:①单选择结构:②双选择结构:③多选择结构. 主要涉及: if_else , switch , while , brea ...
- Java最全文件操作实例汇总
本文实例汇总了Java文件操作.分享给大家供大家参考,具体如下: 1.创建文件夹 ? 1 2 3 4 5 6 7 8 9 10 11 //import java.io.*; File myFolder ...
- 搭建企业cacti服务器
搭建企业cacti服务器 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 今天搭建了cacti,为了方便监控我的交换机~因为查了很多zabbix的资料关于监控交换机的教程~我都屡屡失 ...