System Calls & POSIX
System calls are the gateway between your program and the operating system kernel. Think of them as the reception desk at a secure government building: your program (a visitor) cannot walk into the vault and grab files directly. Instead, you fill out a request form (set up registers), ring a bell (execute thesyscall instruction), and a trusted employee (the kernel) fetches what you need and hands it back through the window.
Every printf, every file open, every network packet your C program sends eventually passes through this gateway. Understanding system calls is the difference between knowing C syntax and understanding how programs actually interact with hardware.
User Space vs Kernel Space
The Transition Steps
- User Mode (Ring 3): Your program runs with limited privileges. It cannot access hardware directly.
- Library Call: You call
printf(). The C library (libc) formats the string and callswrite(). - System Call: The
write()wrapper puts arguments in CPU registers (e.g.,rax=1 for write) and executes a special instruction (syscallon x86-64). - Mode Switch: The CPU switches to Kernel Mode (Ring 0) and jumps to a predefined kernel entry point.
- Kernel Execution: The kernel validates arguments, checks permissions, and performs the operation (e.g., writing to the terminal buffer).
- Return: The kernel executes
sysret, switching the CPU back to User Mode and returning the result (number of bytes written or error).
Making System Calls
Via libc Wrappers
In practice, you almost never call system calls directly. Instead, you call libc wrapper functions that set up the arguments, execute thesyscall instruction, check for errors, and set errno. This is like having an assistant who fills out the government forms for you.
Direct System Calls
Error Handling
File Descriptors
File descriptors are the kernel’s universal handle for “anything you can read from or write to.” Files, pipes, sockets, terminals, even special devices like/dev/null — they all look the same to your program: just an integer you pass to read() and write(). This uniform interface is one of Unix’s most powerful design decisions, and it is why shell pipes like cat file.txt | grep pattern | wc -l just work.
Process Information
Environment Variables
Time and Date
Resource Limits
POSIX Portability
Common System Call Reference
| Category | System Calls |
|---|---|
| File I/O | open, close, read, write, lseek, pread, pwrite |
| File Info | stat, fstat, lstat, access, chmod, chown |
| Directories | mkdir, rmdir, chdir, getcwd, opendir, readdir |
| Processes | fork, exec*, wait, waitpid, exit, _exit |
| Signals | kill, sigaction, sigprocmask, pause, sigsuspend |
| Memory | mmap, munmap, mprotect, brk, sbrk |
| IPC | pipe, socketpair, shmget, semget, msgget |
| Network | socket, bind, listen, accept, connect, send, recv |
| Time | time, gettimeofday, clock_gettime, nanosleep |
| Misc | ioctl, fcntl, dup, dup2, select, poll, epoll |
Exercises
System Info Tool
Build a tool that prints comprehensive system information (CPU, memory, disk, network).
Safe Wrapper Library
Create a library of safe wrappers for common system calls with proper error handling and EINTR retry.
Next Up
Concurrency
Process and thread programming