# Syscall (Systems Call)
A **syscall** is the mechanism a program uses to request a service from the operating system's kernel--things a normal program isn't allowed to do directly, like reading a file, sending network data, allocating memory, or creating a new process
Modern operating systems separate memory and privilege levels into two modes:
- **User mode** — where your application code runs, with restricted access to hardware and system resources
- **Kernel mode** — where the OS core runs, with full access to hardware, memory management, and other processes
## How it Works, Roughly
1. Your program calls a function like `read()`, `write()`, `open()`, or `fork()`
2. That function triggers a special CPU instruction (like `syscall` on x86-64 or `svc` on ARM) that switches the processor from **user mode** to **kernel mode**
3. The kernel looks up which syscall was requested (usually via a syscall number) and executes the corresponding code
4. Control returns to your program in **user mode** with a result
## Classic Example in C on Linux
```c
#include <unistd.h>
write(1, "Hello\n", 6); // write() is a thin wrapped around the write syscall
```
The `write()` isn't doing the actual I/O itself, it's asking the kernel to do it, because only the kernel has permission to talk to the file descriptor/hardware directly
## Some Common Linux Syscalls
| Syscall | Purpose |
| --------------------------- | ---------------------------------------- |
| `read`/`write` | Read/write data to a file descriptor |
| `open`/`close` | Open/close a file |
| `fork`/`execve` | Create a new process/run a program |
| `mmap` | Map memory (e.g. for dynamic allocation) |
| `socket`, `connect`, `send` | Networking |
| `exit` | Terminate a process |
## A Subtlety
You rarely call syscalls directly in high-level code. Instead, you call a library function (like `fopen()` in C, or `open()` in Python), and that library wraps the actual syscall along with extra bookkeeping (buffering, error handling, etc.). The syscall itself is the raw, minimal request to the kernel.
## Why This Matters for Perfomance
Syscalls aren't free - switching between user and kernel mode has real overhead (context switching, CPU pipeline flushes). This is why things like buffered I/O exist: batching many small writes into fewer syscalls is much faster than making a syscall per byte. It's also why techniques like `io_uring` (Linux) exist - to reduce syscall overhead for high-throughput I/O.
- `io_uring` is a Linux kernel interface for doing I/O asynchronously and efficiently, designed to fix the performance problems of older async I/O mechanisms - mainly by drastically cutting downon syscall overhead
- The core idea is **shared ring buffers between user space and kernel space**, so both sides can communicate without a syscall for every operation. Both sides are memory-mapped via `mmap` so user and kernel space see the same memory.
### CPU Pipeline Flush Explained
A **CPU pipeline flush** is what happens when a modern processor has to throw away work it already started, because it turns out that work was based on a wrong assumption about what instruction should run next
A CPU doesn't execute one instruction completely before starting the next. It breaks execution into stages - roughly: fetch -> decode -> execute -> memory access -> write-back - then overlaps them, so while one instruction is being decoded, the next is already being fetched, and the one before is executing. This is a **pipeline**, and it's one of the main reasons CPUs are as fast as they are: multiple instructions are "in flight" at once, like an assembly line
**Pipleline**:
```markdown
Cycle: 1 2 3 4 5
Instr A: Fetch Decode Exec Mem Write
Instr B: Fetch Decode Exec Mem
Instr C: Fetch Decode Exec
```
#### The Problem: Branches
Pipe-lining works great for straight-line code. But programs are full of branches - `if` statements, loops, function calls - where the CPI doesn't actually know which instruction comes next until it finishes evaluating a condition. If it just stalled and waiting every time, it would lose most of pipelining benefit.
Instead, CPU's use **branch prediction**: they guess which way a branch will go (based on past behavior, heuristics, etc.) and speculatively start fetching and executing instructions down that predicted path - before the branch condition is actually resolved.
#### The Flush
If the guess was right, great - the CPU saved time. But if the guess was *wrong*, all those speculatively-executed instructions in the pipeline are invalid. The CPU has to:
1. Discard (flush) all the in-flight instructions from the wrong path
2. Reset to pipeline state
3. Start over fetching from the *correct* instruction address
*This* is a **pipeline flush** (also called a *pipeline stall* or a *branch misprediction penalty*).
## Connecting Back to Syscalls
A syscall forces a *mode switch* (user -> kernel -> user), which involves:
- Saving/restoring registers and CPU state
- Often invalidating cached predictions because you're jumping into completely different code (kernel code) that the CPU's predictions have no relevant history for
- Sometimes flushing TLB (translation lookaside buffer) entires too, depending on the OS/CPU
So the "overhead" of a syscall isn't just the kernel work itself - it's also this disruption to CPU's pipelining and prediction machinery, which is part of why batching operations (fewer, larger syscalls instead of many small ones) is faster.
## A Quick Analogy
>Think of the pipeline like a factory assembly line that's building product designs A, B, C in parallel stages, betting that a decision earlier in the line ("customer wants blue") will hold. If that guess turns out wrong ("actually, customer wants red"), every half-built blue unit already on the line has to be scrapped, and the line has to restart with the red spec. That scrapped work is the flush.