Skip to content

Day52 - fasync, SIGIO, and eventfd Integration

Goal

Learn how to:

  • implement .fasync in a char driver
  • send SIGIO from kernel driver
  • receive asynchronous notification in userspace
  • bridge SIGIO into epoll using eventfd
  • build a unified event-driven userspace loop

1. Driver-Side fasync Support

Device Context

Add async queue:

struct fasync_struct *async_queue;

File Operations

Add:

.fasync = mypoll_fasync,

fasync Handler

static int mypoll_fasync(int fd,
                         struct file *file,
                         int on)
{
    struct mypoll_dev *mydev;

    mydev = file->private_data;

    if (!mydev)
        return -ENODEV;

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

Release Cleanup

mypoll_fasync(-1, file, 0);

2. Send SIGIO from Driver

Inside event generation path:

wake_up_interruptible(&mydev->read_queue);

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

3. Minimal SIGIO Userspace Test

Userspace Flow

open("/dev/mypoll")
install SIGIO handler
F_SETOWN
O_ASYNC
pause()

SIGIO Handler

static void sigio_handler(int signo)
{
    sigio_received = 1;
}

4. Nonblocking Event Read

Userspace enables:

O_NONBLOCK

and drains events until:

EAGAIN

5. eventfd Integration

Create eventfd

eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)

Signal Handler

Signal handler only performs:

write(eventfd)

Example:

static void sigio_handler(int signo)
{
    uint64_t value = 1;

    (void)signo;

    write(g_event_fd, &value, sizeof(value));
}

6. epoll + eventfd

epoll monitors eventfd:

epoll_wait()
read(eventfd)
drain /dev/mypoll

7. Final Architecture

kernel event
mypoll_generate_event()
queue push
wake_up_interruptible()
kill_fasync()
SIGIO
signal handler
write(eventfd)
epoll_wait()
read(eventfd)
read(/dev/mypoll)

8. Build

gcc -Wall -Wextra -o sigio_eventfd_epoll sigio_eventfd_epoll.c

9. Validation Checklist

  • SIGIO received successfully
  • eventfd wakeup works
  • epoll_wait wakes correctly
  • userspace drains driver queue
  • timer events received
  • manual trigger events received
  • no blocking inside signal handler

10. Files

Suggested files:

sigio_test.c
sigio_eventfd_epoll.c