1. poll 机制

本篇主要是进行 poll 内核实现,调用流程的分析。

1.1 sys_poll 分析

应用程序调用 poll() 后,经过 SWI 的处理后,最终会进入内核的 sys_poll() 函数:

asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,long timeout_msecs)

这个函数有两个部分:

  1. 第一部是将应用程序传递下来的时间(poll的第三个参数timespec),从毫秒单位转为节拍单位。

    s64 timeout_jiffies;if (timeout_msecs > 0) {#if HZ > 1000/* We can only overflow if HZ > 1000 */if (timeout_msecs / 1000 > (s64)0x7fffffffffffffffULL / (s64)HZ)timeout_jiffies = -1;else
    #endiftimeout_jiffies = msecs_to_jiffies(timeout_msecs);} else {/* Infinite (< 0) or no (0) timeout */timeout_jiffies = timeout_msecs;}
    
  2. 第二部分是调用 do_sys_poll(ufds, nfds, &timeout_jiffies);

1.2 do_sys_poll 分析

do_sys_poll() 完成的工作有:

  1. 将用户空间的传递下来的 pollfds 链表拷贝到内核空间中,并把每一个 pollfd 封装成一个 poll_list 对象。将所有的 poll_list 对象,串联成一个单链表。

    首先会尝试把所有的 poll_list 都存储在 do_sys_poll() 的函数栈中;

    如果函数栈无法容纳全部 poll_list,则会在堆中开辟新空间,用来存储多出来的 poll_list;

  2. 创建一个 struct poll_wqueues table 对象。

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

    调用 poll_initwait() 函数,初始化该对象。poll_initwait() 会调用 init_poll_funcptr(&pwq->pt, __pollwait); 初始化 poll_table;

    static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc)
    {pt->qproc = qproc;
    }
    

    最终在 poll_table 中保存一个指向 __pollwait 的指针函数

  3. 接着调用 do_poll();

1.3 do_poll 分析

接下来对 do_poll() 进行详细分析:

static int do_poll(unsigned int nfds,  struct poll_list *list,struct poll_wqueues *wait, s64 *timeout)
{/* ...省略... */ for (;;) {/* ...省略...*/for (walk = list; walk != NULL; walk = walk->next) {/* ...省略...*/for (; pfd != pfd_end; pfd++) {/** Fish for events. If we found one, record it* and kill the poll_table, so we don't* needlessly register any other waiters after* this. They'll get immediately deregistered* when we break out and return.*/if (do_pollfd(pfd, pt)) {/* 如果驱动程序的poll返回非零,说明有事件发生,那么count++ */count++; pt = NULL;}}}/* 被唤醒的pfd个数大于零、或超时、或接受到了信号退出 */if (count || !*timeout || signal_pending(current))break;/* ...省略...*//* 进入休眠,* 如果休眠结束仍然没有事件发生,会再次执行一次for循环* 当在此到达上面的条件时,超时退出。*/__timeout = schedule_timeout(__timeout);/* ...省略...*/return count;   /* 有事件的fd个数 */
}

do_poll() 的核心代码,是对每一个 poll_list 对象,都对其调用一次 do_pollfd();

do_pollfd() 的定义如下:

static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
{/* ...省略... */if (fd >= 0) {/* ...省略... */if (file != NULL) {/* ...省略... */file = fget_light(fd, &fput_needed);if (file->f_op && file->f_op->poll)mask = file->f_op->poll(file, pwait);/* Mask out unneeded events. */mask &= pollfd->events | POLLERR | POLLHUP;/* ...省略... */
}

该函数完成的工作是通过 pollfd 中的 fd,获取到文件描述所对应的文件 file 对象。

接着通过文件对象的 file_operations 操作结构体,调用 file_operations 的 .poll 成员,从而访问到驱动的实现的 .poll 函数;

1.4 驱动程序的 .poll 函数

以 s3c2440 为例,一般驱动程序中会调用 poll_wait 函数;

static unsigned s3c2440_buttons_poll(struct file *file, poll_table *wait)
{unsigned int mask = 0;poll_wait(file, &button_waitq, wait);if (ev_press)mask |= POLLIN | POLLRDBAND;return mask;
}

poll_wait 的原型定义如下:

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);
}

p->qproc 就是我们前面提到的 __pollwait 函数。

__pollwait 的原型如下:

static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,poll_table *p)
{struct poll_table_entry *entry = poll_get_entry(p);   /* 获取entry */if (!entry)return;get_file(filp);entry->filp = filp;entry->wait_address = wait_address;/* 将当前进程挂载到等待队列上 */init_waitqueue_entry(&entry->wait, current);  add_wait_queue(wait_address, &entry->wait);
}
  1. 获取entry。entry的定义如下:

    struct poll_table_entry {struct file * filp;wait_queue_t wait;wait_queue_head_t * wait_address;
    };
    
  2. 设置当前进程,对 filp 这个文件“感兴趣”。后续,等这个文件有可操作事件发生时,会唤醒当前进程进行操作;

  3. add_wait_queue() 将当前进程挂载到 wait_address 等待队列上;

完成了上面的操作后,当前进程就被挂载到所有感兴趣的文件描述符的等待队列上。

接着 do_poll 会调用 schedule_timeout 使进程进入休眠状态;

当文件描述符上有事件发生时,进程就会被唤醒,从而再次执行一次 do_poll 中的 for 循环,这时 s3c2440_buttons_poll 中就根据 ev_press 的值,设置 mask 为大于零,从而使得 do_pollfd 返回 count 非零。

