一、概述
- 应用程序可以使用poll,select,epoll三种形式,其中poll和select由两个不同的Unix团队分别实现的:select在BSD Unix中引入,而poll由System V引入。epoll,它用于将poll函数扩展到能够处理数千个文件描述符。所有三个系统调用均通过驱动程序的poll方法提供,原型如下:
unsigned int (*poll) (struct file *filp, poll_table *wait); - 该方法分两步处理:
1.如果当前没有文件描述符可用来执行I/O,则内核将使进程在传递到该系统调用的所有文件描述符对应的等待队列上等待。
2.返回一个用来描述操作是否可以立即无阻塞执行的位掩码。
二、poll相关数据结构描述
1. poll_table数据结构
typedef struct poll_table_struct {
poll_queue_proc _qproc;
unsigned long _key;
} poll_table;
这个数据结构里面最重要的就是_qproc函数指针,在poll_wait函数中会调用
2. poll_table_entry数据结构
struct poll_table_entry {
struct file *filp;
unsigned long key;
wait_queue_t wait;
wait_queue_head_t *wait_address;
};
该数据结构包含一个打开的设备文件的指针,poll_table中的key,一个等待队列入口(元素),一个等待队列头,这个结构体相当重要
3. poll_wqueues数据结构
struct poll_wqueues {
poll_table pt;
struct poll_table_page *table;
struct task_struct *polling_task;
int triggered;
int error;
int inline_index;
struct poll_table_entry inline_entries[N_INLINE_POLL_ENTRIES];
};
该数据结构包含以上的poll_table和poll_table_entry数据结构,polling_task进程数据结构
三、驱动中的poll函数及中断机制
1.poll函数实现
static unsigned int xxx_poll(struct file *fp, poll_table * wait)
{
unsigned int mask =0;
poll_wait(fp, &button_wait, wait);
//中断事件标志, 1:退出休眠状态 0:进入休眠状态
//当超时,就返给应用层为0 ,被唤醒了就返回POLLIN | POLLRDNORM ;
if(even_press)
mask |= POLLIN | POLLRDNORM ;
return mask;
}
2.中断的实现
static irqreturn_t buttons_irq (int irq, void *dev_id)
{
...
even_press=1;
wake_up_interruptible(&button_wait);
...
}
3.驱动机制描述
- 当有中断产生,比如按键按下,cpu会立即执行中断处理函数,在这里设置event_press变量,同时唤醒挂在等待队列button_wait上的所有进程。
- 当xxx_poll函数执行的时候,首先调用poll_wait函数,实际调用wait->_qproc函数,主要作用是将当前进程(调用poll系统调用的进程)添加进button_wait等待队列。然后判断event_press变量是否置位,如果置位则表示中断已产生,则返回相应的掩码给应用程序判断数据可读。
四、poll系统调用及内核poll深入分析
1.应用程序poll函数解析
-
poll系统调用原型
int poll(struct pollfd fds[], nfds_t nfds, int timeout); struct pollfd { int fd; short events; short revents; };
这个结构中fd表示文件描述符,events表示请求检测的事件,revents表示检测之后返回的事件,如果当某个文件描述符有状态变化时,revents的值就不为空。
- poll系统调用参数说明
- fds:存放需要被检测状态的文件描述符;与select不同(select函数在调用之后,会清空检测文件描述符的数组),每当调用这个函数之后,系统不会清空这个数组,而是将有状态变化的描述符结构的revents变量状态变化,操作起来比较方便;
- nfds:用于标记数组fds中的struct pollfd结构元素的总数量;
- timeout:poll函数调用阻塞的时间,单位是ms(毫秒)
- poll系统调用返回值
- 大于0:表示数组fds中有socket描述符的状态发生变化,或可以读取、或可以写入、或出错。并且返回的值表示这些状态有变化的socket描述符的总数量;此时可以对fds数组进行遍历,以寻找那些revents不空的socket描述符,然后判断这个里面有哪些事件以读取数据。
- 等于0:表示没有socket描述符有状态变化,并且调用超时。
- 小于0:此时表示有错误发生,此时全局变量errno保存错误码。