在linux char设备驱动程序中,poll_queue_proc函数做什么?

问题描述 投票:0回答:1

Linux中有一个同步轮询多个设备文件的概念,我正在尝试了解它是如何工作的。在linux 2.6.23源驱动程序/char/random.c中,我看到以下代码

static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);

static unsigned int
random_poll(struct file *file, poll_table * wait)
{
    unsigned int mask;

    poll_wait(file, &random_read_wait, wait);
    poll_wait(file, &random_write_wait, wait);
    mask = 0;
    if (input_pool.entropy_count >= random_read_wakeup_thresh)
        mask |= POLLIN | POLLRDNORM;
    if (input_pool.entropy_count < random_write_wakeup_thresh)
        mask |= POLLOUT | POLLWRNORM;
    return mask;
}

poll_table在include / linux / poll.h中的定义如下

typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *);

typedef struct poll_table_struct {
    poll_queue_proc qproc;
} poll_table;

[我在一本书(第5章,Essential Linux Device Drivers,Venkateswaran)中看到,“ poll_table是被轮询数据的设备驱动程序所拥有的等待队列的表。”但消息人士称这只是一个函数指针。而且我找不到qproc这个函数在做什么。下面是在include / linux / poll.h中定义的函数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);
}

并且在书中说(关于鼠标的char驱动程序示例),“ mouse_poll()使用库函数poll_wait()向内核poll_table添加一个等待队列(mouse_wait)并进入睡眠状态。”因此poll_wait可以休眠,但是在上面的random_poll()函数中,我们看到了两个连续的poll_wait函数。那么random_poll是否按顺序轮询读写可用性并将掩码发送给应用程序?如果有人可以向我展示poll_queue_proc函数的示例,我将不胜感激。我在linux驱动程序源中找不到它(它应该只出现在应用程序中吗?)。

linux linux-device-driver polling device-driver
1个回答
0
投票

drivers/char/random.c:random_poll()在用户空间调用时被调用select()(或与此相关的poll()epoll_wait())和一个文件引用/dev/random的描述符。

这些系统调用是事件多路复用的基础。在里面在以下程序中,用户空间打开了许多输入源(例如/dev/random/dev/ttyS4),并调用select() 它们阻止,直到其中任何一个具有要读取的输入数据为止。 (那里是除了输入以外的其他事件源,输入只是最简单的。)

#include <sys/select.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>


#define _SYSE(ret, msg) do {                    \
    if (ret == -1) {                            \
        perror(msg);                            \
        exit(EXIT_FAILURE);                     \
    }                                           \
} while (0)

static int /*bool: EOF detected*/ consume_fd(int fd, const char* msg)
{
    char tmp[64];
    ssize_t nread;

    nread = read(fd, tmp, sizeof(tmp));
    _SYSE(nread, "read");
    if (nread == 0 /*EOF*/)
        return 1;

    printf("%s: consumed %ld bytes\n", msg, nread);
    return 0;
}

int main(void)
{
    int random_fd, tty_fd, nfds = 0;

    random_fd = open("/dev/random", O_RDONLY);
    _SYSE(random_fd, "open random");
    if (random_fd > nfds)
        nfds = random_fd+1;

    tty_fd = open("/dev/ttyS4", O_RDONLY);
    _SYSE(tty_fd, "open tty");
    if (tty_fd > nfds)
        nfds = tty_fd+1;

    while (1) {
        fd_set in_fds;
        int ret;

        FD_ZERO(&in_fds);
        FD_SET(random_fd, &in_fds);
        FD_SET(tty_fd, &in_fds);

        ret = select(nfds, &in_fds, NULL, NULL, NULL);
        _SYSE(ret, "select");

        if (FD_ISSET(random_fd, &in_fds)) {
            int eof_detected = consume_fd(random_fd, "random");
            if (eof_detected) 
                break;
        }
        if (FD_ISSET(tty_fd, &in_fds)) {
            int eof_detected = consume_fd(tty_fd, "tty");
            if (eof_detected) 
                break;
        }
    }
    return 0;
}

输出将在出现随机数或串行线有数据。 (请注意,如今/dev/random块,而是生成伪随机数,因此输出实际上是快速。)

[select()调用进入内核时,random_poll()被称为,另一个可比较的功能在TTY中的某个位置层-仅仅因为select()将这些文件描述符传递为参数。这些功能应该只是使调用者入队并保存在poll_table中代表为此目的的调用任务)。

[在第二阶段中,select()的实现然后挂起直到任何事件变为真为止。 (请参见fs/select.c。)

© www.soinside.com 2019 - 2024. All rights reserved.