Skip to content

Day85 - poll() Internals

Objective

Understand how Linux poll() integrates with wait queues to implement event-driven I/O.

This lab builds a simplified poll subsystem step by step and demonstrates how a userspace poll() operation interacts with a driver's poll callback.


Learning Objectives

After completing this lab, you should understand:

  • The purpose of poll()
  • How poll_wait() works
  • The role of poll_table
  • Driver poll callback flow
  • Event masks (POLLIN)
  • Relationship between poll and wait queues
  • Blocking event-driven I/O

Lab1 - Poll Table Registration

Objective

Build a simplified poll_table.

Implement:

  • poll_table
  • poll_table_entry
  • poll_wait()

Verify that a poll operation records all monitored wait queues.

Expected Flow

poll_wait()
poll_table
poll_table_entry
wait_queue_head

Expected Result

  • Three wait queues are registered.
  • Dump shows every registered wait queue.
  • Destroy correctly releases all entries.

Lab2 - Driver poll Callback

Objective

Implement a simplified driver poll callback.

Driver Flow

driver_poll()
poll_wait()
Check device state
Return event mask

Validation

Case 1

data_ready = false


mask = 0

Case 2

data_ready = true


mask = POLLIN

Lab3 - Userspace poll()

Objective

Simulate a simplified userspace poll().

Flow

user_poll()


poll_table_init()


driver_poll()


poll_table_destroy()


return mask

Validation

When no data is available:

mask = 0

When data is available:

mask = POLLIN

Lab4 - Blocking poll

Objective

Combine poll(), wait queues and wakeup.

Poll Thread

user_poll()


driver_poll()


poll_wait()


wait_event()


driver_poll()


return POLLIN


read()

Producer Thread

sleep()


data_ready = true


wake_up()

Expected Output

[POLL] user poll start
[POLL] no event, sleep
[DRV] data ready
mask=0x00000001
[DRV] read data

Summary

This lab demonstrates the complete event-driven I/O flow:

Userspace poll()


Driver poll()


poll_wait()


wait queue


sleep


wake_up()


Driver poll()


POLLIN


read()

The most important takeaway is that:

  • poll_wait() only registers a wait queue.
  • It never blocks.
  • The driver determines readiness by returning an event mask.
  • read() consumes the data after poll() reports that data is available.