After this lesson, you will be able to: Understand the systems-programming foundations C exposes: system calls, file descriptors, processes (fork/exec/wait), and signals, the layer every server, shell, and OS is built on.
C is the language of systems programming because it talks almost directly to the operating system. This lesson covers the core OS concepts C gives you access to: what a system call actually is, why everything is a file descriptor, how processes are created with fork and exec, and how signals interrupt a running program. These are the foundations behind every web server, shell, and container you have used, and they come up directly in systems-engineering interviews.
Your program runs in user mode with limited privileges. Anything that touches hardware or shared resources, reading a file, opening a network socket, creating a process, must ask the operating system kernel to do it via a system call (syscall). Library functions like `printf` and `fopen` are convenient wrappers that ultimately make syscalls like `write` and `open`. The transition from user mode to kernel mode has a cost, which is why high-performance code tries to minimize syscalls (for example, buffering output instead of writing one byte at a time). On Linux the low-level syscall wrappers live in `unistd.h`.
Open files, sockets, and pipes are all file descriptors. The low-level I/O syscalls work on them directly.
#include <fcntl.h>#include <unistd.h>int main(void) {// open() returns a file descriptor: a small int the kernel uses to track the fileint fd = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0644);if (fd < 0) { perror("open"); return 1; }const char *msg = "hello syscalls\n";write(fd, msg, 15); // write() is the syscall under fputs/printfclose(fd); // always close; leaked fds eventually exhaust the limitreturn 0;}// fd 0 = stdin, 1 = stdout, 2 = stderr; they're just pre-opened file descriptors.// Sockets and pipes are also file descriptors, which is why the same read()/write()// calls work on files AND network connections. 'Everything is a file' in action.
This trio is how every shell launches programs and how servers spawn workers.
#include <unistd.h>#include <sys/wait.h>#include <stdio.h>int main(void) {pid_t pid = fork(); // duplicates the process; returns twiceif (pid == 0) {// child: replace this process image with a new programexeclp("ls", "ls", "-l", NULL);perror("exec"); // only reached if exec fails_exit(1);} else {// parent: wait for the child to finish and read its exit statusint status;waitpid(pid, &status, 0);printf("child exited with %d\n", WEXITSTATUS(status));}return 0;}// fork() = copy the current process; exec() = become a different program;// wait() = parent collects the child's result. Every shell command you run is fork+exec+wait.
A signal is an asynchronous notification the OS (or another process) sends to your program: `SIGINT` when you press Ctrl+C, `SIGTERM` when something asks you to shut down, `SIGSEGV` on an invalid memory access, `SIGKILL` to force-kill (which you cannot catch). You register a handler with `signal()` or, more robustly, `sigaction()`. The professional use is graceful shutdown: catch `SIGTERM`, finish in-flight work, close file descriptors, then exit, exactly what a container runtime sends when stopping your process. Signal handlers run in a constrained context, so they should do as little as possible (set a flag, then handle it in the main loop).
Leaking file descriptors by not calling `close()`, eventually hitting the per-process fd limit and failing to open anything. Ignoring the return value of syscalls like `read`/`write`, which can return fewer bytes than requested or fail; always check. Doing non-trivial work inside a signal handler; only async-signal-safe functions are allowed there. Set a flag and handle it in the main loop. Forgetting to `wait()` on children, creating zombie processes that linger in the process table. Assuming a single `write()` sends everything; for sockets especially, loop until all bytes are written.
Pick the correct sequence.
Sign in and purchase access to unlock this lesson.