2. 补充说明节拍

通过 msecs_to_jiffies()可以将毫秒时间转换为以节拍做单位。

poll的timespec将其转为节拍,内核就可以在当前节拍(base)基础上poll的节拍作为offset,算出一个poll超时时的节拍,当节拍次数达到这个base+offset时,就可以判断poll时间超时,就会触发应用程序poll的超时返回。

在Linux内核中使用全局变量 jiffies 记录自系统启动以来产生的节拍的总次数。内核启动后会将 jiffies 初始化为零,此后,每次时钟中断处理程序都会增加该变量的值。而一秒内时钟中断的次数会等于 HZ 数,所以 jiffies 一秒内增加的值就为 HZ。

如果系统运行时间以秒为单位计算,那么也就是等于 $ 系统运行的总时间 = jiffies / HZ $

Linux内核poll机制分析相关推荐

  1. Linux内核NAPI机制分析

    转自:http://blog.chinaunix.net/uid-17150-id-2824051.html 简介: NAPI 是 Linux 上采用的一种提高网络处理效率的技术,它的核心概念就是不采 ...

  2. linux内核机制是什么,linux内核slab机制分析

    1.内部碎片和外部碎片 外部碎片 什么是外部碎片呢?我们通过一个图来解释: image.png 假设这是一段连续的页框,阴影部分表示已经被使用的页框,现在需要申请一个连续的5个页框.这个时候,在这段内 ...

  3. Linux的poll机制

    目录 前言 1 应用层使用poll 1.1 poll的原型 1.2 使用示例 2 驱动怎么支持poll 2.1 字符设备驱动 3 一些更深入的分析 3.1 从系统调用poll到驱动的xxx_poll ...

  4. Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 【转】...

    原文地址:Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinauni ...

  5. Linux内核同步机制之(四):spin lock【转】

    转自:http://www.wowotech.net/kernel_synchronization/spinlock.html 一.前言 在linux kernel的实现中,经常会遇到这样的场景:共享 ...

  6. [漏洞分析] CVE-2022-0847 Dirty Pipe linux内核提权分析

    CVE-2022-0847 Dirty Pipe linux内核提权分析 文章目录 CVE-2022-0847 Dirty Pipe linux内核提权分析 漏洞简介 环境搭建 漏洞原理 漏洞发生点 ...

  7. openVswitch(OVS)源代码之linux RCU锁机制分析

    前言 本来想继续顺着数据包的处理流程分析upcall调用的,但是发现在分析upcall调用时必须先了解linux中内核和用户空间通信接口Netlink机制,所以就一直耽搁了对upcall的分析.如果对 ...

  8. Linux内核源代码情景分析笔记

    Linux内核源代码情景分析笔记 好吧,首先我承认我要是读者的话,这篇文章我看着也头疼,因为写的太长太泛(其主要部分集中在内存管理,进程管理,文件系统)!原本是想按自己理解的精简精简的,按照操作系统中 ...

  9. Linux内核源码分析之内存管理

    本文站的角度更底层,基本都是从Linux内核出发,会更深入.所以当你都读完,然后再次审视这些功能的实现和设计时,我相信你会有种豁然开朗的感觉. 1.页 内核把物理页作为内存管理的基本单元. 尽管处理器 ...

最新文章

  1. CSU 1806 Toll 自适应simpson积分+最短路
  2. 如何训练孩子上厕所(初级篇)
  3. 设计模式 之 模板模式
  4. Java提升篇-事务隔离级别和传播机制
  5. java自动gc_具有Java 7中自动资源管理功能的GC
  6. java socket 传送进度_java-★-Socket文件上传/进度条
  7. 图形的装饰教案计算机,《电脑图案设计师》教案教学设计
  8. HDU.1003 Max Sum
  9. 2020.11.18 比赛总结题解合集
  10. 思科交换机命令大全 一
  11. PHP架构师必备技术视频合集
  12. 天津大学学硕和专硕的区别_专硕学硕的区别你弄明白了吗?听听学长学姐怎么说...
  13. LVGL V8之Animation timeline
  14. SQL AlawaysOn 之二:添加组织和域用户
  15. matlab输出箱线图的五个特征值_Matlab绘制箱线图
  16. 【HashTab初学】哈希表
  17. pcl点云特征提取 法线估计 PFH FPFH NARF 惯量偏心矩 RoPs特征 视点特征直方图VFH GASD特征
  18. 【SAP Abap】SAP S/4 ABAP OPEN SQL中WITH的应用案例
  19. 仅凭我自己的经验写给小白的网页制作全过程
  20. 前段基础 HTML 第三章文字与段落标记----假期学习第二天

热门文章

  1. 计算机的发展与应用 教学设计,第二课《计算机的发展与应用》教学设计.docx
  2. 父母对儿子结婚女儿出嫁的忠告
  3. 职工管理系统c语言课设需求分析,人力资源管理系统需求分析报告及系统架构图...
  4. 博途1200间MODBUS TCP通信
  5. 护士成绩用计算机改卷,解密!2020年卫生资格/护士人机对话考试如何评分?成绩如何核算?...
  6. 大规模敏捷框架SAFe模型简介
  7. 2022年执法资格通用法律知识考试多选题专项训练题及答案
  8. XA 分布式事务原理
  9. 红旗MeeGo中文版平板电脑问世
  10. 论文笔记(综述)——Image fusion meets deep learning: A survey and perspective