一.总体说明
二.代码分析
2.1 在fs/select.c中 sys_select
-
int sys_select( unsigned long *buffer )
-
{
-
/* Perform the select(nd, in, out, ex, tv) system call. */
-
int i;
-
fd_set res_in, in = 0, *inp;
-
fd_set res_out, out = 0, *outp;
-
fd_set res_ex, ex = 0, *exp;
-
fd_set mask;
-
struct timeval *tvp;
-
unsigned long timeout;
-
-
mask = ~((~0) << get_fs_long(buffer++));
-
inp = (fd_set *) get_fs_long(buffer++);
-
outp = (fd_set *) get_fs_long(buffer++);
-
exp = (fd_set *) get_fs_long(buffer++);
-
tvp = (struct timeval *) get_fs_long(buffer);
-
-
if (inp)
-
in = mask & get_fs_long(inp);
-
if (outp)
-
out = mask & get_fs_long(outp);
-
if (exp)
-
ex = mask & get_fs_long(exp);
-
//1.当用户设置的timeout转为jiffies放在全局的current->timeout中
-
timeout = 0xffffffff; -->timeout设为-1
-
if (tvp) {
-
timeout = get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ); //看清楚这儿是等号
-
timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ; //将用户设置的timeout在这儿转为jiffies
-
timeout += jiffies; //加上当前的jiffies就是超时时的jiffies
-
}
-
current->timeout = timeout; //将这个超时值放在全局的current->timeout中
-
cli();
-
//2.在do_select中使用
-
i = do_select(in, out, ex, &res_in, &res_out, &res_ex); //在do_select中会用到这个current->timeout
-
if (current->timeout > jiffies)
-
timeout = current->timeout - jiffies;
-
else
-
timeout = 0;
-
sti();
-
current->timeout = 0;
-
if (i < 0)
-
return i;
-
if (inp) {
-
verify_area(inp, 4);
-
put_fs_long(res_in,inp);
-
}
-
if (outp) {
-
verify_area(outp,4);
-
put_fs_long(res_out,outp);
-
}
-
if (exp) {
-
verify_area(exp,4);
-
put_fs_long(res_ex,exp);
-
}
-
if (tvp) {
-
verify_area(tvp, sizeof(*tvp));
-
put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
-
timeout %= HZ;
-
timeout *= (1000000/HZ);
-
put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
-
}
-
if (!i && (current->signal & ~current->blocked))
-
return -EINTR;
-
return i;
-
}
2.2
在fs/select.c中 sys_select-->do_select
-
int do_select(fd_set in, fd_set out, fd_set ex,
-
fd_set *inp, fd_set *outp, fd_set *exp)
-
{
-
int count;
-
select_table wait_table;
-
int i;
-
fd_set mask;
-
-
mask = in | out | ex;
-
for (i = 0 ; i < NR_OPEN ; i++,mask >>= 1) {
-
if (!(mask & 1))
-
continue;
-
if (!current->filp[i])
-
return -EBADF;
-
if (!current->filp[i]->f_inode)
-
return -EBADF;
-
if (current->filp[i]->f_inode->i_pipe)
-
continue;
-
if (S_ISCHR(current->filp[i]->f_inode->i_mode))
-
continue;
-
if (S_ISFIFO(current->filp[i]->f_inode->i_mode))
-
continue;
-
return -EBADF;
-
}
-
repeat:
-
wait_table.nr = 0;
-
*inp = *outp = *exp = 0;
-
count = 0;
-
mask = 1;
-
for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
-
if (mask & in)
-
if (check_in(&wait_table,current->filp[i]->f_inode)) {
-
*inp |= mask;
-
count++;
-
}
-
if (mask & out)
-
if (check_out(&wait_table,current->filp[i]->f_inode)) {
-
*outp |= mask;
-
count++;
-
}
-
if (mask & ex)
-
if (check_ex(&wait_table,current->filp[i]->f_inode)) {
-
*exp |= mask;
-
count++;
-
}
-
}
-
//下面的if判断有好几个,这儿只关心current->timout
-
//如果current->timeout!=0则条件成立进入schedule(),然后goto repeat,即do_select并不结束
-
//如果current->timeout==0,则条件不成立,free_wait之后就return了
-
if (!(current->signal & ~current->blocked) && (wait_table.nr || current->timeout) && !count) {
-
current->state = TASK_INTERRUPTIBLE;
-
schedule(); -->这个函数里面有问题
-
free_wait(&wait_table);
-
goto repeat;
-
}
-
free_wait(&wait_table);
-
return count;
-
}
a. 如果用户设置了timeout,那么这儿的current->timeout!=0,就会不断的goto repeat,这个do_select就会永远执行下去,
那么这个timeout就起不到相应的作用了。
b. 肯定是有个地方会在超时结束时改变这个current->timeout,才会使得超时后跳出do_select,这个地方是哪儿呢?
2.3 在kernel/sched.c中
-
void schedule(void)
-
{
-
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
-
if (*p) {
-
//如果current->timeouttimeout设为0
-
if ((*p)->timeout && (*p)->timeout < jiffies) {
-
(*p)->timeout = 0;
-
if ((*p)->state == TASK_INTERRUPTIBLE)
-
(*p)->state = TASK_RUNNING;
-
}
-
...
-
}
-
...
-
switch_to(next);
-
}
2.4 稍微总结一下
a.如果用户在调用select时设置了timeout,则在sys_select中会把这个timeout转为jiffies,并加上当前的jiffies,构成超时时的jiffies
b. sys_select调用do_select,如果current->timeout不为0,则一直goto repeat进行循环,并调用schedule
c. schedule中进行判断:
c.1 如果current->timeout>=jiffies说明还没有到超时,不改变,do_select中goto repeate循环
c.2
如果current->timeout说明超时时间到了,就把current->timeout=0,则do_select循环结束,到了sys_select中了。
2.5沿着这条路再返回去
a. kernel/sched.c中发现current->timeouttimeout=0
b. kernel/select.c中do_select里面if(current->timeout) 条件不成立,就return了
c. kernel/select.c中sys_select里面
-
int sys_select( unsigned long *buffer )
-
{
-
i = do_select(in, out, ex, &res_in, &res_out, &res_ex); //这儿返回了
-
if (current->timeout > jiffies) //如果current->timeout>jiffies说明没有超时
-
timeout = current->timeout - jiffies; //没有超时(超时之前)就有描述符可读/写/异常,记录超时时间
-
else
-
timeout = 0; //如果是因为超时返回,就把tiemout设为0
-
sti();
-
current->timeout = 0;
-
...
-
if (tvp) {
-
verify_area(tvp, sizeof(*tvp)); //把这个时间报给用户层
-
put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
-
timeout %= HZ;
-
timeout *= (1000000/HZ);
-
put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
-
}
-
-
}
阅读(2598) | 评论(0) | 转发(0) |