Implementing Poll in a Linux Kernel Module

Implementing poll in a Linux kernel module


Disclaimer

Well, this is a good architectural question and it implies some assumptions about your hardware and desired user-space interface. So let me jump into conclusions for a change and try to guess which solution would be best in your case.

Design

Taking into the account that you haven't mentioned write() operation, I will assume further that your hardware is producing new data all the time. If it's so, the design you mentioned can be exactly what is confusing you:

The read call is very simple. It starts a DMA write, and then waits on a wait queue.

This is exactly what prevents you from working with your driver in regular, commonly used (and probably desired for you) way. Let's think out of the box and come up with the desired user interface first (how you would want to use your driver from user-space). The next case is commonly used and sufficient here (from my point of view):

  1. poll() your device file to wait for new data to arrive
  2. read() your device file to obtain arrived data

Now you can see that data requesting (to DMA) should be started not by read() operation. The correct solution would be to read data continuously in the driver (without any triggering from user-space) and store it internally, and when user asks your driver for the data to consume (by read() operation) -- provide the user with data stored internally. If there is no data stored internally in driver -- user can wait for new data to arrive using poll() operation.

As you can see, this is well-known producer-consumer problem.You can use circular buffer to store data from your hardware in your driver (so you intentionally lost old data when buffer is full to prevent buffer overflow situation). So the producer (DMA) writes to the head of that RX ring buffer, and the consumer (user performing read() from user-space) reads from tail of that RX ring buffer.

Code references

This all situation reminds me of serial console [1, 2] drivers. So consider using Serial API in your driver implementation (if your device in fact is a serial console). For example see drivers/tty/serial/atmel_serial.c driver. I'm not really familiar with UART API, so I can't tell you precisely what's going on there, but it doesn't look too hard at the first glance, so probably you can figure out a thing or two from that code for your driver design.

If your driver shouldn't use Serial API, you can use next drivers for references:

  • drivers/char/virtio_console.c
  • drivers/char/xillybus/xillybus_core.c

Complementary

Answering your question in comment:

are you suggesting that read calls poll when there is no data available and read should block?

First of all, you want to decide, whether you want to provide:

  • blocking I/O
  • non-blocking I/O
  • or both of them

Let's assume (for the sake of argument) that you want to provide both options in your driver. In that case, you should check in open() call if flags parameter contains O_NONBLOCK flag. From man 2 open:

O_NONBLOCK or O_NDELAY

When possible, the file is opened in nonblocking mode. Neither the open() nor any subsequent operations on the file descriptor which is returned will cause the calling process to wait. For the handling of FIFOs (named pipes), see also fifo(7). For a discussion of the effect of O_NONBLOCK in conjunction with mandatory file locks and with file leases, see fcntl(2).

Now when you're aware of mode chosen by user, you can do next (in your driver):

  1. If flags in open() don't contain such flags, you can do blocking read() (i.e. if data is not available, wait for DMA transaction to finish and then return new data).
  2. But if there is O_NONBLOCK in open() flags and there is no data available in circular buffer -- you should return from read() call with EWOULDBLOCK error code.

From man 2 read:

EAGAIN or EWOULDBLOCK

The file descriptor fd refers to a socket and has been marked nonblocking (O_NONBLOCK), and the read would block. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.

You also may want to read next articles to get a better grasp on corresponding interfaces:

[1] Serial Programming Guide for POSIX Operating Systems

[2] Serial Programming HOWTO

Complementary 2

I need some sort of background task that is continuously reading from the device and populating the ring buffer. poll is now trivial - just check if there's anything in that buffer, but read is more difficult because it may need to wait for something to be posted to the ring buffer.

For example look at drivers/char/virtio_console.c driver implementation.

  1. In poll() function: do poll_wait() (to wait for new data to arrive)
  2. In receive data interrupt handler: do wake_up_interruptible() (to wake up poll and read operations)
  3. In read() function:

    • if port has no data:

      • if O_NONBLOCK flag was set (in open() operation): return -EAGAIN = -EWOULDBLOCK immediately
      • otherwise we have blocking read: do wait_event_freezable() to wait for new data to arrive
    • if port do have data: return data from buffer

See also related question: How to add poll function to the kernel module code?.

How to add poll function to the kernel module code?

You can find some good examples in kernel itself. Take a look at next files:

  • drivers/rtc/dev.c, drivers/rtc/interface.c
  • kernel/printk/printk.c
  • drivers/char/random.c

To add poll() function to your code follow next steps.

  1. Include needed headers:

     #include <linux/wait.h>
    #include <linux/poll.h>
  2. Declare waitqueue variable:

     static DECLARE_WAIT_QUEUE_HEAD(fortune_wait);
  3. Add fortune_poll() function and add it (as .poll callback) to your file operations structure:

     static unsigned int fortune_poll(struct file *file, poll_table *wait)
    {
    poll_wait(file, &fortune_wait, wait);
    if (new-data-is-ready)
    return POLLIN | POLLRDNORM;
    return 0;
    }

    static const struct file_operations proc_test_fops = {
    ....
    .poll = fortune_poll,
    };

    Note that you should return POLLIN | POLLRDNORM if you have some new data to read, and 0 in case there is no new data to read (poll() call timed-out). See man 2 poll for details.

  4. Notify your waitqueue once you have new data:

     wake_up_interruptible(&fortune_wait);

That's the basic stuff about implementing poll() operation. Depending on your task, you may be needed to use some waitqueue API in your .read function (like wait_event_interruptible()).


See also related question: Implementing poll in a Linux kernel module.

Emitting a poll/select event from a timer handler through a wait queue

Call wake_up_interruptible() on the polled queue just force the .poll method to be called again. User space process receive notification only when .poll method returns mask which have polled bits set.

Check that your .poll method actually returns non-zero mask.



Related Topics



Leave a reply



Submit