理解poll_wait

简介: 理解poll_wait   poll_wait()是用在select系统调用中的. 一般你的代码会有一个struct file_operations结构, 其中fop->poll函数指针指向一个你自己的函数, 在这个函数里应该调用poll_wait() 当用户调用selec...

理解poll_wait

 

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中的延时!

目录
相关文章
|
Web App开发 域名解析 缓存
如何在 Ubuntu 20.04 上安装 Node.js 和 npm
本文我们主要为大家介绍在 Ubuntu 20.04 上安装 Node.js 和 npm 的三种不同的方式。
164883 7
如何在 Ubuntu 20.04 上安装 Node.js 和 npm
|
人工智能 安全 Linux
云+AI时代下,Alibaba Cloud Linux 进一步演进思考
用好开源、做深开源、自研创新,打造全方位安全可信的服务器操作系统。
|
存储 C++ 容器
C++ 第九节——map/set(用法+底层原理+模拟实现)
们需要知道的是,Map和Set的底层都是红黑树。
1236 1
C++ 第九节——map/set(用法+底层原理+模拟实现)
crash —— 内核符号和地址直接相互转换
crash —— 内核符号和地址直接相互转换
|
数据采集 机器学习/深度学习 人工智能
利用AI技术实现个性化新闻推荐系统
【8月更文挑战第31天】 本文将介绍如何利用AI技术实现一个个性化的新闻推荐系统。我们将使用Python语言和一些常用的机器学习库,如scikit-learn和pandas,来构建一个简单的推荐系统。这个系统可以根据用户的阅读历史和兴趣偏好,为他们推荐相关的新闻文章。我们将从数据预处理、特征提取、模型训练和结果评估等方面进行详细的讲解。
|
Shell Linux Perl
在Linux中,编写一个shell脚本,用于统计指定目录下所有文件的行数。
在Linux中,编写一个shell脚本,用于统计指定目录下所有文件的行数。
|
Linux
Linux命令之dmesg
Linux命令之dmesg
755 4
|
安全 编译器 程序员
CPU处理器模式与异常
CPU处理器模式与异常
623 0
|
Linux
linux驱动开发--copy_to_user 、copy_from_user函数实现内核空间数据与用户空间数据的相互访问
<strong><u>设备读操作</u></strong><br><p>如果该操作为空,将使得read系统调用返回负EINVAL失败,正常返回实际读取的字节数</p> <p><strong>ssize_t (*read)(struct file *filp, char __user *buf, size_t  count, lofft *f_pos);</strong><br><span
12857 0
|
消息中间件 负载均衡 NoSQL
消息队列 NSQ
消息队列 NSQ
384 0