前言

poll机制用于实现IO多路复用。所谓IO多路复用,通俗的讲,其实就是线程复用,使其能在一个线程上处理多个IO。

用户空间

用户通过调用用户空间的poll函数使用该机制。

驱动部分的实现

用户如果要在自己的驱动中实现poll机制,则必须实现:
struct file_operations中的
unsigned int (poll) (struct file , struct poll_table_struct *) 函数

该函数主要调用:

static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)

用于将一个wait_queue加入到poll_table中

然后检查相应状态,设置并返回给用户

eg(LDD 3):

static unsigned int scull_p_poll(struct file *filp, poll_table *wait)
{
    struct scull_pipe *dev = filp->private_data;
    unsigned int mask = 0;
    /*
    * The buffer is circular; it is considered full
    * if "wp" is right behind "rp" and empty if the
    * two are equal.
    */
    down(&dev->sem);
    poll_wait(filp, &dev->inq, wait);
    poll_wait(filp, &dev->outq, wait);
    if (dev->rp != dev->wp)
        mask |= POLLIN | POLLRDNORM; /* readable */
    if (spacefree(dev))
        mask |= POLLOUT | POLLWRNORM; /* writable */
    up(&dev->sem);
    return mask;
}

内核实现分析

下面以内核版本4.10.0进行分析

在内核,实现为do_sys_poll(/fs/select.c)

int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
        struct timespec64 *end_time)
{
..................................
    poll_initwait(&table);
    fdcount = do_poll(head, &table, end_time);
    poll_freewait(&table);
..................................
}

do_sys_poll 函数主要就是创建一个 struct poll_wqueues 的结构体,然后调用 do_poll。

其中 struct poll_wqueues结构体:

struct poll_wqueues {
    poll_table pt;
    struct poll_table_page *table;
    struct task_struct *polling_task;
    int triggered;
    int error;
    int inline_index;
    struct poll_table_entry inline_entries[N_INLINE_POLL_ENTRIES];
};

do_poll(/fs/select)函数,主要是一个for循环,会将struct poll_wqueues 的 poll_table pt作为参数,传递给相应文件的poll函数。如果检查到任意一个文件能使用,就返回,否则就等待,直到有可用的文件为止。

然后文件的poll函数,调用poll_wait函数

poll_wait函数,接着调用__pollwait函数.

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;
    entry->filp = get_file(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);
}

分析,可知,获取一个poll_table_entry,对其进行初始化,然后将当前进程加入到等待队列中,等待事件的发生。

总结

对一个程序的分析,最重要的是对其数据结构的分析。

当用户调用poll函数时,内核会创建一个struct poll_wqueues,然后将其中的poll_table 传递给文件的poll函数,然后由poll函数调用poll_wait,将当前调用进程加入等待队列中,等待事件的发生。

当一个进程,poll多个文件描述符时,该进程会被加载进多个等待队列中。

