在Linux内核中实现正确的模块间同步

时间:2021-07-28 18:19:56

I'm implementing a custom serial bus driver for a certain ARM-based Linux board (a custom UART driver, actually). This driver shall enable communication with a certain MCU on the other end of the bus via a custom protocol. The driver will not (and actually must not) expose any of its functions to the userspace, nor it is possible to implement it in userspace at all (hence, the need for the custom driver instead of using the stock TTY subsystem).

我正在为某个基于ARM的Linux板(实际上是一个自定义UART驱动程序)实现自定义串行总线驱动程序。该驱动程序应通过自定义协议启用与总线另一端的某个MCU的通信。驱动程序不会(实际上不能)将其任何功能暴露给用户空间,也不可能在用户空间中实现它(因此,需要自定义驱动程序而不是使用库存TTY子系统)。

The driver will implement the communication protocol and UART reads/writes, and it has to export a set of higher-level functions to its users to allow them to communicate with the MCU (e.g. read_register(), drive_gpios(), all this stuff). There will be only one user of this module.

驱动程序将实现通信协议和UART读/写,并且必须将一组更高级别的函数导出到其用户以允许它们与MCU通信(例如read_register(),drive_gpios(),所有这些东西) 。该模块只有一个用户。

The calling module will have to wait for the completion of the operations (the aforementioned read_register() and others). I'm currently considering using semaphores: the user module will call my driver's function, which will initiate the transfers and wait on a semaphore; the IRQ handler of my driver will send requests to the MCU and read the answers, and, when done, post to the semaphore, thus waking up the calling module. But I'm not really familiar with kernel programming, and I'm baffled by the multitude of possible alternative implementations (tasklets? wait queues?).

调用模块必须等待操作的完成(前面提到的read_register()和其他)。我正在考虑使用信号量:用户模块将调用我的驱动程序的函数,它将启动传输并等待信号量;我的驱动程序的IRQ处理程序将向MCU发送请求并读取答案,并在完成后发布到信号量,从而唤醒调用模块。但我对内核编程并不熟悉,而且我对众多可能的替代实现(tasklets?等待队列?)感到困惑。

The question is: is my semaphore-based approach OK, or too naïve? What are the possible alternatives? Are there any pitfalls I may be missing?

问题是:我的基于信号量的方法是好还是太天真了?有哪些替代方案?我可能会遗失任何陷阱吗?

1 个解决方案

#1


5  

Traditionally IRQ handling in Linux is done in two parts:

传统上Linux中的IRQ处理分为两部分:

  1. So called "upper-half" is actual working in IRQ context (IRQ handler itself). This part must exit as fast as possible. So it basically checks interrupt source and then starts bottom-half.

    所谓的“上半部分”实际上在IRQ上下文中工作(IRQ处理程序本身)。这部分必须尽快退出。所以它基本上检查中断源,然后从下半部分开始。

  2. "Bottom-half". It may be implemented as work queue. It is where actual job is done. It runs in normal context, so it can use blocking functions, etc.

    “下半区”。它可以实现为工作队列。这是实际工作的地方。它在正常的上下文中运行,因此它可以使用阻塞函数等。

If you only want to wait for IRQ in your worker thread, better to use special object called completion. It is exactly created for this task.

如果您只想在工作线程中等待IRQ,最好使用称为完成的特殊对象。它完全是为此任务创建的。

#1


5  

Traditionally IRQ handling in Linux is done in two parts:

传统上Linux中的IRQ处理分为两部分:

  1. So called "upper-half" is actual working in IRQ context (IRQ handler itself). This part must exit as fast as possible. So it basically checks interrupt source and then starts bottom-half.

    所谓的“上半部分”实际上在IRQ上下文中工作(IRQ处理程序本身)。这部分必须尽快退出。所以它基本上检查中断源,然后从下半部分开始。

  2. "Bottom-half". It may be implemented as work queue. It is where actual job is done. It runs in normal context, so it can use blocking functions, etc.

    “下半区”。它可以实现为工作队列。这是实际工作的地方。它在正常的上下文中运行,因此它可以使用阻塞函数等。

If you only want to wait for IRQ in your worker thread, better to use special object called completion. It is exactly created for this task.

如果您只想在工作线程中等待IRQ,最好使用称为完成的特殊对象。它完全是为此任务创建的。