Blocking reads aren't always the right answer. Time to let userspace choose.
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.
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.
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;
}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;