networking · intermediate · ~15 min

Filter the fds reported as readable by epoll_wait

The dispatch-loop pattern; mask matching for the 'readable' flags.

Challenge

Walk a table of epoll-style ready events and pull out the fds you need to read from — the heart of an epoll dispatch loop.

Task

The harness defines epoll-like flags and an event struct:

#define EPOLLIN  0x001
#define EPOLLOUT 0x004
#define EPOLLERR 0x008
#define EPOLLHUP 0x010
typedef struct { int events; int fd; } evt_t;

Implement int filter_readable(const evt_t *in, int n, int *out_fds, int max). Copy into out_fds[], in order, the fd of every entry whose events has EPOLLIN, EPOLLHUP, or EPOLLERR set (the three flags that mean "you should read this fd").

Input

  • in: array of n event entries {events, fd}.
  • n: number of entries in in.
  • out_fds: output array.
  • max: capacity of out_fds.

Output

Return the number of fds copied. Never copy more than max; stop once out_fds is full.

Example

in = {{IN,3},{OUT,4},{IN|OUT,5},{HUP,6},{ERR,7},{0,8}}, max=16
  -> returns 4, out_fds = {3, 5, 6, 7}   (4 and 8 are not "readable")
in = {{OUT,1},{OUT,2}}, max=16  ->  0
in = {{IN,10}}, max=0           ->  0
in = {{IN,10}}, max=1           ->  1, out_fds = {10}

Edge cases

  • Empty input, all-readable, none-readable.
  • max smaller than the number of matches: copy only max, return max.

Rules

  • Single pass; treat EPOLLIN, EPOLLHUP, and EPOLLERR all as "readable".

Why this matters

When epoll_wait fills your events[] buffer, you walk it once and dispatch each fd. Getting the dispatch loop right — including masks for HUP/ERR — is the difference between a working server and a stuck one.

Input format

in, an array of n {events, fd} entries; out_fds, an output array of capacity max.

Output format

The number of fds copied into out_fds (never more than max).

Constraints

Single pass; readable means EPOLLIN | EPOLLHUP | EPOLLERR; respect max.

Starter code

#define EPOLLIN  0x001
#define EPOLLOUT 0x004
#define EPOLLERR 0x008
#define EPOLLHUP 0x010
typedef struct { int events; int fd; } evt_t;
int filter_readable(const evt_t *in, int n, int *out_fds, int max) { /* TODO */ return 0; }

Common mistakes

Treating only EPOLLIN as 'readable' — HUP and ERR also need attention.

Edge cases to handle

Empty input, all-set, none-set, max smaller than matches.

Complexity

O(n).

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.