字符驱动-poll机制

字符驱动-poll机制

什么是poll

  • poll机制基于等待队列wait_queue
  • poll机制:如果没有发生需要的事件,那么进程进入休眠。如果在限定的时间内得到需要的事件,那么成功返回,如果没有则返回超时错误信息
#include <poll.h>

  int poll(struct pollfd fd[], nfds_t nfds, int timeout);


struct pollfd{

  int fd;              //文件描述符

  short events;    //请求的事件

  short revents;   //返回的事件

  };
  
nfds:要监视的描述符的数目

timeout:超时时间
INFTIM  永远
0  	    立即返回
x>0	 	x毫秒
事件意义
POLLIN普通或优先级带数据可读
POLLRDNORM普通数据可读
POLLRDBAND优先级带数据可读
POLLPRI高优先级数据可读
POLLOUT普通数据可写
POLLWRNORM普通数据可写
POLLWRBAND优先级带数据可写
POLLERR发生错误
POLLHUP发生挂起
POLLNVAL描述字不是一个打开的文件

要想深入理解poll机制,就必须先理解wait_queue

什么是等待队列

等待队列

  • 在 Linux 驱动程序设计中,可以使用等待队列来实现进程的阻塞.
  • 等待队列实质由一个等待队列头加上N个等待队列项组成的循环双向链表
  • 常用函数如下:
函数意义
wait_queue_head_t wq;分配等待队列头
init_waitqueue_head(&wq);初始化等待队列头
wait_event加入等待队列项
wait_evnet_timeout
wait_event_interruptible
wait_event_interruptible_timeout
wake_up唤醒等待队列
wake_up_interruptib
  • 使用等待队列前通常先定义一个等待队列头static wait_queue_head_t wq
  • 然后调用wait_event_*函数将等待某条件condition的当前进程插入到等待队列wq中并睡眠
  • 一直等到condition条件满足后,内核再将睡眠在等待队列wq上的某一进程或所有进程唤醒

wait_event_*中,先创建等待队列项(包含了当前进程的参数) -> 再将等待队列项加入到等待队列头中 -> 设置休眠状态 -> 调用schedule切换任务

wake_up*中当收到唤醒信号后,signal_pending判断唤醒信号 -> 设置运行态 -> 移除等待队列项 -> __wake_up_common循环遍历等待队列内的所有元素,分别执行其对应的唤醒函数。

poll驱动框架

以上可以清楚的了解到poll机制的原理:利用等待队列实现休眠查询事件

poll驱动框架如下

static unsigned int Mypoll(struct file *file, poll_table *wait)
{
	unsigned int mask = 0;
 
	/* 该函数,只是将进程挂在button_waitq队列上,而不是立即休眠 */
	poll_wait(file, &button_waitq, wait);
 
	if(ev_press)
	{
		mask |= POLLIN | POLLRDNORM;  /* 表示有数据可读 */
	}
 
	/* 如果ev_press事件发生,mask |= POLLIN | POLLRDNORM,否则mask = 0 */
	return mask;  
}
  • 其中,当事件发生时,设置事件状态 -> 调用wait_event_*函数唤醒等待队列,回到poll_wait休眠处顺序执行

可以看到主要是调用了poll_wait函数,其调用流程如下

app: poll
      |
drv:sys_poll
      |
      — do_sys_poll(struct pollfd __user * ufds, unsigned int nfds, struct timespec * end_time)
         |   
   	      - poll_initwait(&table);  >  实际效果:令函数指针 table.pt.qproc = __pollwait,这个函数指针最终会传递给poll_wait函数调用中的wait->qproc
          |
          - do_poll(nfds, head, &table, end_time);
           |
            _ for ( ; ; )
            {
                  for (; pfd != pfd_end; pfd++) 
                  {    /* 可以监测多个驱动设备所产生的事件 */
                      if (do_pollfd(pfd, pt))
                       {  
                          mask = file->f_op->poll(file, pwait); > 实际效果:执行我们写的drivers_poll(file,pwait)
                                |
                                 _  poll_wait(file, &button_waitq, wait); > 实际效果:执行__pollwait(file, &button_waitq, wait),也就是将
                                                                            进程挂接到button_waitq等待队列下
                                |
                                —  mask赋值 ; return mask; /* 返回事件类型 */
                         pollfd->revents = mask;    /* 将实际事件类型返回 */
                         count++; pt = NULL; 
                       } 
                 } 
                 if (count || timed_out) /* 如果有事件发生,或者超时,则跳出poll */ 
                      break; 
                 if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack)) /* 如果没有事件发生,那么陷入休眠状态 */ 
                      timed_out = 1; 
            }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值