Linux内核poll内部实现的更多相关文章

  1. Linux内核poll/select机制简析

    0 I/O多路复用机制 I/O多路复用 (I/O multiplexing),提供了同时监测若干个文件描述符是否可以执行IO操作的能力. select/poll/epoll 函数都提供了这样的机制,能 ...

  2. Linux内核中双向链表的经典实现

    概要 前面一章"介绍双向链表并给出了C/C++/Java三种实现",本章继续对双向链表进行探讨,介绍的内容是Linux内核中双向链表的经典实现和用法.其中,也会涉及到Linux内核 ...

  3. linux内核-双向链表

    linux中的经典宏定义 offsetof 定义:offsetof在linux内核的include/linux/stddef.h中定义. #define offsetof(TYPE, MEMBER) ...

  4. Linux内核3.11的socket busy poll机制避免睡眠切换

    Linux的网络协议栈很独立,上下通过两个接口分别和用户态以及设备相连.也能够看作是北向和南向接口...北向通过socket接口,南向通过qdisc接口(你能够觉得是上层的netdev queue,对 ...

  5. (十二)Linux内核驱动之poll和select

    使用非阻塞 I/O 的应用程序常常使用 poll, select, 每个允许一个进程来决定它是否可读或者写一个或多个文件而不阻塞. 这些调用也可阻塞进程直到任何一个给定集合的文件描述符可用来读或写.  ...

  6. Linux内核中网络数据包的接收-第二部分 select/poll/epoll

    和前面文章的第一部分一样,这些文字是为了帮别人或者自己理清思路的.而不是所谓的源代码分析.想分析源代码的,还是直接debug源代码最好,看不论什么文档以及书都是下策. 因此这类帮人理清思路的文章尽可能 ...

  7. linux 内核邮件列表

    第一节 - 一般性问题 1. 为什么有些时候使用“GNU/Linux"而另一些时候使用“Linux”? 答:在这个FAQ中,我们尝试使用“linux”或者“linux kernel”来表示内 ...

  8. linux内核数据结构学习总结

    目录 . 进程相关数据结构 ) struct task_struct ) struct cred ) struct pid_link ) struct pid ) struct signal_stru ...

  9. Linux内核调试方法总结【转】

    转自:http://my.oschina.net/fgq611/blog/113249 内核开发比用户空间开发更难的一个因素就是内核调试艰难.内核错误往往会导致系统宕机,很难保留出错时的现场.调试内核 ...

随机推荐

  1. 转载 基于JAVA每月运势api调用代码实例

    代码描述:基于JAVA每月运势api调用代码实例 接口地址:http://www.juhe.cn/docs/api/id/58 原文链接:http://outofmemory.cn/code-snip ...

  2. Java开发中json使用,各对象与json相互转换

    Json:一种网络通信使用的数据格式,因为便于解析,比较流行,对象可以转为json,同样json也可以转对象. 下面介绍下Json工具的简单使用(fastjson && jackson ...

  3. 前端面试整理——javascript算法和测试题

    (1)算法: 1.斐波那契数列:1.1.2.3.5.8.13.21.输入n,输出数列中第n位数的值. 方案一: function fn(n){ var num1 = 1, num2= 1, num3 ...

  4. CSS--居中方式总结

    一.水平居中方法 1.行内元素.字体的水平居中 1.对于行内元素(display值为inline或inline-block都可以)或者字体:父元素添加css规则:text-align:center; ...

  5. Network-Emulator Network-Emulator-Toolkit网络模拟器使用详细介绍

    Network-Emulator-Toolkit网络模拟器使用详细介绍 by:授客 QQ:1033553122 原理介绍 图1 如上图,一个ADSL用户通过modem连接到网络,通过网络应用如IE,M ...

  6. Session Cookies随笔

    1.对于Session而言 它是用来保存在服务端的信息,可以用来做登录验证,在后台保存有用信息. 一个浏览器访问一个网站,就是建立一个连接,连接信息是独立的,就是在该建立的连接内,保存到Session ...

  7. 聊聊HTTP gzip压缩与常见的Android网络框架

    版权声明: 欢迎转载,但请保留文章原始出处 作者:GavinCT 出处:http://www.cnblogs.com/ct2011/p/5835990.html 进入主题之前,我们先来看一下客户端与服 ...

  8. [iOS]深入理解GCD

    看到一篇很好的文章,本来想翻译的,但发现已经有人翻译了,遂简单整理了一下,方便阅读学习 新博客[wossoneri.com] 什么是GCD GCD(Grand Central Dispatch)是li ...

  9. MySQL——优化嵌套查询和分页查询

    优化嵌套查询 嵌套查询(子查询)可以使用SELECT语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中.嵌套查询写起来简单,也容易理解.但是,有时候可以被更有效率的连接(JOIN ...

  10. 利用python中的gensim模块训练和测试word2vec

    word2vec的基础知识介绍参考上一篇博客和列举的参考资料. 首先利用安装gensim模块,相关依赖如下,注意版本要一致: Python >= 2.7 (tested with version ...