Free — no signup required

Generation 1: Select and Poll

2 min read

The "Are We There Yet?" Era

select() and poll() were the first tools for monitoring multiple file descriptors simultaneously. The programming model is straightforward:

// Simplified select() usage
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd1, &readfds);
FD_SET(fd2, &readfds);

// Block until one of the fds is ready
select(max_fd + 1, &readfds, NULL, NULL, &timeout);

// Now iterate through ALL fds to find which ones are ready
for (int i = 0; i <= max_fd; i++) {
    if (FD_ISSET(i, &readfds)) {
        // This fd has data — handle it
    }
}

The critical problem is visible in the loop: you must check every file descriptor every time, even if only one of 10,000 connections has data. The kernel also copies the entire fd_set between user space and kernel space on every call.

Complexity: O(N) per call, where N is the number of monitored file descriptors.

select limitations:
- Maximum of 1,024 file descriptors (hardcoded FD_SETSIZE limit).
- The fd_set is destroyed after each call — you must rebuild it.

poll improvements:
- No 1,024 fd limit (uses a dynamic array).
- The pollfd array is not destroyed after each call.
- Still O(N) — still iterates through every fd.

Neither select nor poll scales beyond a few thousand connections. This was the "C10K problem" — how do you handle 10,000 concurrent connections on a single server?

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free