Skip to content

Day15 - User-space Event Loop and Poll

🎯 Goal

Understand how to properly consume events from a driver using:

  • blocking I/O
  • non-blocking I/O
  • poll / select / epoll
  • event loop design

1. Blocking vs Non-blocking

Blocking I/O

read(fd, buf, size);
  • If no data is available β†’ process sleeps
  • CPU usage is low
  • Simple but not scalable

Non-blocking I/O

fd = open("/dev/mygpio", O_RDONLY | O_NONBLOCK);
read(fd, buf, size);
  • If no data β†’ returns -EAGAIN
  • Requires polling or retry logic

2. Why poll is needed

Problem:

while (1) {
read(fd, buf, size);   // busy loop ❌
}

β†’ wastes CPU


Solution:

poll() β†’ wait for event β†’ read()

3. poll concept

poll checks whether a file descriptor is ready.

poll(fds, nfds, timeout);

Workflow

poll() blocks
↓
driver wakes wait queue
↓
poll returns
↓
read() consumes data

4. Relationship with driver

Driver implements:

.poll = my_poll

Inside:

poll_wait(file, &wait_queue, wait);

Key idea

  • poll does NOT read data
  • poll only checks readiness

5. Event-driven model

Typical pattern:

while (1) {
poll(...)
read(...)
handle_event(...)
}

6. Level-trigger behavior

poll is level-triggered:

  • If data exists β†’ poll keeps returning ready
  • Must consume data (read)

7. Common mistakes

❌ Busy loop

while (1) read(fd, ...);

❌ Forget to read after poll

β†’ poll will keep waking


❌ Mixing blocking read + poll incorrectly


8. poll vs select vs epoll

API νŠΉμ§•
select old, fd limit
poll simple
epoll scalable

9. System view

Linux is fundamentally:

event-driven system

Examples:

  • GPIO IRQ
  • socket
  • timer
  • input device

All can be handled via poll/epoll


πŸ“Œ Summary

  • driver provides readiness
  • poll waits for readiness
  • read consumes data
  • event loop connects everything