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() delivers SIGIO to every registered asynchronous listener.
User-space Setup¶
User space typically performs the following steps:
- Set the process owner with
F_SETOWN - Enable asynchronous notification with
O_ASYNC - Install a
SIGIOsignal 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 deliversSIGIOwhen 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.