理解poll_wait

来源:互联网 发布:windows错误恢复都不行 编辑:程序博客网 时间:2024/06/07 23:32

poll_wait()是用在select系统调用中的.

一般你的代码会有一个struct file_operations结构,
其中fop->poll函数指针指向一个你自己的函数,
在这个函数里应该调用poll_wait()

当用户调用select系统调用时,select系统调用会
先调用
poll_initwait(&table);
然后调用你的
fop->poll();
从而将current加到某个等待队列(这里调用poll_wait()),
并检查是否有效
如果无效就调用
schedule_timeout();
去睡眠.

事件发生后,schedule_timeout()回来,调用
fop->poll();
检查到可以运行,就调用
poll_freewait(&table);

从而完成select系统调用.

重要的是fop->poll()里面要检查是否就绪,
如果是,要返回相应标志

参见内核的函数:
fs/select.c/do_select()


 
 
1 等待队列的使用
 
DECLARE_WAITQUEUE(wait, current);
 
#define __WAITQUEUE_INITIALIZER(name, tsk) {                \
     .private    = tsk,                        \
     .func        = default_wake_function,            \
     .task_list    = { NULL, NULL } }
 
#define DECLARE_WAITQUEUE(name, tsk)                    \
     wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
 
一目了然,给wait这个等待队列赋值,private用来表示被唤醒的进程,这里current代表了本进程, 而func是被唤醒时调用的回调函数, 唤醒private!
 
add_wait_queue(w_wait, wait);
 将wait加入到等待队列w_wait中, 被唤醒时遍历w_wait队列!
 
wake_up(w_wait)
 唤醒w_wait, 遍历队列中的wait, 调用wait的func来唤醒private
 
所以用法为
 task 1
     DECLARE_WAITQUEUE(wait, current);
     add_wait_queue(w_wait, wait);
     __set_current_state(TASK_INTERRUPTIBLE);
     schedule();
     //task1 进程休眠
     ................//唤醒后从这儿执行
 task 2 //唤醒task1
    wake_up(w_wait);
 

2 poll_wait使用
   主要用于非阻塞访问时应用层select的调用
   驱动实现为
   down(&dev->sem);
 
  poll_wait(filp, &dev->r_wait, wait);
   poll_wait(filp, &dev->w_wait, wait);
   /*fifo非空*/
   if (dev->current_len != 0)
   {
     mask |= POLLIN | POLLRDNORM;
   }
   /*fifo非满*/
   if (dev->current_len != GLOBALFIFO_SIZE)
   {
     mask |= POLLOUT | POLLWRNORM;
  }
 
  up(&dev->sem);
   和do_select配合使用
 
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); //是在do_select中的poll_init_wait中为__pollwait
 }
 
  /* Add a new entry */
 static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
                 poll_table *p)
 {
     struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);
     struct poll_table_entry *entry = poll_get_entry(pwq);
     if (!entry)
         return;
     get_file(filp);
     entry->filp = filp;
     entry->wait_address = wait_address;
     entry->key = p->key;
     init_waitqueue_func_entry(&entry->wait, pollwake);
     entry->wait.private = pwq;
     add_wait_queue(wait_address, &entry->wait); // 把p中的entry->wait加入到等待队列
 }
 
void poll_initwait(struct poll_wqueues *pwq)
 {
     init_poll_funcptr(&pwq->pt, __pollwait);
     pwq->polling_task = current;
     pwq->triggered = 0;
     pwq->error = 0;
     pwq->table = NULL;
     pwq->inline_index = 0;
 }
 
会在其他task唤醒 然后返回给do_select; do_select实现休眠等待唤醒和select中的延时!
 

文章出处:飞诺网(www.diybl.com):http://www.diybl.com/course/6_system/linux/linuxjq/20110813/558332.html
来源:http://blog.csdn.net/gtkknd/article/details/7229527

原创粉丝点击