前言

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. sql server:Monty Hall problem (蒙提霍尔问题)

    --------------------------------------------------------------------- -- Auxiliry Table of Numbers 数 ...

  2. FullCalendar:eventColor,eventBackgroundColor, eventBorderColor, and eventTextColor

    <!DOCTYPE html> <html> <head> <meta charset='utf-8' /> <title>背景色設定< ...

  3. [总结]jQuery之常用函数方法参考手册

    w3school参考地址:http://www.w3school.com.cn/jquery/index.asp runoob参考地址:http://www.runoob.com/jquery/jqu ...

  4. 小结:ES7——async和await初识

    一.async async其实是ES7才有有的关键字,async的意思是异步,顾名思义是有关异步的操作 async用于声明一个函数是异步的. 通常情况下async.await都是跟随promise一起 ...

  5. JS性能优化 之 事件委托

    面试中2次被问到过这个知识点,实际开发中,应用事件委托也比较常见.JS中事件委托的实现主要依赖于 事件冒泡 .那什么是事件冒泡?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一 ...

  6. [ng:areq] Argument 'XXXXCtrl' is not a function, got undefined

    angular.module('MyApp', []) 这里的[]重复了,以后引入新的controller.js文件会覆盖前面那个,所以此处的[]去掉 .controller('MyCtrl', fu ...

  7. [20170628]完善ooerr脚本.txt

    [20170628]完善ooerr脚本.txt --//注意不是oracle的oerr,是我写的一个小脚本,下面会提到.很简单.^_^.--//参考链接:blog.itpub.net/267265/v ...

  8. Oracle EBS FA 资产取值

    SELECT fb.book_type_code, fth.ASSET_NUMBER, fdh.units_assigned, fdh.assigned_to, pf.FULL_NAME, fl.se ...

  9. 洗礼灵魂,修炼python(47)--巩固篇—定义类的方法之@classmethod,@staticmethod

    定义类的方法,相信你会说,不就是在class语句下使用def () 就是定义类的方法了嘛,是的,这是定义的方法的一种,而且是最普通的方式 首先,我们已经知道有两种方式: 1.普通方法: 1)与类无关的 ...

  10. 【PAT】B1072 开学寄语(20 分)

    代码注释应该很清晰 先存下违禁品,放到数组中,未使用map #include<cstdio> #include<string.h> int wupin[10],N,M; boo ...