首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

对select()参数fdset的完拾掇解

2012-12-23 
对select()参数fdset的完整理解虽然写了很多代码,但select我就从没有完整理解过,要用时不过copy paste而已

对select()参数fdset的完整理解

虽然写了很多代码,但select我就从没有完整理解过,要用时不过copy paste而已。惭愧!


今天决定要对select()参数fdset有一个完整理解。Go!


先上一段代码(代码1-1),这段代码做的事情是

1. 创建一个socket来listen请求

2. 调用select等待新请求、等待已有请求的数据收发状态READY

3. 当有新连接请求来的时候就调用accpet接受请求

4. 当有数据可读可写的时候就调用do_read/do_write执行数据收发

5. loop回去

注意:上面所有的操作都是在一个线程上做的。


看完代码,再看for循环内几个细节。

细节1. select前每次都要对三个fdset进行初始化。具体初始化策略就是:

   - listen fd总是要set,这表明希望select关心listen fd的变化

   - 已经accept了的fd总是要set,这表明希望select关心这些fd上是否可读可写

细节2. select后会对三个fdset的状态进行检查。具体检查结果是:

  - listen fd如果被set了,表明有新的连接请求来了,需要调用accept

 - readfdset中如果有fd被set了,表明那个fd上有新数据可读

 - writefdset中如果有fd被set了,表明那个fd上可以写数据进去


从上面两个细节中可以发现

int do_select(int n, fd_set_bits *fds, struct timespec *end_time){        ktime_t expire, *to = NULL;        struct poll_wqueues table;        poll_table *wait;        int retval, i, timed_out = 0;        unsigned long slack = 0;        rcu_read_lock();        retval = max_select_fd(n, fds);        rcu_read_unlock();        if (retval < 0)                return retval;        n = retval;        poll_initwait(&table);        [color=Red]wait = &table.pt;[/color]        if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {                wait = NULL;                timed_out = 1;        }        if (end_time && !timed_out)                slack = estimate_accuracy(end_time);        retval = 0;        for (;;) {                unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;// fdset的输入参数,表明关心哪些fd                inp = fds->in; outp = fds->out; exp = fds->ex;// fdset的输出参数,表明哪些关心的fd状态变成了可读可写可连接                rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex;// 这里看看n,就是外面传进来的max_fd,就很能理解为什么max_fd需要加1了                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;                        const 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) {// 性能优化代码。一次判断4个字节,32个fd,如果都不关心,则可以一次跳过                                i += __NFDBITS;                                continue;                           } // 32个fd中至少有一个fd是被用户关心的,得瞧瞧                        for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) {                                  int fput_needed;                                if (i >= n)                                        break;                                if (!(bit & all_bits))                                        continue;                                file = fget_light(i, &fput_needed);                                if (file) {                                        f_op = file->f_op;                                        mask = DEFAULT_POLLMASK;                                        if (f_op && f_op->poll)   //调用pool看这个fd是否ready                                                mask = (*f_op->poll)(file, retval ? NULL : wait);                                        fput_light(file, fput_needed);                                        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++;                                        }                                }                        }                        if (res_in)                                *rinp = res_in;                        if (res_out)                                *routp = res_out;                        if (res_ex)                                *rexp = res_ex;                        cond_resched();                }        return retval;}


对select的理解欲是被昨晚看的《编程人生》第一篇文章激发的, Jamie Zawinski:好奇心是驱动一个程序员的终极原动力,唯有好奇心才能让你对code了如指掌。


我的微博:http://weibo.com/raywill2



热点排行