4/32 · 5 min
How a program asks for something it cannot do
A program cannot touch a disk, open a socket or create a process. Those are privileged, and a program runs unprivileged. The system call is the one door between the two.
What happens on a call
ssize_t n = read(fd, buffer, 1024);- 1The library puts the call number and arguments in registers
- 2A special instruction switches the processor into kernel mode
- 3The kernel checks the arguments, including that the buffer is really yours
- 4It does the work, possibly blocking the process while the disk responds
- 5It switches back to user mode with a return value
Step 3 is the reason the boundary exists. Every argument crossing it is untrusted, and a kernel that skipped validation would let any program read any memory.
It is not a function call
| Function call | System call | |
|---|---|---|
| Cost | a few nanoseconds | hundreds of nanoseconds to microseconds |
| Changes privilege | no | yes |
| Can block | rarely | routinely |
That cost difference is why buffering exists. Writing a million lines one call at a time is a million transitions; buffering into 4KB chunks is a few thousand. Same output, dramatically different time.
$ strace -c ls
% time seconds usecs/call calls syscall
24.15 0.000112 7 15 mmap
14.22 0.000066 8 8 openat
10.99 0.000051 6 8 readstrace shows every call a program makes, and it is the fastest way to find out what a misbehaving program is actually doing.
The families
| Kind | Examples |
|---|---|
| Process | fork, execve, exit, wait |
| File | open, read, write, close, lseek |
| Device | ioctl, read, write |
| Information | getpid, time, uname |
| Communication | pipe, socket, send, recv |
| Protection | chmod, chown, umask |
The library in between
You rarely make one directly. printf formats the text and eventually calls write. fopen calls open and adds buffering. The standard library is a convenience layer, which is why the same C program compiles on Linux and Windows despite entirely different kernels underneath.