前言

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设计模式-----12、外观模式

    Facade模式也叫外观模式,是由GoF提出的23种设计模式中的一种.Facade模式为一组具有类似功能的类群,比如类库,子系统等等,提供一个一致的简单的界面.这个一致的简单的界面被称作facade. ...

  2. JSON方式封装通信接口

    1.封装通信接口数据的方法 2. 案例:生成json 注意:json_encode() 只能接收utf-8数据 测试: <?php $arr = array( 'id'=>1, 'name ...

  3. HTML meta头部小结

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. php7.27: export excel from mysql

    https://stackoverflow.com/questions/15699301/export-mysql-data-to-excel-in-php https://github.com/PH ...

  5. 微信小程序日历课表

    最近项目中使用到了日历,在网上找了一些参考,自己改改,先看效果图 wxml <view class="date"> <image class="dire ...

  6. 【读书笔记】iOS-iOS的持续集成

    一,Jenkins http://jenkins-ci.org 二,iOS单元测试的持续集成 在Xcode进入OCUnit作为单元测试框架前,把单元测试分为两种:Logic Test和Applicat ...

  7. Redis 入门 安装 命令

    win7 64位安装redis 及Redis Desktop Manager使用 引自:http://blog.csdn.net/joyhen/article/details/47358999 写基于 ...

  8. Python 基于python+mysql浅谈redis缓存设计与数据库关联数据处理

    基于python+mysql浅谈redis缓存设计与数据库关联数据处理 by:授客  QQ:1033553122 测试环境 redis-3.0.7 CentOS 6.5-x86_64 python 3 ...

  9. .NetCore(四) 在Nginx部署

    ​本篇主要体验一下Nginx的使用,之前只接触过IIS. 一.Nginxa) ASP.NET Core内置了Kestrel服务器,但功能简单,主要用于SelfHost,正式运行还是要依赖IIS.Apa ...

  10. vi 复制或剪切多行超级强大方法

    同一个文件:光标移到起始行,输入ma 光标移到结束行,输入mb 光标移到粘贴行,输入mc 然后 :'a, 'b co 'c 把 co 改成 m 就成剪切了多个文件:在文件一: 光标移到起始行,输入ma ...