linux-3.4.2之poll机制分析

http://liu1227787871.blog.163.com/blog/static/205363197201281215457217/
#define SYSCALL_DEFINE3(name, ...)            SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINEx(x, sname, ...)       __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#define __SYSCALL_DEFINEx(x, name, ...)     asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))

所以:
SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds , int, timeout_msecs)
就相当于:
asmlinkage long sys_poll( poll, struct pollfd __user *, ufds, unsigned int, nfds , int, timeout_msecs)

在用户空间执行poll函数的时候,会调用系统函数sys_poll,也就是 SYSCALL_DEFINE3,于是我们开始内核分析:
SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds , int, timeout_msecs)
    //设置超时时间
    poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC, NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC));
    do_sys_poll(ufds, nfds, to);
         poll_initwait(&table);
         init_poll_funcptr(&pwq->pt, __pollwait);
              //也就是说:pwq->pt->_qproc=__pollwait,__pollwait用于将当前进程加入等待队列
             //__pollwait函数在我们注册的poll函数里面会调用
              pt->_qproc = qproc;
         do_poll(nfds, head, &table, end_time);

我们贴出do_poll的部分内核代码:
static int do_poll(unsigned int nfds,  struct poll_list *list, struct poll_wqueues *wait, struct timespec *end_time)
{
for (;;) {
  struct poll_list *walk;

  for (walk = list; walk != NULL; walk = walk->next) {
    struct pollfd * pfd, * pfd_end;

    pfd = walk->entries;
    pfd_end = pfd + walk->len;
    //这个循环是针对多个进程的
    for (; pfd != pfd_end; pfd++) {
        //这个函数就是调用我们在驱动里面实现的poll函数,我们下面会贴出部分代码
        //只要有一个进程的返回值不为0,count就不为0
       if (do_pollfd(pfd, pt)) {
         count++;
         pt->_qproc = NULL;
       }
    }
  } //end of for (walk = list; walk != NULL; walk = walk->next)

  pt->_qproc = NULL;
  if (!count) {
    count = wait->error;
    if (signal_pending(current))
    count = -EINTR;
  }
  //一旦count不为0或者超时就会跳出循环,也就是应用程序返回了
  if (count || timed_out)
    break;

  if (end_time && !to) {
    expire = timespec_to_ktime(*end_time);
    to = &expire;
  }
  //如过count仍是0的话,就会在这里休眠一段时间,然后再次循环
  if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack))
    timed_out = 1;
}//end of for (;;)
return count;
}



static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
{
unsigned int mask;

mask = file->f_op->poll(file, pwait); //这就是调用我们注册的poll函数
//如果mask 与pollfd->events相同就能保证mask不为0
mask &= pollfd->events | POLLERR | POLLHUP; 

return mask;

下面我们总结一下poll机制:
在用户空间调用poll函数,然后会跳转进内核;之后会指向我们注册的poll函数,在poll函数里面我们会放一条指令:poll_wait,poll_wait里面会调用__pollwait函数将当前进程放入等待队列,但是这是并没有休眠,只是加入队列;如果没有发生我们想要的事件的话,我们要使返回值为0,这时就会进入休眠状态;一旦发生了我们想要的时间的话,我们可以唤醒进程!比如我们下一节要写的按键驱动程序,如果发生了按键按下,就会在中断函数里面唤醒进程!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值