System calls
Programs cannot touch hardware directly. System calls are the controlled doorway through which every program asks the kernel to open files, create processes, and send data.
What a system call is
A system call is a request from a user-space program to the kernel. Because user code runs with restricted privileges, operations such as reading a disk, allocating memory, creating a process, or opening a network connection must go through the kernel. Linux on x86-64 has over 350 system calls, each identified by a number.
How a system call works
A program places the system call number and arguments in specific CPU registers and executes a special instruction, syscall on x86-64. The CPU switches to kernel mode, the kernel validates the arguments, performs the operation, and returns a result in a register, switching back to user mode. This boundary crossing protects the system but costs time, so efficient programs avoid unnecessary system calls.
The C library
Most programs do not issue system calls directly but call wrapper functions in the C library, glibc on most distributions or musl on Alpine. printf, for instance, formats text in a user-space buffer and eventually calls write(). The library also provides functions that are not system calls, such as strlen and qsort, entirely in user space.
Errors and errno
System calls typically return -1 on failure (the C wrappers do this) and set the global variable errno to a code explaining why: ENOENT (no such file), EACCES (permission denied), EINTR (interrupted by a signal), EAGAIN (try again), and many more. perror() and strerror() turn codes into readable messages. Robust programs check every call's return value.
Categories of system calls
Process control: fork, execve, exit, wait4, kill. File and I/O: open, read, write, close, lseek, stat. Memory: mmap, munmap, brk. Networking: socket, bind, listen, accept, connect, sendto, recvfrom. Information and time: getpid, uname, clock_gettime. Many others manage permissions, signals, devices, and namespaces.
Observing system calls
strace runs a program and prints each system call with arguments and results: strace -e trace=open,openat cat notes.txt shows which files cat opens, and strace -c summarises counts and time spent. ltrace traces library calls. These tools reveal configuration files a program reads, permission failures, and where it hangs.
vDSO and fast paths
Some frequently used calls, such as clock_gettime and gettimeofday, are accelerated with the vDSO (virtual dynamic shared object), a small piece of kernel-provided code mapped into every process so these calls can run in user space without a mode switch. Newer interfaces such as io_uring (2019) batch many I/O operations with few system calls for high performance.
Worked example
strace -e trace=openat,read,write,close cat hello.txt shows the program opening its shared libraries, then openat(AT_FDCWD, "hello.txt", O_RDONLY) = 3, read(3, "hi\n", 131072) = 3, write(1, "hi\n", 3) = 3, a final read returning 0 (end of file), and close(3). If the file did not exist, the trace would show openat(...) = -1 ENOENT (No such file or directory).
Key takeaways
System calls are requests from user space to the kernel for privileged operations; x86-64 Linux has over 350. A syscall instruction switches to kernel mode, the kernel validates and acts, then returns, at some cost. The C library (glibc or musl) wraps system calls and adds user-space functions. Failures return -1 and set errno, such as ENOENT or EACCES; always check results. Categories include process control, file I/O, memory, networking, and information. strace and ltrace reveal calls; the vDSO speeds time calls, and io_uring batches I/O.
Flashcard
Request from user space to the kernel
Check your understanding
A program prints 'Permission denied' when opening a file. What would strace most likely show?
