这里先介绍一下select函数:
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
/* 功能:监听多个描述符,阻塞等待有一个或者多个文件描述符,准备就绪。
内核将没有准备就绪的文件描述符,从集合中清掉了。
参数: nfds 最大文件描述符数 ,加1
readfds 读文件描述符集合
writefds 写文件描述符集合
exceptfds 其他异常的文件描述符集合
timeout 超时时间(NULL)
返回值:当timeout为NULL时返回0,成功:准备好的文件描述的个数 出错:-1
当timeout不为NULL时,如超时设置为0,则select为非阻塞,超时设置 > 0,则无描述符可被操作的情况下阻塞指定长度的时间
*/
那select函数怎么知道所监测的文件描述符可读或则可写了呢?
以下是select函数的底层驱动代码实现:
unsigned int mychar_poll(struct file *pfile,poll_table *wait)
{
struct my_cedv * my_dev=(struct my_cedv*)pfile->private_data;
unsigned int mask=0;
poll_wait(pfile,&my_dev->rd,wait);
poll_wait(pfile,&my_dev->we,wait);
if(my_dev->curlen>0)
{
mask|=POLLIN |POLLRDNORM;
}
if(N-my_dev->curlen>0)
{
mask |=POLLOUT | POLLWRNORM;
}
return mask;
}
-
poll_wait函数可以被 select/poll/epoll 等系统调用使用:
poll_wait
函数通常被用于为实现基于事件驱动 I/O 复用的系统调用提供支持,比如select
、poll
、epoll
等。当文件描述符上发生了对应的事件时(根据返回值mask),poll_wait
函数可以唤醒在该文件描述符上等待的进程(并且将对应的读文件描述符集合中对应的位置一),从而实现了对文件描述符事件状态的监听和通知。(当没有事件时就会休眠,放入等待队列中) -
当第一个if条件成立时,即有可读事件就会给mask赋值。当第二个if条件成立时,即有可写事件成立就会给mask赋值。
-
内核会根据mask值和
poll_wait
函数,将相应的进程唤醒。