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是最关键的一个结构体,
1 struct poll_wqueues { 2 poll_table pt; 3 struct poll_table_page * table; 4 int error; 5 int inline_index; 6 struct poll_table_entry inline_entries[N_INLINE_POLL_ENTRIES]; 7 };
poll_table结构体只包含一个函数指针,初始化时指向
void __pollwait(struct file *filp, wait_queue_head_t *wait_address,poll_table *p)
1 typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *); 2 3 typedef struct poll_table_struct { 4 poll_queue_proc qproc; 5 } poll_table;
poll_table_page就是包含poll_table_entry结构的链表,作用与inline_entries[N]相同,检测文件数少的时候用不到这个结构
1 struct poll_table_page { 2 struct poll_table_page * next; 3 struct poll_table_entry * entry; 4 struct poll_table_entry entries[0]; 5 };
poll_table_entry包含文件指针,等待队列及等待队列头
1 struct poll_table_entry { 2 struct file * filp; 3 wait_queue_t wait; 4 wait_queue_head_t * wait_address; 5 };
4.操作
poll_wqueues初始化
1 static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc) 2 { 3 pt->qproc = qproc; 4 } 5 void poll_initwait(struct poll_wqueues *pwq) 6 { 7 init_poll_funcptr(&pwq->pt, __pollwait); 8 pwq->error = 0; 9 pwq->table = NULL; 10 pwq->inline_index = 0; 11 }
那么poll_table结构中的函数什么时候使用及干什么呢?
我们自己在驱动中的poll函数中会调用poll_wait()函数
1 static unsigned forth_drv_poll(struct file *file, poll_table *wait) 2 { 3 unsigned int mask = 0; 4 poll_wait(file, &button_waitq, wait); // 不会立即休眠 5 6 if (ev_press) 7 mask |= POLLIN | POLLRDNORM; 8 9 return mask; 10 }
而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); }
1 /* Add a new entry */ 2 static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, 3 poll_table *p) 4 { 5 struct poll_table_entry *entry = poll_get_entry(p); 6 if (!entry) 7 return; 8 get_file(filp); 9 entry->filp = filp; 10 entry->wait_address = wait_address; //即forth_drv_poll中传入的button_waitq等待队列头 11 init_waitqueue_entry(&entry->wait, current); 12 add_wait_queue(wait_address, &entry->wait); 13 }