FirstHack Learn
Log in Sign up free
Lessons in this course 0/6 All courses Operating Systems

CSE

Progress0 / 6 lessons
  1. 1. What an OS actually does, and what a system call is
  2. 2. Processes vs threads, with a fork() example
  3. 3. CPU scheduling with worked FCFS, SJF and Round Robin numbers
  4. 4. Deadlock: the four conditions and how to break them
  5. 5. Memory: paging, virtual memory and page faults
  6. 6. File systems and how a file is really stored

Courses › Operating Systems

What an OS actually does, and what a system call is

The OS as a resource manager and a protection boundary, and the exact moment your program crosses it.

10 min read · Lesson 1 of 6 · Free

The OS has two jobs

Textbooks list ten functions of an operating system. There are really two, and every listed function is one of them wearing a hat.

Job one: share the hardware. You have one CPU, or maybe eight cores, and forty running programs. You have 8 GB of RAM and every program thinks it owns memory starting at address zero. You have one disk and one network card. The OS decides who gets what and when.

Job two: stop programs hurting each other. Your browser must not be able to read your bank app's memory. A crashing program must not take the machine down. A buggy loop must not freeze everything else.

Both jobs need the same thing: the OS must be more powerful than your program. That is where the CPU's two modes come in.

User mode and kernel mode

Modern CPUs run in one of two modes.

In user mode, some instructions are simply forbidden. You cannot talk to the disk controller. You cannot change the page tables that define which memory you can see. You cannot disable interrupts. If you try, the CPU faults and the OS kills your process.

In kernel mode, everything is allowed. Only OS code runs here.

So your program cannot open a file. It genuinely lacks the power. It must ask the kernel to do it.

A system call is that ask

A system call is a controlled doorway from user mode into kernel mode. Your program puts a number in a register saying which service it wants, puts the arguments in other registers, and executes a special instruction (syscall on x86-64). The CPU switches to kernel mode and jumps to one fixed address the kernel chose in advance.

That last part is the security. You do not get to say where in the kernel to jump. You get a numbered menu.

Linux has roughly 350 system calls. You use maybe twenty regularly: read, write, open, close, fork, execve, exit, mmap, brk, wait4, socket, connect.

Here is a program with no standard library output at all — it makes the system call directly.

C
#include <unistd.h>
#include <string.h>

int main(void) {
    const char *msg = "this text came from a write() system call\n";
    write(1, msg, strlen(msg));
    return 0;
}

File descriptor 1 is standard output. write is a thin wrapper that sets up the registers and executes the trap instruction. There is nothing between you and the kernel here.

So what is printf doing?

C
#include <stdio.h>

int main(void) {
    printf("hello\n");
    return 0;
}

printf is a library function, not a system call. It formats your string into a buffer in your own memory, and only calls write when the buffer fills up, or when it sees a newline on a terminal, or when the program exits.

That buffering explains a bug you have probably hit:

C
#include <stdio.h>

int main(void) {
    printf("about to crash");
    int *p = NULL;
    *p = 42;          /* segmentation fault */
    return 0;
}

Run it and "about to crash" often does not appear. The text is sitting in the C library's buffer, in your process's memory, and the process dies before anything flushes it. The kernel never saw those bytes.

⚠️

Do not debug by adding printf and trusting what you see. If your program crashes, the last few printf lines may be lost. Either add \n at the end of every debug line, call fflush(stdout) right after, or use fprintf(stderr, ...) — stderr is unbuffered by default and always appears.

Why system calls are expensive

A normal function call is a few nanoseconds. A system call is a few hundred nanoseconds to a couple of microseconds — roughly a hundred times more. The CPU switches mode, saves registers, jumps into the kernel, validates your arguments (the kernel must assume you are lying about that pointer), does the work, and switches back.

That cost is why buffering exists everywhere. Writing a 1 MB file one byte at a time with write costs a million system calls. Writing it in 4 KB chunks costs 256. Same bytes, hundreds of times faster.

💡

On any Linux machine, run strace ./a.out on your compiled program. Every line of output is one system call your program made. Run it on the printf version and the write version and compare. Nothing explains this lesson faster than seeing the actual list.

What the OS gives you, summarised

You never touch a disk sector. You get files. You never touch physical RAM addresses. You get a private address space. You never schedule the CPU. You just run, and the OS interrupts you every few milliseconds to let someone else run.

Every one of those is an abstraction — a simpler, safer imaginary machine built on top of the messy real one. The rest of this course is about how each abstraction is built.