select源码分析
select()
函数是从SYSCALL_DEFINE5(select, ...)
开始. 可以简单的将SYSCALL_DEFINEx
理解为系统定义的系统函数, 如果想了解 SYSCALL_DEFINE 可以看一下.
具体的执行流程是 :
- 将时间定义从用户空间复制到内核空间中, 进行时间片的设置, 如果为0或不合法就设置为默认值, 否则就设置为传入的时间.
- 调用
core_sys_select
函数, 以实现等待消息到来, 轮询等主要操作 - 调用
timeval_compare
返回执行完剩余的时间 - 最后将返回的时间使用
copy_to_user
复制到用户空间
SYSCALL_DEFINE5(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;
if (tvp)
{
// 将数据从用户空间拷贝到内核空间的tv中
if (copy_from_user(&tv, tvp, sizeof(tv)))
return -EFAULT;
...
}
// 设置 fds 结构的参数并且等待消息的到来, 或者时间片没有结束调度程序
ret = core_sys_select(n, inp, outp, exp, &timeout);
// 设置时间片
if (tvp)
{
...
// 返回执行完后剩余时间
if (timeval_compare(&rtv, &tv) >= 0)
rtv = tv;
if (copy_to_user(tvp, &rtv, sizeof(rtv)))
...
}
return ret;
}
core_sys_select
因为select的主要功能都是do_select
函数, 这里我们先分析一下关于core_sys_select函数.
- 获取文件文件描述符表并存放在
fdtable
中 - 为
fdtable
读, 写, 错误分配空间, 并初始化 - 将select传入的
readfds
,writefds
,errorfds
参数从用户空间复制到内核空间的fdtable
对应的读, 写, 错误中. 这里需要解释一下, fdselect主要是保存之后要将来的信号返回给用户空间的. - 调用
do_select
, 轮询等待消息的到来, 并