1.用户空间调用(参考 poll(2) - Linux man page

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

it waits for one of a set of file descriptors to become ready to perform I/O.

The set of file descriptors to be monitored is specified in the fds argument, which is an array of structures of the following form:

struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};

关于timeout参数的说明:

  timeout>0,设置超时时间为timeout

  timeout=0,直接返回

  timeout<0,无限长超时时间

返回值说明:

On success, a positive number is returned; this is the number of structures which have nonzero revents fields (in other words, those descriptors with events or errors reported).

A value of 0 indicates that the call timed out and no file descriptors were ready. On error, -1 is returned, and errno is set appropriately.

2.内核调用

asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,long timeout_msecs)
-->ret = do_sys_poll(ufds, nfds, &timeout);
-->struct poll_wqueues table;
-->poll_initwait(&table);
-->init_poll_funcptr(&pwq->pt, __pollwait);
-->把ufds指向的用户空间数据拷贝到内核空间,由poll_list结构体保存
-->fdcount = do_poll(nfds, head, &table, timeout);
for (;;) {
-->set_current_state(TASK_INTERRUPTIBLE);
-->for (walk = list; walk != NULL; walk = walk->next) //遍历poll_list结构中的pollfd结构
-->do_pollfd(pfd, pt)
-->if (file->f_op && file->f_op->poll) //驱动中的poll函数
--> void __pollwait(struct file *filp, wait_queue_head_t *wait_address,poll_table *p)
-->struct poll_table_entry *entry = poll_get_entry(p);
-->entry->filp = filp;
-->entry->wait_address = wait_address;
-->init_waitqueue_entry(&entry->wait, current);
-->add_wait_queue(wait_address, &entry->wait);//加入等待队列头
-->return mask;//返回设备是否可读写状态
-->if (count || !*timeout || signal_pending(current))
break;//设备可读写,超时时间到,有信号中断三种情况都返回
-->__timeout = schedule_timeout(__timeout);//进程调度,休眠
}
//唤醒后返回
-->__set_current_state(TASK_RUNNING);
-->return count;
-->把poll_list结构体保存的pollfd.revents返回给用户空间的ufds数组
-->poll_freewait(&table);//释放poll_table_entry中的等待队列

3.相关结构体都在fs/select.c,include/linux/poll.h

poll_wqueues是最关键的一个结构体,

 struct poll_wqueues {
poll_table pt;
struct poll_table_page * table;
int error;
int inline_index;
struct poll_table_entry inline_entries[N_INLINE_POLL_ENTRIES];
};

poll_table结构体只包含一个函数指针,初始化时指向

void __pollwait(struct file *filp, wait_queue_head_t *wait_address,poll_table *p)

 typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *);

 typedef struct poll_table_struct {
poll_queue_proc qproc;
} poll_table;

poll_table_page就是包含poll_table_entry结构的链表,作用与inline_entries[N]相同,检测文件数少的时候用不到这个结构

 struct poll_table_page {
struct poll_table_page * next;
struct poll_table_entry * entry;
struct poll_table_entry entries[];
};

poll_table_entry包含文件指针,等待队列及等待队列头

 struct poll_table_entry {
struct file * filp;
wait_queue_t wait;
wait_queue_head_t * wait_address;
};

4.操作

poll_wqueues初始化

 static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc)
{
pt->qproc = qproc;
}
void poll_initwait(struct poll_wqueues *pwq)
{
init_poll_funcptr(&pwq->pt, __pollwait);
pwq->error = ;
pwq->table = NULL;
pwq->inline_index = ;
}

那么poll_table结构中的函数什么时候使用及干什么呢?

我们自己在驱动中的poll函数中会调用poll_wait()函数

 static unsigned forth_drv_poll(struct file *file, poll_table *wait)
{
unsigned int mask = ;
poll_wait(file, &button_waitq, wait); // 不会立即休眠 if (ev_press)
mask |= POLLIN | POLLRDNORM; return mask;
}

而poll_wait()函数最终会调用__pollwait()函数

static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
{
if (p && wait_address)
p->qproc(filp, wait_address, p);
}
 /* Add a new entry */
static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
poll_table *p)
{
struct poll_table_entry *entry = poll_get_entry(p);
if (!entry)
return;
get_file(filp);
entry->filp = filp;
entry->wait_address = wait_address; //即forth_drv_poll中传入的button_waitq等待队列头
init_waitqueue_entry(&entry->wait, current);
add_wait_queue(wait_address, &entry->wait);
}

最新文章

  1. 7.2WebApi2中的全局异常处理
  2. mysql二进制文件操作语法(mysql binary log operate statements)
  3. 使用OpenLDAP构建基础账号系统
  4. IntelliJ IDEA 修改包名
  5. 配置Junit测试程序
  6. 亚马逊 在线测试题目 amazon (变种的)三叉树的最近公共祖先问题
  7. 基于Python的密码生成程序的优化
  8. C#和Javascript中 正则表达式使用的总结
  9. scala学习笔记:函数与方法
  10. Summary Ranges 解答
  11. JS实现AOP拦截方法调用
  12. POJ 2479 Maximum sum 解题报告
  13. [02] Servlet获取请求和页面跳转
  14. java中log4j学习笔记
  15. Func和Action委托简单用法
  16. WordPress博客彻底关闭图片缩略图功能的方法
  17. 【网站建设】Linux上安装MySQL - 12条命令搞定MySql
  18. js如何调用php文件内显示的数值到html?
  19. Redis深入学习笔记(一)Redis启动数据加载流程
  20. linux 内核分析工具 Dtrace、SystemTap、火焰图、crash等

热门文章

  1. python入门之递归
  2. 转 php include
  3. PHP采集利器 Snoopy 试用心得
  4. 记住,永远不要在MySQL中使用“utf8”-转
  5. JS的文本框验证以及form表单的提交阻止
  6. 数据库查询,显示为树形结构(easyui+SSM)
  7. Java编程基础-运算符
  8. Number of 1 BitsWrite a function that takes an unsigned integer and returns the number of ’1&#39; bits i
  9. Android - CollapsingToolbarLayout 完全解析
  10. Selenium私房菜系列9 -- 我遇到的问题及解决问题的方法