免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 651 | 回复: 0
打印 上一主题 下一主题

select()实现分析(转) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-09-27 10:18 |只看该作者 |倒序浏览
#undef __NFDBITS
#define __NFDBITS    (8 * sizeof(unsigned long))
#undef __FD_SETSIZE
#define __FD_SETSIZE    1024
#undef __FDSET_LONGS
#define __FDSET_LONGS    (__FD_SETSIZE/__NFDBITS)
typedef struct {
    unsigned long fds_bits [__FDSET_LONGS];
} __kernel_fd_set;
//由上可以看到可以支持1024个描述符
asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp,
            fd_set __user *exp, struct timeval __user *tvp)
{
    s64 timeout = -1;
    struct timeval tv;
    int ret;
    //将超时时间换成jiffies
    if (tvp) {
        if (copy_from_user(&tv, tvp, sizeof(tv)))
            return -EFAULT;
        if (tv.tv_sec = (u64)MAX_INT64_SECONDS)
            timeout = -1;    /* infinite */
        else {
            timeout = ROUND_UP(tv.tv_usec, USEC_PER_SEC/HZ);
            timeout += tv.tv_sec * HZ;
        }
    }
    ret = core_sys_select(n, inp, outp, exp, &timeout);
    //将剩余时间拷贝回用户空间进程
    if (tvp) {
        struct timeval rtv;
        if (current->personality & STICKY_TIMEOUTS)
            goto sticky;
        rtv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ));
        rtv.tv_sec = timeout;
        if (timeval_compare(&rtv, &tv) >= 0)
            rtv = tv;
        if (copy_to_user(tvp, &rtv, sizeof(rtv))) {
sticky:
            /*
            * If an application puts its timeval in read-only
            * memory, we don't want the Linux-specific update to
            * the timeval to cause a fault after the select has
            * completed successfully. However, because we're not
            * updating the timeval, we can't restart the system
            * call.
            */
            if (ret == -ERESTARTNOHAND)
                ret = -EINTR;
        }
    }
    return ret;
}
static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
               fd_set __user *exp, s64 *timeout)
{
    fd_set_bits fds;
    void *bits;
    int ret, max_fds;
    unsigned int size;
    struct fdtable *fdt;
    /* Allocate small arguments on the stack to save memory and be faster */
    long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
    ret = -EINVAL;
    if (n files);
    max_fds = fdt->max_fds; //从files结构中获取最值
    rcu_read_unlock();
    if (n > max_fds)
        n = max_fds;
    /*
    * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
    * since we used fdset we need to allocate memory in units of
    * long-words.
    */
        //我们需要使用6倍于最大描述符的描述符个数,
    //分别是in/out/ex, 并且每份有一个输入和一个输出(用于结果返回)
    size = FDS_BYTES(n);
    bits = stack_fds;
    if (size > sizeof(stack_fds) / 6) { //栈不能满足
        /* Not enough space in on-stack array; must use kmalloc */
        ret = -ENOMEM;
        bits = kmalloc(6 * size, GFP_KERNEL);
        if (!bits)
            goto out_nofds;
    }
    fds.in      = bits;
    fds.out     = bits +   size;
    fds.ex      = bits + 2*size;
    fds.res_in = bits + 3*size;
    fds.res_out = bits + 4*size;
    fds.res_ex = bits + 5*size;
    //将各个输入拷贝到fds中
    if ((ret = get_fd_set(n, inp, fds.in)) ||
        (ret = get_fd_set(n, outp, fds.out)) ||
        (ret = get_fd_set(n, exp, fds.ex)))
        goto out;
    //初始化用于输出的结果为0
    zero_fd_set(n, fds.res_in);
    zero_fd_set(n, fds.res_out);
    zero_fd_set(n, fds.res_ex);
    ret = do_select(n, &fds, timeout);
    if (ret in; outp = fds->out; exp = fds->ex;
        rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex;
        for (i = 0; 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)
                        mask = (*f_op->poll)(file, retval ? NULL : wait);
                    fput_light(file, fput_needed);
                    if ((mask & POLLIN_SET) && (in & bit)) {
                        res_in |= bit; //如果是这个描述符可读, 将这个位置位
                        retval++;   //返回描述符个数加1
                    }
                    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;
        }
        if (*timeout = (s64)MAX_SCHEDULE_TIMEOUT - 1)) {
            /* Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in a loop */
            __timeout = MAX_SCHEDULE_TIMEOUT - 1;
            *timeout -= __timeout;
        } else {
            __timeout = *timeout;
            *timeout = 0;
        }
        __timeout = schedule_timeout(__timeout);
        if (*timeout >= 0)
            *timeout += __timeout;
    }
    __set_current_state(TASK_RUNNING);
    poll_freewait(&table);
    return retval;
}


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/78225/showart_1226948.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP