← Back to CS Fundamentals

File Descriptor

CS FundamentalsEntry

The Question

What is a file descriptor?

What a Strong Answer Covers

  • integer handle
  • "stdin=0
  • stdout=1
  • stderr=2
  • "per-process

Senior-Level Answer

A file descriptor (FD) is a small non-negative integer that the operating system kernel uses to represent an open I/O resource within a process. When a process opens a file, creates a socket, or establishes a pipe, the kernel returns an FD — typically the smallest available integer starting from 0. The process then uses this integer in subsequent system calls (`read`, `write`, `close`, `select`, `epoll_ctl`) to refer to that resource without needing to know its underlying type.

Every process starts with three FDs open by convention: 0 (stdin), 1 (stdout), and 2 (stderr). These are just entries in the process's file descriptor table like any other.

Under the hood, the kernel maintains a per-process **file descriptor table** — an array where each index (the FD) points to an entry in a system-wide **open file table**. The open file table entry stores the file offset (current read/write position), access mode (read/write/append), and a pointer to the underlying **vnode** (inode reference). Multiple FDs, potentially from different processes, can point to the same open file table entry — this happens after `fork()`, where parent and child share file offsets.

The UNIX design philosophy of "everything is a file" means FDs abstract over: regular files, directories, character and block devices, named and anonymous pipes (FIFOs), sockets (TCP, UDP, Unix domain), terminal devices (TTYs), and special files like `/dev/null` and `/dev/random`. Calling `read()` on a socket, a pipe, or a file uses the same syscall — the kernel dispatches to the correct implementation via the vnode's operation table.

FDs are process-local. The same integer in two different processes refers to different resources. FDs are inherited across `fork()` (unless marked `O_CLOEXEC`) and can be passed between processes via Unix domain sockets using `sendmsg` with `SCM_RIGHTS`.

Operating systems impose limits on open FDs: `ulimit -n` shows the per-process soft limit (often 1024 or 65536). Servers handling many concurrent connections must raise this limit. Leaking FDs — opening resources without closing them — exhausts the table and causes `EMFILE` errors, a common production bug.

What Separates a 2/3 from a 3/3

2/3 — Passing but Incomplete

Explains that an FD is an integer index into a per-process table, names stdin/stdout/stderr as 0/1/2, and gives two concrete examples of resource types (file, socket, pipe).

3/3 — Strong Answer

Describes the three-level kernel structure (FD table → open file table → vnode), explains FD sharing after fork(), mentions O_CLOEXEC, addresses ulimit and FD leak scenarios.

Common Mistakes

  • Saying FDs only refer to files — they abstract all I/O resources including sockets and pipes.
  • Not mentioning that FD integers are process-local — the same number in two processes means different things.
  • Ignoring the file offset sharing behavior after fork() — a classic source of bugs in multiprocess programs.
  • Forgetting ulimit and FD exhaustion as a real production concern.

Follow-Up Questions

  • What happens to file descriptors when you call fork()? — Child inherits copies of all open FDs; they share the same open file table entry (shared offset) unless the child closes or dups them.
  • What is O_CLOEXEC and when would you use it? — Marks an FD to be closed automatically on exec() — prevents unintended FD leakage into spawned child processes.
  • How does epoll use file descriptors? — epoll_create() returns an FD representing an interest list; epoll_ctl() registers other FDs to watch; epoll_wait() returns ready FDs — FDs all the way down.
  • How would you diagnose an EMFILE (too many open files) error in production? — lsof -p <pid> to count open FDs, compare to ulimit -n; look for FD leaks in connection-handling code paths.

Related Questions

  • Process vs Thread
  • Race Condition
  • Deadlock — 4 Conditions, Prevention
  • Thread Safety — Is dict Thread Safe?
  • HashMap Internals

Can You Explain This Cold?

Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.

Get Graded — Free Assessment
GrindQuestionsAITechnical interview assessment
TermsPrivacyAbout