【问题标题】:Linux device driver buffering strategyLinux设备驱动缓冲策略
【发布时间】:2017-06-14 11:20:11
【问题描述】:

假设我有一个外部设备不断将数据推送到驱动程序中的一个小缓冲区中。我正在使用等待队列,其中中断处理程序唤醒等待的用户进程(类似于 LDD (3rd edition) - 实现处理程序)。

irq_handler_t irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{

 flag = 1;
 wake_up_interruptible(&wq);

return  IRQ_HANDLED;
}

ssize_t my_read(struct file *dev, char __user *buf, size_t count, loff_t *f_pos)

{

        wait_event_interruptible(wq, flag != 0);
        flag = 0;
        copy_to_user(usr_buf, drv_buf, count);

}


/***********************User program***********************/

while(1)
{    
    read(fid, buffer, size);

    //do stuff with data

}

用户程序调用 read 并等待中断从外部设备获取新数据。由于外部设备可能会以比此代码执行速度更快的速度推送数据,我可以使用哪些机制来确保在用户程序复制数据之前不会覆盖数据?像结构这样的环形缓冲区会在这里工作吗?不清楚如何实现。

谢谢

【问题讨论】:

  • 你的 drv_buf 如何获取数据? copy_to_user(usr_buf, drv_buf, count) 应该是 copy_to_user(buf, drv_buf, count)。
  • “我可以使用什么机制来确保数据在用户程序复制之前不会被覆盖?” -- 本质上,驱动程序只能尽可能多地缓冲,直到那里是缓冲区溢出。 (静态分配的)环形缓冲区(如答案中所提议的)仅在(环形)缓冲区大小不足时才能推迟溢出。编写良好的驱动程序将能够检测并报告这种情况。即使是动态分配的缓冲区也可能不足以应付“慢”的阅读器。 IOW 你必须确保用户空间至少能以某种平均速率跟上到达的数据。

标签: c linux linux-kernel linux-device-driver


【解决方案1】:

是的,环形缓冲区可以工作。

您只需从中断处理程序中填充缓冲区,然后您将从my_read 回调中读取它。

一个非常幼稚且非常低效的实现可能是(未经测试):

static irqreturn_t irq_handler(int irq, void *dev_id)
{
        struct my_dev *dev = dev_id;

        buf[buf_wr] = read_device(dev);
        buf_wr++;

        if (buf_wr >= BUFSIZE)
                buf_wr = 0;

        wake_up(&wq);
        return IRQ_HANDLED;
}

static ssize_t my_read(struct file *file, char __user *ubuf,
                             size_t sz, loff_t *ppos)
{
        int n, ret;

        ret = wait_event_interruptible(wq,
                                buf_wr != buf_rd);
        if (ret)
                return ret;

        n = buf_wr - buf_rd;
        if (n < 0)
               n += BUFSIZE;

        n = min(count, n);
        ret = copy_to_user(ubuf, buf, n);
        buf_rd += n;

        if (buf_rd >= BUFSIZE)
                buf_rd -= BUFSIZE;

        if (ret)
                return ret;

        *ppos += n;
        return 1;
}

您可能还想使用 DMA 或 mmap 或两者兼而有之,以提高效率。

【讨论】:

  • 当两个以上的用户可以访问 ring buff 时,它必须通过一些同步原语来保护,也就是说在中断处理程序-irq_handler 中,可以休眠吗?
  • 用户空间信号相当于linux内核中的中断是的,你可以使用环形缓冲区机制。但是你需要使用内核同步的方法来保护数据
  • 是的,您绝对必须使用适当的锁定(在这里,互斥锁可能就足够了)。如前所述,这是一个非常简单的实现,
  • 使用kFIFO 机制可能是有效的。
猜你喜欢
  • 1970-01-01
  • 2015-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-22
相关资源
最近更新 更多