Arc I · Linux Driver Lab
Chapter 02

Non-Blocking + Poll Driver

Blocking reads aren't always the right answer. Time to let userspace choose.

O_NONBLOCK poll/select wait queue EAGAIN

Why this driver?

The first driver blocks. But real applications — especially ones monitoring multiple file descriptors — can't afford to block on one. They use poll() or select() to watch many fds at once and act when any of them becomes readable.

This driver adds that capability to the message queue without breaking the blocking API.

Non-blocking read

while (kernel_logger.count == 0) {
    mutex_unlock(&kernel_logger.etx_mutex);
    if (filp->f_flags & O_NONBLOCK)
        return -EAGAIN;   /* tell the caller: try again later */
    if (wait_event_interruptible_exclusive(etx_wait_queue,
                                           kernel_logger.count > 0))
        return -ERESTARTSYS;
    mutex_lock(&kernel_logger.etx_mutex);
}

One flag check, one early return. The POSIX contract for non-blocking I/O: don't sleep, return EAGAIN if nothing is ready.

Poll implementation

static __poll_t etx_poll(struct file *filp, poll_table *wait)
{
    poll_wait(filp, &etx_wait_queue, wait);
    if (kernel_logger.count > 0)
        return POLLIN | POLLRDNORM;
    return 0;
}
poll_wait() does not sleep. It registers the wait queue with the kernel's poll infrastructure so the kernel knows which fd to wake when data arrives. The actual sleeping is in the kernel's poll loop, not here.

Per-open private state

Two flags per open file descriptor — read_done and write_done — let each session track its own completion independently.

typedef struct etx_priv {
    int read_done;
    int write_done;
} etx_priv_t;