java中select函数_Select函数源码剖析

源码一进来就可以发现,它的事件是通过宏来实现的

#define FDS_IN(fds, n) (fds->in + n) //读事件

#define FDS_OUT(fds, n) (fds->out + n) //写事件

#define FDS_EX(fds, n) (fds->ex + n) //异常事件

#define BITS(fds, n) (FDS_IN(fds, n)|FDS_OUT(fds, n)|*FDS_EX(fds, n))//通过一个位图可以同时监听三种事件

这就是位图本来的样子

typedef struct {

unsigned long *in, *out, *ex;

unsigned long *res_in, *res_out, *res_ex;

} fd_set_bits;

这是select的函数主体

int do_select(int n, fd_set_bits *fds, long *timeout);

首先找出最大的文件描述符

spin_lock(&current->files->file_lock);

retval = max_select_fd(n, fds);

spin_unlock(&current->files->file_lock);

if (retval < 0)

return retval; //如果最大值还是小于0,报错

n = retval; //将n设置成它最大值加1

这里可以看一下max_select_fd()函数,目的是找出最大的fd的值+1

static int max_select_fd(unsigned long n, fd_set_bits *fds)

{

unsigned long *open_fds;

unsigned long set;

int max;

/* handle last in-complete long-word first */

set = ~(~0UL << (n & (__NFDBITS-1))); //将传入的n最高位往后取1(究竟有多少要检查的fd)

n /= __NFDBITS; //类似于哈希函数一样,对n取一个下标位置

open_fds = current->files->open_fds->fds_bits+n; //打开fd

max = 0;

if (set) {

set &= BITS(fds, n); //寻找一下n在fds位图中的位置

if (set) { //如果在容器中已经存在

if (!(set & ~*open_fds)) //检查一下文件是不是已经打开?

goto get_max; //打开都OK的话那么找到最大值开始遍历吧

return -EBADF;

}

}

//开始遍历

while (n) {

open_fds--;

n--;

set = BITS(fds, n); //检查在n处有没有注册的fd

if (!set) //如果没有,抬走下一位

continue;

if (set & ~*open_fds) //如果有,但是文件没有打开的话报错

return -EBADF;

if (max) //

continue;

get_max:

do {

max++;

set >>= 1;

} while (set); //max出来是最高fd的位数加1

max += n * __NFDBITS; //max出来是最大fd的值加一

}

return max;

}

进行初始化变量

poll_initwait(&table);

wait = &table.pt;

if (!__timeout) //如果没有超时的话,wait置空

wait = NULL;

retval = 0;

核心部分

for (;;) {

unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;

set_current_state(TASK_INTERRUPTIBLE);//将此进程设为可中断阻塞

inp = fds->in; outp = fds->out; exp = fds->ex;

rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex;

//核心中的核心……………………词穷。。。真正开始遍历

for (i = 0; i < n; ++rinp, ++routp, ++rexp) {

unsigned long in, out, ex, all_bits, bit = 1, mask, j;

unsigned long res_in = 0, res_out = 0, res_ex = 0;

struct file_operations *f_op = NULL;

struct file *file = NULL;

in = *inp++; out = *outp++; ex = *exp++;

all_bits = in | out | ex; //所有注册事件

if (all_bits == 0) { i += __NFDBITS;

continue;

}

for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) {

if (i >= n) //到了最大描述符+1的位置,循环结束

break;

if (!(bit & all_bits)) //如果当前位置没有注册,进入下一次

continue;

file = fget(i); //拿取当前的文件描述符

if (file) { //检测三种事件

f_op = file->f_op;

mask = DEFAULT_POLLMASK;

if (f_op && f_op->poll)

mask = (*f_op->poll)(file, retval ? NULL : wait);

fput(file);

if ((mask & POLLIN_SET) && (in & bit)) {

res_in |= bit;

retval++;

}

if ((mask & POLLOUT_SET) && (out & bit)) {

res_out |= bit;

retval++;

}

if ((mask & POLLEX_SET) && (ex & bit)) {

res_ex |= bit;

retval++;

}

}

cond_resched();

}

if (res_in)

*rinp = res_in;

if (res_out)

*routp = res_out;

if (res_ex)

*rexp = res_ex;

}

//循环退出部分

wait = NULL;

//对所有的文件描述符进行询问后,检查是否有事件就绪、超时或者收到信号,就跳出循环

if (retval || !__timeout || signal_pending(current))

break;

//检查是否出错,如果出错,就跳出循环

if(table.error) {

retval = table.error;

break;

}

__timeout = schedule_timeout(__timeout);

//继续当前进程

__set_current_state(TASK_RUNNING);

//释放位图

poll_freewait(&table);

//更新超时时间

*timeout = __timeout;

return retval;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值