POLL机制的内核代码详解

POLL机制的内核代码详解

Linux APP 系统调用,基本都可以在它的名字前加上 sys_ 前缀,这就是它在内核中对应的函数。比如系统调用 openreadwritepoll ,与之对应的内核函数为 sys_opensys_readsys_writesys_poll

对于系统调用 pollselect ,他们对应的内核函数都是 sys_poll。分析 sys_poll ,即可理解 poll 机制。

sys_poll 函数

sys_poll 位于 fs/select.c 文件中,代码如下:

SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,
                int, timeout_msecs)
{
    struct timespec64 end_time, *to = NULL;
    int ret;
    if (timeout_msecs >= 0) {
        to = &end_time;
        poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC,
        NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC));
    }
    ret = do_sys_poll(ufds, nfds, to);
    ……

SYSCALL_DEFINE3 是一个宏,它定义于 include/linux/syscalls.h,展开后就有 sys_poll 函数。
sys_poll 对超时参数稍作处理后,直接调用 do_sys_poll。

do_sys_poll 函数

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

poll_initwait 函数非常简单,它初始化一个 poll_wqueues 变量 table:

poll_initwait
init_poll_funcptr(&pwq->pt, __pollwait);
pt->qproc = qproc;

即 table->pt->qproc = __pollwait, __pollwait 将在驱动的 poll 函数里用到。do_poll 函数才是核心,继续看代码。

do_poll 函数

do_poll 函数位于 fs/select.c 文件中,这是 POLL 机制中最核心的代码,贴图如下:
在这里插入图片描述
① 从这里开始,将会导致驱动程序的 poll 函数被第一次调用
沿着②③④⑤,你可以看到:驱动程序里的poll_wait会调用__pollwait 函数把线程放入某个队列。
当执行完①之后,在⑥或⑦处, pt->_qproc 被设置为 NULL,所以第二次调用驱动程序的 poll 时,不会再次把线程放入某个队列里。
⑧ 如果驱动程序的 poll 返回有效值,则 count 非 0,跳出循环;
⑨ 否则休眠一段时间;当休眠时间到,或是被中断唤醒时,会再次循环、再次调用驱动程序的 poll。

回顾 APP 的代码, APP 可以指定“想等待某些事件”, poll 函数返回后,可以知道“发生了哪些事件”:
在这里插入图片描述
驱动程序里怎么体现呢?在上上一个图中,看②位置处,细说如下:
在这里插入图片描述

  • 14
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`poll_wait` 函数是 Linux 内核中用于实现轮询等待的一个重要函数,其主要作用是将当前进程挂起,等待某个特定的事件发生,例如数据从 IO 设备上到达或者设备错误等。当事件发生时,`poll_wait` 将会唤醒等待的进程,使其可以继续执行。 下面详细介绍一下 `poll_wait` 函数的使用方法。 ## 语法 ```c void poll_wait(struct file *filp, wait_queue_head_t *queue, struct wait_queue_entry *wait); ``` ## 参数 - `filp`:待等待的文件指针; - `queue`:等待队列的头指针; - `wait`:等待队列的条目指针。 ## 功能 将当前进程加入到等待队列中,等待某个特定的事件发生。 ## 注意事项 1. `poll_wait` 函数只能在进程的上下文中使用,不能在中断上下文中使用。 2. 在调用 `poll_wait` 函数之前,必须先调用 `init_waitqueue_head` 函数对等待队列进行初始化。 3. 在等待队列中,每个等待事件都必须使用唯一的等待队列条目。 ## 示例 下面是一个示例程序,演示了如何使用 `poll_wait` 函数: ```c DEFINE_WAIT(wait); init_waitqueue_head(&wait_queue_head); // 等待事件发生 poll_wait(file, &wait_queue_head, &wait); // 判断事件是否已经发生 if (event_occurred) { // 唤醒等待队列中的进程 wake_up_interruptible(&wait_queue_head); } ``` 在上面的示例程序中,首先使用 `DEFINE_WAIT` 宏定义了一个等待队列条目,然后使用 `init_waitqueue_head` 函数对等待队列进行初始化。接着,使用 `poll_wait` 函数将当前进程加入到等待队列中,等待事件发生。当事件发生时,使用 `wake_up_interruptible` 函数唤醒等待队列中的进程,使其可以继续执行。 总之,`poll_wait` 函数是 Linux 内核中实现轮询等待的一个重要函数,它可以方便地实现进程挂起和等待事件发生的功能,是 Linux 内核中非常常用的一个函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值