Skip to content

fasync_helper() and kill_fasync()

Purpose

The fasync API allows a character driver to support asynchronous event notification through SIGIO.

Applications enable asynchronous notification by configuring the file with F_SETOWN and O_ASYNC. The VFS then invokes the driver's .fasync() callback, which registers or unregisters the file from the driver's asynchronous notification list.

Registration Flow

Application
fcntl(F_SETOWN)
fcntl(F_SETFL | O_ASYNC)
VFS
driver .fasync()
fasync_helper()
Driver async queue

Driver Callback

static int mydev_fasync(int fd, struct file *file, int on)
{
    struct mydev_data *dev = file->private_data;

    return fasync_helper(fd, file, on, &dev->async_queue);
}

fasync_helper() maintains the driver's asynchronous listener list. When on is non-zero, the file is registered. Otherwise, it is removed from the list.

Event Notification

When the driver detects a device event, it notifies all registered listeners:

kill_fasync(&dev->async_queue, SIGIO, POLL_IN);

kill_fasync() delivers SIGIO to every registered asynchronous listener.

User-space Setup

User space typically performs the following steps:

  1. Set the process owner with F_SETOWN
  2. Enable asynchronous notification with O_ASYNC
  3. Install a SIGIO signal handler

Relationship with poll()

poll() and epoll() determine readiness by calling the driver's .poll() callback.

SIGIO uses a different notification path:

  • .poll() reports the current readiness state.
  • .fasync() manages asynchronous listeners.
  • kill_fasync() actively delivers SIGIO when an event occurs.

Drivers commonly implement both .poll() and .fasync() so that applications can choose the most suitable I/O model.

Common Pitfalls

Warning

Signals are notifications rather than an event queue. Signal handlers should perform minimal work and return quickly.

Warning

Drivers should update their internal state before calling kill_fasync() so that subsequent poll() or read() operations observe the correct device state.